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