• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.base.Objects;
21 import static com.google.common.base.Preconditions.checkArgument;
22 import static com.google.common.base.Preconditions.checkState;
23 
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.io.Serializable;
28 import java.util.Collection;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.Set;
32 
33 import javax.annotation.Nullable;
34 
35 /**
36  * A general-purpose bimap implementation using any two backing {@code Map}
37  * instances.
38  *
39  * <p>Note that this class contains {@code equals()} calls that keep it from
40  * supporting {@code IdentityHashMap} backing maps.
41  *
42  * @author Kevin Bourrillion
43  * @author Mike Bostock
44  */
45 @GwtCompatible
46 abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
47     implements BiMap<K, V>, Serializable {
48 
49   private transient Map<K, V> delegate;
50   private transient AbstractBiMap<V, K> inverse;
51 
52   /** Package-private constructor for creating a map-backed bimap. */
AbstractBiMap(Map<K, V> forward, Map<V, K> backward)53   AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
54     setDelegates(forward, backward);
55   }
56 
57   /** Private constructor for inverse bimap. */
AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward)58   private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
59     delegate = backward;
60     inverse = forward;
61   }
62 
delegate()63   @Override protected Map<K, V> delegate() {
64     return delegate;
65   }
66 
67   /**
68    * Specifies the delegate maps going in each direction. Called by the
69    * constructor and by subclasses during deserialization.
70    */
setDelegates(Map<K, V> forward, Map<V, K> backward)71   void setDelegates(Map<K, V> forward, Map<V, K> backward) {
72     checkState(delegate == null);
73     checkState(inverse == null);
74     checkArgument(forward.isEmpty());
75     checkArgument(backward.isEmpty());
76     checkArgument(forward != backward);
77     delegate = forward;
78     inverse = new Inverse<V, K>(backward, this);
79   }
80 
setInverse(AbstractBiMap<V, K> inverse)81   void setInverse(AbstractBiMap<V, K> inverse) {
82     this.inverse = inverse;
83   }
84 
85   // Query Operations (optimizations)
86 
containsValue(Object value)87   @Override public boolean containsValue(Object value) {
88     return inverse.containsKey(value);
89   }
90 
91   // Modification Operations
92 
put(K key, V value)93   @Override public V put(K key, V value) {
94     return putInBothMaps(key, value, false);
95   }
96 
forcePut(K key, V value)97   public V forcePut(K key, V value) {
98     return putInBothMaps(key, value, true);
99   }
100 
putInBothMaps(@ullable K key, @Nullable V value, boolean force)101   private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
102     boolean containedKey = containsKey(key);
103     if (containedKey && Objects.equal(value, get(key))) {
104       return value;
105     }
106     if (force) {
107       inverse().remove(value);
108     } else {
109       checkArgument(!containsValue(value), "value already present: %s", value);
110     }
111     V oldValue = delegate.put(key, value);
112     updateInverseMap(key, containedKey, oldValue, value);
113     return oldValue;
114   }
115 
updateInverseMap( K key, boolean containedKey, V oldValue, V newValue)116   private void updateInverseMap(
117       K key, boolean containedKey, V oldValue, V newValue) {
118     if (containedKey) {
119       removeFromInverseMap(oldValue);
120     }
121     inverse.delegate.put(newValue, key);
122   }
123 
remove(Object key)124   @Override public V remove(Object key) {
125     return containsKey(key) ? removeFromBothMaps(key) : null;
126   }
127 
removeFromBothMaps(Object key)128   private V removeFromBothMaps(Object key) {
129     V oldValue = delegate.remove(key);
130     removeFromInverseMap(oldValue);
131     return oldValue;
132   }
133 
removeFromInverseMap(V oldValue)134   private void removeFromInverseMap(V oldValue) {
135     inverse.delegate.remove(oldValue);
136   }
137 
138   // Bulk Operations
139 
putAll(Map<? extends K, ? extends V> map)140   @Override public void putAll(Map<? extends K, ? extends V> map) {
141     for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
142       put(entry.getKey(), entry.getValue());
143     }
144   }
145 
clear()146   @Override public void clear() {
147     delegate.clear();
148     inverse.delegate.clear();
149   }
150 
151   // Views
152 
inverse()153   public BiMap<V, K> inverse() {
154     return inverse;
155   }
156 
157   private transient Set<K> keySet;
158 
keySet()159   @Override public Set<K> keySet() {
160     Set<K> result = keySet;
161     return (result == null) ? keySet = new KeySet() : result;
162   }
163 
164   private class KeySet extends ForwardingSet<K> {
delegate()165     @Override protected Set<K> delegate() {
166       return delegate.keySet();
167     }
168 
clear()169     @Override public void clear() {
170       AbstractBiMap.this.clear();
171     }
172 
remove(Object key)173     @Override public boolean remove(Object key) {
174       if (!contains(key)) {
175         return false;
176       }
177       removeFromBothMaps(key);
178       return true;
179     }
180 
removeAll(Collection<?> keysToRemove)181     @Override public boolean removeAll(Collection<?> keysToRemove) {
182       return Iterators.removeAll(iterator(), keysToRemove);
183     }
184 
retainAll(Collection<?> keysToRetain)185     @Override public boolean retainAll(Collection<?> keysToRetain) {
186       return Iterators.retainAll(iterator(), keysToRetain);
187     }
188 
iterator()189     @Override public Iterator<K> iterator() {
190       final Iterator<Entry<K, V>> iterator = delegate.entrySet().iterator();
191       return new Iterator<K>() {
192         Entry<K, V> entry;
193 
194         public boolean hasNext() {
195           return iterator.hasNext();
196         }
197         public K next() {
198           entry = iterator.next();
199           return entry.getKey();
200         }
201         public void remove() {
202           checkState(entry != null);
203           V value = entry.getValue();
204           iterator.remove();
205           removeFromInverseMap(value);
206         }
207       };
208     }
209   }
210 
211   private transient Set<V> valueSet;
212 
values()213   @Override public Set<V> values() {
214     /*
215      * We can almost reuse the inverse's keySet, except we have to fix the
216      * iteration order so that it is consistent with the forward map.
217      */
218     Set<V> result = valueSet;
219     return (result == null) ? valueSet = new ValueSet() : result;
220   }
221 
222   private class ValueSet extends ForwardingSet<V> {
223     final Set<V> valuesDelegate = inverse.keySet();
224 
delegate()225     @Override protected Set<V> delegate() {
226       return valuesDelegate;
227     }
228 
iterator()229     @Override public Iterator<V> iterator() {
230       final Iterator<V> iterator = delegate.values().iterator();
231       return new Iterator<V>() {
232         V valueToRemove;
233 
234         /*@Override*/ public boolean hasNext() {
235           return iterator.hasNext();
236         }
237 
238         /*@Override*/ public V next() {
239           return valueToRemove = iterator.next();
240         }
241 
242         /*@Override*/ public void remove() {
243           iterator.remove();
244           removeFromInverseMap(valueToRemove);
245         }
246       };
247     }
248 
toArray()249     @Override public Object[] toArray() {
250       return ObjectArrays.toArrayImpl(this);
251     }
252 
toArray(T[] array)253     @Override public <T> T[] toArray(T[] array) {
254       return ObjectArrays.toArrayImpl(this, array);
255     }
256 
toString()257     @Override public String toString() {
258       return Iterators.toString(iterator());
259     }
260   }
261 
262   private transient Set<Entry<K, V>> entrySet;
263 
264   @Override public Set<Entry<K, V>> entrySet() {
265     Set<Entry<K, V>> result = entrySet;
266     return (result == null) ? entrySet = new EntrySet() : result;
267   }
268 
269   private class EntrySet extends ForwardingSet<Entry<K, V>> {
270     final Set<Entry<K, V>> esDelegate = delegate.entrySet();
271 
272     @Override protected Set<Entry<K, V>> delegate() {
273       return esDelegate;
274     }
275 
276     @Override public void clear() {
277       AbstractBiMap.this.clear();
278     }
279 
280     @Override public boolean remove(Object object) {
281       if (!esDelegate.remove(object)) {
282         return false;
283       }
284       Entry<?, ?> entry = (Entry<?, ?>) object;
285       inverse.delegate.remove(entry.getValue());
286       return true;
287     }
288 
289     @Override public Iterator<Entry<K, V>> iterator() {
290       final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
291       return new Iterator<Entry<K, V>>() {
292         Entry<K, V> entry;
293 
294         /*@Override*/ public boolean hasNext() {
295           return iterator.hasNext();
296         }
297 
298         /*@Override*/ public Entry<K, V> next() {
299           entry = iterator.next();
300           final Entry<K, V> finalEntry = entry;
301 
302           return new ForwardingMapEntry<K, V>() {
303             @Override protected Entry<K, V> delegate() {
304               return finalEntry;
305             }
306 
307             @Override public V setValue(V value) {
308               // Preconditions keep the map and inverse consistent.
309               checkState(contains(this), "entry no longer in map");
310               // similar to putInBothMaps, but set via entry
311               if (Objects.equal(value, getValue())) {
312                 return value;
313               }
314               checkArgument(!containsValue(value),
315                   "value already present: %s", value);
316               V oldValue = finalEntry.setValue(value);
317               checkState(Objects.equal(value, get(getKey())),
318                   "entry no longer in map");
319               updateInverseMap(getKey(), true, oldValue, value);
320               return oldValue;
321             }
322           };
323         }
324 
325         /*@Override*/ public void remove() {
326           checkState(entry != null);
327           V value = entry.getValue();
328           iterator.remove();
329           removeFromInverseMap(value);
330         }
331       };
332     }
333 
334     // See java.util.Collections.CheckedEntrySet for details on attacks.
335 
336     @Override public Object[] toArray() {
337       return ObjectArrays.toArrayImpl(this);
338     }
339     @Override public <T> T[] toArray(T[] array) {
340       return ObjectArrays.toArrayImpl(this, array);
341     }
342     @Override public boolean contains(Object o) {
343       return Maps.containsEntryImpl(delegate(), o);
344     }
345     @Override public boolean containsAll(Collection<?> c) {
346       return Collections2.containsAll(this, c);
347     }
348     @Override public boolean removeAll(Collection<?> c) {
349       return Iterators.removeAll(iterator(), c);
350     }
351     @Override public boolean retainAll(Collection<?> c) {
352       return Iterators.retainAll(iterator(), c);
353     }
354   }
355 
356   /** The inverse of any other {@code AbstractBiMap} subclass. */
357   private static class Inverse<K, V> extends AbstractBiMap<K, V> {
358     private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
359       super(backward, forward);
360     }
361 
362     /*
363      * Serialization stores the forward bimap, the inverse of this inverse.
364      * Deserialization calls inverse() on the forward bimap and returns that
365      * inverse.
366      *
367      * If a bimap and its inverse are serialized together, the deserialized
368      * instances have inverse() methods that return the other.
369      */
370 
371     /**
372      * @serialData the forward bimap
373      */
374     private void writeObject(ObjectOutputStream stream) throws IOException {
375       stream.defaultWriteObject();
376       stream.writeObject(inverse());
377     }
378 
379     @SuppressWarnings("unchecked") // reading data stored by writeObject
380     private void readObject(ObjectInputStream stream)
381         throws IOException, ClassNotFoundException {
382       stream.defaultReadObject();
383       setInverse((AbstractBiMap<V, K>) stream.readObject());
384     }
385 
386     Object readResolve() {
387       return inverse().inverse();
388     }
389 
390     private static final long serialVersionUID = 0;
391   }
392 
393   private static final long serialVersionUID = 0;
394 }
395