001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.collect;
016
017import static com.google.common.base.Preconditions.checkArgument;
018import static com.google.common.collect.CollectPreconditions.checkNonnegative;
019import static com.google.common.collect.CollectPreconditions.checkRemove;
020import static com.google.common.collect.Hashing.smearedHash;
021
022import com.google.common.annotations.GwtCompatible;
023import com.google.common.annotations.GwtIncompatible;
024import com.google.common.base.Objects;
025import com.google.common.collect.Maps.IteratorBasedAbstractMap;
026import com.google.j2objc.annotations.WeakOuter;
027
028import java.io.IOException;
029import java.io.ObjectInputStream;
030import java.io.ObjectOutputStream;
031import java.io.Serializable;
032import java.util.AbstractMap;
033import java.util.Arrays;
034import java.util.ConcurrentModificationException;
035import java.util.Iterator;
036import java.util.Map;
037import java.util.NoSuchElementException;
038import java.util.Set;
039
040import javax.annotation.Nullable;
041
042/**
043 * A {@link BiMap} backed by two hash tables. This implementation allows null keys and values. A
044 * {@code HashBiMap} and its inverse are both serializable.
045 *
046 * <p>See the Guava User Guide article on <a href=
047 * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#bimap"> {@code BiMap}
048 * </a>.
049 *
050 * @author Louis Wasserman
051 * @author Mike Bostock
052 * @since 2.0
053 */
054@GwtCompatible(emulated = true)
055public final class HashBiMap<K, V> extends IteratorBasedAbstractMap<K, V>
056    implements BiMap<K, V>, Serializable {
057
058  /**
059   * Returns a new, empty {@code HashBiMap} with the default initial capacity (16).
060   */
061  public static <K, V> HashBiMap<K, V> create() {
062    return create(16);
063  }
064
065  /**
066   * Constructs a new, empty bimap with the specified expected size.
067   *
068   * @param expectedSize the expected number of entries
069   * @throws IllegalArgumentException if the specified expected size is negative
070   */
071  public static <K, V> HashBiMap<K, V> create(int expectedSize) {
072    return new HashBiMap<K, V>(expectedSize);
073  }
074
075  /**
076   * Constructs a new bimap containing initial values from {@code map}. The bimap is created with an
077   * initial capacity sufficient to hold the mappings in the specified map.
078   */
079  public static <K, V> HashBiMap<K, V> create(Map<? extends K, ? extends V> map) {
080    HashBiMap<K, V> bimap = create(map.size());
081    bimap.putAll(map);
082    return bimap;
083  }
084
085  private static final class BiEntry<K, V> extends ImmutableEntry<K, V> {
086    final int keyHash;
087    final int valueHash;
088
089    @Nullable
090    BiEntry<K, V> nextInKToVBucket;
091    @Nullable
092    BiEntry<K, V> nextInVToKBucket;
093    
094    @Nullable
095    BiEntry<K, V> nextInKeyInsertionOrder;
096    @Nullable
097    BiEntry<K, V> prevInKeyInsertionOrder;
098
099    BiEntry(K key, int keyHash, V value, int valueHash) {
100      super(key, value);
101      this.keyHash = keyHash;
102      this.valueHash = valueHash;
103    }
104  }
105
106  private static final double LOAD_FACTOR = 1.0;
107
108  private transient BiEntry<K, V>[] hashTableKToV;
109  private transient BiEntry<K, V>[] hashTableVToK;
110  private transient BiEntry<K, V> firstInKeyInsertionOrder;
111  private transient BiEntry<K, V> lastInKeyInsertionOrder;
112  private transient int size;
113  private transient int mask;
114  private transient int modCount;
115
116  private HashBiMap(int expectedSize) {
117    init(expectedSize);
118  }
119
120  private void init(int expectedSize) {
121    checkNonnegative(expectedSize, "expectedSize");
122    int tableSize = Hashing.closedTableSize(expectedSize, LOAD_FACTOR);
123    this.hashTableKToV = createTable(tableSize);
124    this.hashTableVToK = createTable(tableSize);
125    this.firstInKeyInsertionOrder = null;
126    this.lastInKeyInsertionOrder = null;
127    this.size = 0;
128    this.mask = tableSize - 1;
129    this.modCount = 0;
130  }
131
132  /**
133   * Finds and removes {@code entry} from the bucket linked lists in both the
134   * key-to-value direction and the value-to-key direction.
135   */
136  private void delete(BiEntry<K, V> entry) {
137    int keyBucket = entry.keyHash & mask;
138    BiEntry<K, V> prevBucketEntry = null;
139    for (BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket];
140        true;
141        bucketEntry = bucketEntry.nextInKToVBucket) {
142      if (bucketEntry == entry) {
143        if (prevBucketEntry == null) {
144          hashTableKToV[keyBucket] = entry.nextInKToVBucket;
145        } else {
146          prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket;
147        }
148        break;
149      }
150      prevBucketEntry = bucketEntry;
151    }
152
153    int valueBucket = entry.valueHash & mask;
154    prevBucketEntry = null;
155    for (BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];
156        true;
157        bucketEntry = bucketEntry.nextInVToKBucket) {
158      if (bucketEntry == entry) {
159        if (prevBucketEntry == null) {
160          hashTableVToK[valueBucket] = entry.nextInVToKBucket;
161        } else {
162          prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket;
163        }
164        break;
165      }
166      prevBucketEntry = bucketEntry;
167    }
168    
169    if (entry.prevInKeyInsertionOrder == null) {
170      firstInKeyInsertionOrder = entry.nextInKeyInsertionOrder;
171    } else {
172      entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry.nextInKeyInsertionOrder;
173    }
174    
175    if (entry.nextInKeyInsertionOrder == null) {
176      lastInKeyInsertionOrder = entry.prevInKeyInsertionOrder;
177    } else {
178      entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry.prevInKeyInsertionOrder;
179    }
180    
181    size--;
182    modCount++;
183  }
184
185  private void insert(BiEntry<K, V> entry, @Nullable BiEntry<K, V> oldEntryForKey) {
186    int keyBucket = entry.keyHash & mask;
187    entry.nextInKToVBucket = hashTableKToV[keyBucket];
188    hashTableKToV[keyBucket] = entry;
189
190    int valueBucket = entry.valueHash & mask;
191    entry.nextInVToKBucket = hashTableVToK[valueBucket];
192    hashTableVToK[valueBucket] = entry;
193
194    if (oldEntryForKey == null) {
195      entry.prevInKeyInsertionOrder = lastInKeyInsertionOrder;
196      entry.nextInKeyInsertionOrder = null;
197      if (lastInKeyInsertionOrder == null) {
198        firstInKeyInsertionOrder = entry;
199      } else {
200        lastInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
201      }
202      lastInKeyInsertionOrder = entry;
203    } else {
204      entry.prevInKeyInsertionOrder = oldEntryForKey.prevInKeyInsertionOrder;
205      if (entry.prevInKeyInsertionOrder == null) {
206        firstInKeyInsertionOrder = entry;
207      } else {
208        entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
209      }
210      entry.nextInKeyInsertionOrder = oldEntryForKey.nextInKeyInsertionOrder;
211      if (entry.nextInKeyInsertionOrder == null) {
212        lastInKeyInsertionOrder = entry;
213      } else {
214        entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry;
215      }
216    }
217
218    size++;
219    modCount++;
220  }
221
222  private BiEntry<K, V> seekByKey(@Nullable Object key, int keyHash) {
223    for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask];
224        entry != null;
225        entry = entry.nextInKToVBucket) {
226      if (keyHash == entry.keyHash && Objects.equal(key, entry.key)) {
227        return entry;
228      }
229    }
230    return null;
231  }
232
233  private BiEntry<K, V> seekByValue(@Nullable Object value, int valueHash) {
234    for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask];
235        entry != null;
236        entry = entry.nextInVToKBucket) {
237      if (valueHash == entry.valueHash && Objects.equal(value, entry.value)) {
238        return entry;
239      }
240    }
241    return null;
242  }
243
244  @Override
245  public boolean containsKey(@Nullable Object key) {
246    return seekByKey(key, smearedHash(key)) != null;
247  }
248
249  @Override
250  public boolean containsValue(@Nullable Object value) {
251    return seekByValue(value, smearedHash(value)) != null;
252  }
253
254  @Nullable
255  @Override
256  public V get(@Nullable Object key) {
257    return Maps.valueOrNull(seekByKey(key, smearedHash(key)));
258  }
259
260  @Override
261  public V put(@Nullable K key, @Nullable V value) {
262    return put(key, value, false);
263  }
264
265  @Override
266  public V forcePut(@Nullable K key, @Nullable V value) {
267    return put(key, value, true);
268  }
269
270  private V put(@Nullable K key, @Nullable V value, boolean force) {
271    int keyHash = smearedHash(key);
272    int valueHash = smearedHash(value);
273
274    BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
275    if (oldEntryForKey != null
276        && valueHash == oldEntryForKey.valueHash
277        && Objects.equal(value, oldEntryForKey.value)) {
278      return value;
279    }
280
281    BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
282    if (oldEntryForValue != null) {
283      if (force) {
284        delete(oldEntryForValue);
285      } else {
286        throw new IllegalArgumentException("value already present: " + value);
287      }
288    }
289
290    BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
291    if (oldEntryForKey != null) {
292      delete(oldEntryForKey);
293      insert(newEntry, oldEntryForKey);
294      oldEntryForKey.prevInKeyInsertionOrder = null;
295      oldEntryForKey.nextInKeyInsertionOrder = null;
296      rehashIfNecessary();
297      return oldEntryForKey.value;
298    } else {
299      insert(newEntry, null);
300      rehashIfNecessary();
301      return null;
302    }
303  }
304
305  @Nullable
306  private K putInverse(@Nullable V value, @Nullable K key, boolean force) {
307    int valueHash = smearedHash(value);
308    int keyHash = smearedHash(key);
309
310    BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
311    if (oldEntryForValue != null
312        && keyHash == oldEntryForValue.keyHash
313        && Objects.equal(key, oldEntryForValue.key)) {
314      return key;
315    }
316
317    BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
318    if (oldEntryForKey != null) {
319      if (force) {
320        delete(oldEntryForKey);
321      } else {
322        throw new IllegalArgumentException("value already present: " + key);
323      }
324    }
325
326    if (oldEntryForValue != null) {
327      delete(oldEntryForValue);
328    }
329    BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
330    insert(newEntry, oldEntryForKey);
331    if (oldEntryForKey != null) {
332      oldEntryForKey.prevInKeyInsertionOrder = null;
333      oldEntryForKey.nextInKeyInsertionOrder = null;
334    }
335    rehashIfNecessary();
336    return Maps.keyOrNull(oldEntryForValue);
337  }
338
339  private void rehashIfNecessary() {
340    BiEntry<K, V>[] oldKToV = hashTableKToV;
341    if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
342      int newTableSize = oldKToV.length * 2;
343
344      this.hashTableKToV = createTable(newTableSize);
345      this.hashTableVToK = createTable(newTableSize);
346      this.mask = newTableSize - 1;
347      this.size = 0;
348
349      for (BiEntry<K, V> entry = firstInKeyInsertionOrder; entry != null; 
350          entry = entry.nextInKeyInsertionOrder) {
351        insert(entry, entry);
352      }
353      this.modCount++;
354    }
355  }
356
357  @SuppressWarnings("unchecked")
358  private BiEntry<K, V>[] createTable(int length) {
359    return new BiEntry[length];
360  }
361
362  @Override
363  public V remove(@Nullable Object key) {
364    BiEntry<K, V> entry = seekByKey(key, smearedHash(key));
365    if (entry == null) {
366      return null;
367    } else {
368      delete(entry);
369      entry.prevInKeyInsertionOrder = null;
370      entry.nextInKeyInsertionOrder = null;
371      return entry.value;
372    }
373  }
374
375  @Override
376  public void clear() {
377    size = 0;
378    Arrays.fill(hashTableKToV, null);
379    Arrays.fill(hashTableVToK, null);
380    firstInKeyInsertionOrder = null;
381    lastInKeyInsertionOrder = null;
382    modCount++;
383  }
384
385  @Override
386  public int size() {
387    return size;
388  }
389
390  abstract class Itr<T> implements Iterator<T> {
391    BiEntry<K, V> next = firstInKeyInsertionOrder;
392    BiEntry<K, V> toRemove = null;
393    int expectedModCount = modCount;
394
395    @Override
396    public boolean hasNext() {
397      if (modCount != expectedModCount) {
398        throw new ConcurrentModificationException();
399      }
400      return next != null;
401    }
402
403    @Override
404    public T next() {
405      if (!hasNext()) {
406        throw new NoSuchElementException();
407      }
408
409      BiEntry<K, V> entry = next;
410      next = entry.nextInKeyInsertionOrder;
411      toRemove = entry;
412      return output(entry);
413    }
414
415    @Override
416    public void remove() {
417      if (modCount != expectedModCount) {
418        throw new ConcurrentModificationException();
419      }
420      checkRemove(toRemove != null);
421      delete(toRemove);
422      expectedModCount = modCount;
423      toRemove = null;
424    }
425
426    abstract T output(BiEntry<K, V> entry);
427  }
428
429  @Override
430  public Set<K> keySet() {
431    return new KeySet();
432  }
433
434  @WeakOuter
435  private final class KeySet extends Maps.KeySet<K, V> {
436    KeySet() {
437      super(HashBiMap.this);
438    }
439
440    @Override
441    public Iterator<K> iterator() {
442      return new Itr<K>() {
443        @Override
444        K output(BiEntry<K, V> entry) {
445          return entry.key;
446        }
447      };
448    }
449
450    @Override
451    public boolean remove(@Nullable Object o) {
452      BiEntry<K, V> entry = seekByKey(o, smearedHash(o));
453      if (entry == null) {
454        return false;
455      } else {
456        delete(entry);
457        entry.prevInKeyInsertionOrder = null;
458        entry.nextInKeyInsertionOrder = null;
459        return true;
460      }
461    }
462  }
463
464  @Override
465  public Set<V> values() {
466    return inverse().keySet();
467  }
468
469  @Override
470  Iterator<Entry<K, V>> entryIterator() {
471    return new Itr<Entry<K, V>>() {
472      @Override
473      Entry<K, V> output(BiEntry<K, V> entry) {
474        return new MapEntry(entry);
475      }
476
477      class MapEntry extends AbstractMapEntry<K, V> {
478        BiEntry<K, V> delegate;
479
480        MapEntry(BiEntry<K, V> entry) {
481          this.delegate = entry;
482        }
483
484        @Override
485        public K getKey() {
486          return delegate.key;
487        }
488
489        @Override
490        public V getValue() {
491          return delegate.value;
492        }
493
494        @Override
495        public V setValue(V value) {
496          V oldValue = delegate.value;
497          int valueHash = smearedHash(value);
498          if (valueHash == delegate.valueHash && Objects.equal(value, oldValue)) {
499            return value;
500          }
501          checkArgument(seekByValue(value, valueHash) == null, "value already present: %s", value);
502          delete(delegate);
503          BiEntry<K, V> newEntry =
504              new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash);
505          insert(newEntry, delegate);
506          delegate.prevInKeyInsertionOrder = null;
507          delegate.nextInKeyInsertionOrder = null;
508          expectedModCount = modCount;
509          if (toRemove == delegate) {
510            toRemove = newEntry;
511          }
512          delegate = newEntry;
513          return oldValue;
514        }
515      }
516    };
517  }
518
519  private transient BiMap<V, K> inverse;
520
521  @Override
522  public BiMap<V, K> inverse() {
523    return (inverse == null) ? inverse = new Inverse() : inverse;
524  }
525
526  private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
527    BiMap<K, V> forward() {
528      return HashBiMap.this;
529    }
530
531    @Override
532    public int size() {
533      return size;
534    }
535
536    @Override
537    public void clear() {
538      forward().clear();
539    }
540
541    @Override
542    public boolean containsKey(@Nullable Object value) {
543      return forward().containsValue(value);
544    }
545
546    @Override
547    public K get(@Nullable Object value) {
548      return Maps.keyOrNull(seekByValue(value, smearedHash(value)));
549    }
550
551    @Override
552    public K put(@Nullable V value, @Nullable K key) {
553      return putInverse(value, key, false);
554    }
555
556    @Override
557    public K forcePut(@Nullable V value, @Nullable K key) {
558      return putInverse(value, key, true);
559    }
560
561    @Override
562    public K remove(@Nullable Object value) {
563      BiEntry<K, V> entry = seekByValue(value, smearedHash(value));
564      if (entry == null) {
565        return null;
566      } else {
567        delete(entry);
568        entry.prevInKeyInsertionOrder = null;
569        entry.nextInKeyInsertionOrder = null;
570        return entry.key;
571      }
572    }
573
574    @Override
575    public BiMap<K, V> inverse() {
576      return forward();
577    }
578
579    @Override
580    public Set<V> keySet() {
581      return new InverseKeySet();
582    }
583
584    @WeakOuter
585    private final class InverseKeySet extends Maps.KeySet<V, K> {
586      InverseKeySet() {
587        super(Inverse.this);
588      }
589
590      @Override
591      public boolean remove(@Nullable Object o) {
592        BiEntry<K, V> entry = seekByValue(o, smearedHash(o));
593        if (entry == null) {
594          return false;
595        } else {
596          delete(entry);
597          return true;
598        }
599      }
600
601      @Override
602      public Iterator<V> iterator() {
603        return new Itr<V>() {
604          @Override
605          V output(BiEntry<K, V> entry) {
606            return entry.value;
607          }
608        };
609      }
610    }
611
612    @Override
613    public Set<K> values() {
614      return forward().keySet();
615    }
616
617    @Override
618    public Set<Entry<V, K>> entrySet() {
619      return new Maps.EntrySet<V, K>() {
620
621        @Override
622        Map<V, K> map() {
623          return Inverse.this;
624        }
625
626        @Override
627        public Iterator<Entry<V, K>> iterator() {
628          return new Itr<Entry<V, K>>() {
629            @Override
630            Entry<V, K> output(BiEntry<K, V> entry) {
631              return new InverseEntry(entry);
632            }
633
634            class InverseEntry extends AbstractMapEntry<V, K> {
635              BiEntry<K, V> delegate;
636
637              InverseEntry(BiEntry<K, V> entry) {
638                this.delegate = entry;
639              }
640
641              @Override
642              public V getKey() {
643                return delegate.value;
644              }
645
646              @Override
647              public K getValue() {
648                return delegate.key;
649              }
650
651              @Override
652              public K setValue(K key) {
653                K oldKey = delegate.key;
654                int keyHash = smearedHash(key);
655                if (keyHash == delegate.keyHash && Objects.equal(key, oldKey)) {
656                  return key;
657                }
658                checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key);
659                delete(delegate);
660                BiEntry<K, V> newEntry =
661                    new BiEntry<K, V>(key, keyHash, delegate.value, delegate.valueHash);
662                delegate = newEntry;
663                insert(newEntry, null);
664                expectedModCount = modCount;
665                // This is safe because entries can only get bumped up to earlier in the iteration,
666                // so they can't get revisited.
667                return oldKey;
668              }
669            }
670          };
671        }
672      };
673    }
674
675    Object writeReplace() {
676      return new InverseSerializedForm<K, V>(HashBiMap.this);
677    }
678  }
679
680  private static final class InverseSerializedForm<K, V> implements Serializable {
681    private final HashBiMap<K, V> bimap;
682
683    InverseSerializedForm(HashBiMap<K, V> bimap) {
684      this.bimap = bimap;
685    }
686
687    Object readResolve() {
688      return bimap.inverse();
689    }
690  }
691
692  /**
693   * @serialData the number of entries, first key, first value, second key, second value, and so on.
694   */
695  @GwtIncompatible("java.io.ObjectOutputStream")
696  private void writeObject(ObjectOutputStream stream) throws IOException {
697    stream.defaultWriteObject();
698    Serialization.writeMap(this, stream);
699  }
700
701  @GwtIncompatible("java.io.ObjectInputStream")
702  private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
703    stream.defaultReadObject();
704    init(16);
705    int size = Serialization.readCount(stream);
706    Serialization.populateMap(this, stream, size);
707  }
708
709  @GwtIncompatible("Not needed in emulated source")
710  private static final long serialVersionUID = 0;
711}