Home | History | Annotate | Download | only in collect
      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. */
     53   AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
     54     setDelegates(forward, backward);
     55   }
     56 
     57   /** Private constructor for inverse bimap. */
     58   private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
     59     delegate = backward;
     60     inverse = forward;
     61   }
     62 
     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    */
     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 
     81   void setInverse(AbstractBiMap<V, K> inverse) {
     82     this.inverse = inverse;
     83   }
     84 
     85   // Query Operations (optimizations)
     86 
     87   @Override public boolean containsValue(Object value) {
     88     return inverse.containsKey(value);
     89   }
     90 
     91   // Modification Operations
     92 
     93   @Override public V put(K key, V value) {
     94     return putInBothMaps(key, value, false);
     95   }
     96 
     97   public V forcePut(K key, V value) {
     98     return putInBothMaps(key, value, true);
     99   }
    100 
    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 
    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 
    124   @Override public V remove(Object key) {
    125     return containsKey(key) ? removeFromBothMaps(key) : null;
    126   }
    127 
    128   private V removeFromBothMaps(Object key) {
    129     V oldValue = delegate.remove(key);
    130     removeFromInverseMap(oldValue);
    131     return oldValue;
    132   }
    133 
    134   private void removeFromInverseMap(V oldValue) {
    135     inverse.delegate.remove(oldValue);
    136   }
    137 
    138   // Bulk Operations
    139 
    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 
    146   @Override public void clear() {
    147     delegate.clear();
    148     inverse.delegate.clear();
    149   }
    150 
    151   // Views
    152 
    153   public BiMap<V, K> inverse() {
    154     return inverse;
    155   }
    156 
    157   private transient Set<K> keySet;
    158 
    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> {
    165     @Override protected Set<K> delegate() {
    166       return delegate.keySet();
    167     }
    168 
    169     @Override public void clear() {
    170       AbstractBiMap.this.clear();
    171     }
    172 
    173     @Override public boolean remove(Object key) {
    174       if (!contains(key)) {
    175         return false;
    176       }
    177       removeFromBothMaps(key);
    178       return true;
    179     }
    180 
    181     @Override public boolean removeAll(Collection<?> keysToRemove) {
    182       return Iterators.removeAll(iterator(), keysToRemove);
    183     }
    184 
    185     @Override public boolean retainAll(Collection<?> keysToRetain) {
    186       return Iterators.retainAll(iterator(), keysToRetain);
    187     }
    188 
    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 
    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 
    225     @Override protected Set<V> delegate() {
    226       return valuesDelegate;
    227     }
    228 
    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 
    249     @Override public Object[] toArray() {
    250       return ObjectArrays.toArrayImpl(this);
    251     }
    252 
    253     @Override public <T> T[] toArray(T[] array) {
    254       return ObjectArrays.toArrayImpl(this, array);
    255     }
    256 
    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