001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 The ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.collections;
018
019import java.util.HashMap;
020import java.util.Map;
021import java.util.Map.Entry;
022
023import org.conqat.lib.commons.assertion.CCSMAssert;
024
025/**
026 * A collection which implements a bidirectional mapping.
027 */
028public class BidirectionalMap<S, T> {
029
030        /** Mapping from s to t. */
031        private final Map<S, T> stMap;
032
033        /** Mapping from t to s. */
034        private final Map<T, S> tsMap;
035
036        /** Creates new bidirectional map based on hash maps. */
037        public BidirectionalMap() {
038                stMap = new HashMap<S, T>();
039                tsMap = new HashMap<T, S>();
040        }
041
042        /** Creates new bidirectional map based given maps. */
043        @SuppressWarnings("null")
044        public BidirectionalMap(Map<S, T> stMap, Map<T, S> tsMap) {
045                CCSMAssert.isTrue(stMap != null && tsMap != null, "Maps may not be null!");
046                CCSMAssert.isTrue(stMap != tsMap, "Maps may not be equal!");
047                CCSMAssert.isTrue(stMap.isEmpty() && tsMap.isEmpty(), "Maps may not be used (filled)!");
048
049                this.stMap = stMap;
050                this.tsMap = tsMap;
051        }
052
053        /** Get first element. */
054        public S getFirst(T t) {
055                return tsMap.get(t);
056        }
057
058        /** Get second element. */
059        public T getSecond(S s) {
060                return stMap.get(s);
061        }
062
063        /** Returns whether this map is empty. */
064        public boolean isEmpty() {
065                return stMap.isEmpty();
066        }
067
068        /** Returns the size. */
069        public int size() {
070                return stMap.size();
071        }
072
073        /** Clears the map. */
074        public void clear() {
075                stMap.clear();
076                tsMap.clear();
077        }
078
079        /**
080         * Returns whether the given element is in the first set (the domain of the
081         * bijection).
082         */
083        public boolean containsFirst(S s) {
084                return stMap.containsKey(s);
085        }
086
087        /**
088         * Returns whether the given element is in the second set (the range of the
089         * bijection).
090         */
091        public boolean containsSecond(T t) {
092                return tsMap.containsKey(t);
093        }
094
095        /** Returns the first set (the domain). */
096        public UnmodifiableSet<S> getFirstSet() {
097                return CollectionUtils.asUnmodifiable(stMap.keySet());
098        }
099
100        /** Returns the second set (the range). */
101        public UnmodifiableSet<T> getSecondSet() {
102                return CollectionUtils.asUnmodifiable(tsMap.keySet());
103        }
104
105        /** Returns the entries. */
106        public UnmodifiableSet<Entry<S, T>> getEntrySet() {
107                return CollectionUtils.asUnmodifiable(stMap.entrySet());
108        }
109
110        /** Returns the inverted entries. */
111        public UnmodifiableSet<Entry<T, S>> getInvertedEntrySet() {
112                return CollectionUtils.asUnmodifiable(tsMap.entrySet());
113        }
114
115        /**
116         * Inserts the given pair into the bijection. Any mapping associated with
117         * those values is removed before. This map does not support null values.
118         */
119        public void put(S s, T t) {
120                CCSMAssert.isTrue(s != null && t != null, "null values not supported.");
121
122                removeFirst(s);
123                removeSecond(t);
124
125                stMap.put(s, t);
126                tsMap.put(t, s);
127        }
128
129        /** Removes the first object */
130        public void removeFirst(S s) {
131                T t = stMap.get(s);
132                if (t != null) {
133                        stMap.remove(s);
134                        tsMap.remove(t);
135                }
136        }
137
138        /** Removes the second object */
139        public void removeSecond(T t) {
140                S s = tsMap.get(t);
141                if (s != null) {
142                        stMap.remove(s);
143                        tsMap.remove(t);
144                }
145        }
146
147        /** {@inheritDoc} */
148        @Override
149        public String toString() {
150                return stMap.toString();
151        }
152
153}