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.errorprone.annotations.CanIgnoreReturnValue;
027import com.google.j2objc.annotations.RetainedWith;
028import com.google.j2objc.annotations.WeakOuter;
029import java.io.IOException;
030import java.io.ObjectInputStream;
031import java.io.ObjectOutputStream;
032import java.io.Serializable;
033import java.util.AbstractMap;
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 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>This implementation guarantees insertion-based iteration order of its keys.
047 *
048 * <p>See the Guava User Guide article on <a href=
049 * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#bimap"> {@code BiMap} </a>.
050 *
051 * @author Louis Wasserman
052 * @author Mike Bostock
053 * @since 2.0
054 */
055@GwtCompatible(emulated = true)
056public final class HashBiMap<K, V> extends IteratorBasedAbstractMap<K, V>
057    implements BiMap<K, V>, Serializable {
058
059  /**
060   * Returns a new, empty {@code HashBiMap} with the default initial capacity (16).
061   */
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<K, V>(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    @Nullable BiEntry<K, V> nextInKToVBucket;
091    @Nullable BiEntry<K, V> nextInVToKBucket;
092
093    @Nullable BiEntry<K, V> nextInKeyInsertionOrder;
094    @Nullable 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
131   * key-to-value direction 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, @Nullable 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(@Nullable 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(@Nullable 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(@Nullable Object key) {
243    return seekByKey(key, smearedHash(key)) != null;
244  }
245
246  @Override
247  public boolean containsValue(@Nullable Object value) {
248    return seekByValue(value, smearedHash(value)) != null;
249  }
250
251  @Nullable
252  @Override
253  public V get(@Nullable Object key) {
254    return Maps.valueOrNull(seekByKey(key, smearedHash(key)));
255  }
256
257  @CanIgnoreReturnValue
258  @Override
259  public V put(@Nullable K key, @Nullable V value) {
260    return put(key, value, false);
261  }
262
263  @CanIgnoreReturnValue
264  @Override
265  public V forcePut(@Nullable K key, @Nullable V value) {
266    return put(key, value, true);
267  }
268
269  private V put(@Nullable K key, @Nullable 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<K, V>(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  @Nullable
305  private K putInverse(@Nullable V value, @Nullable K key, boolean force) {
306    int valueHash = smearedHash(value);
307    int keyHash = smearedHash(key);
308
309    BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
310    if (oldEntryForValue != null
311        && keyHash == oldEntryForValue.keyHash
312        && Objects.equal(key, oldEntryForValue.key)) {
313      return key;
314    }
315
316    BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
317    if (oldEntryForKey != null) {
318      if (force) {
319        delete(oldEntryForKey);
320      } else {
321        throw new IllegalArgumentException("value already present: " + key);
322      }
323    }
324
325    if (oldEntryForValue != null) {
326      delete(oldEntryForValue);
327    }
328    BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
329    insert(newEntry, oldEntryForKey);
330    if (oldEntryForKey != null) {
331      oldEntryForKey.prevInKeyInsertionOrder = null;
332      oldEntryForKey.nextInKeyInsertionOrder = null;
333    }
334    rehashIfNecessary();
335    return Maps.keyOrNull(oldEntryForValue);
336  }
337
338  private void rehashIfNecessary() {
339    BiEntry<K, V>[] oldKToV = hashTableKToV;
340    if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
341      int newTableSize = oldKToV.length * 2;
342
343      this.hashTableKToV = createTable(newTableSize);
344      this.hashTableVToK = createTable(newTableSize);
345      this.mask = newTableSize - 1;
346      this.size = 0;
347
348      for (BiEntry<K, V> entry = firstInKeyInsertionOrder;
349          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  @CanIgnoreReturnValue
363  @Override
364  public V remove(@Nullable Object key) {
365    BiEntry<K, V> entry = seekByKey(key, smearedHash(key));
366    if (entry == null) {
367      return null;
368    } else {
369      delete(entry);
370      entry.prevInKeyInsertionOrder = null;
371      entry.nextInKeyInsertionOrder = null;
372      return entry.value;
373    }
374  }
375
376  @Override
377  public void clear() {
378    size = 0;
379    Arrays.fill(hashTableKToV, null);
380    Arrays.fill(hashTableVToK, null);
381    firstInKeyInsertionOrder = null;
382    lastInKeyInsertionOrder = null;
383    modCount++;
384  }
385
386  @Override
387  public int size() {
388    return size;
389  }
390
391  abstract class Itr<T> implements Iterator<T> {
392    BiEntry<K, V> next = firstInKeyInsertionOrder;
393    BiEntry<K, V> toRemove = null;
394    int expectedModCount = modCount;
395
396    @Override
397    public boolean hasNext() {
398      if (modCount != expectedModCount) {
399        throw new ConcurrentModificationException();
400      }
401      return next != null;
402    }
403
404    @Override
405    public T next() {
406      if (!hasNext()) {
407        throw new NoSuchElementException();
408      }
409
410      BiEntry<K, V> entry = next;
411      next = entry.nextInKeyInsertionOrder;
412      toRemove = entry;
413      return output(entry);
414    }
415
416    @Override
417    public void remove() {
418      if (modCount != expectedModCount) {
419        throw new ConcurrentModificationException();
420      }
421      checkRemove(toRemove != null);
422      delete(toRemove);
423      expectedModCount = modCount;
424      toRemove = null;
425    }
426
427    abstract T output(BiEntry<K, V> entry);
428  }
429
430  @Override
431  public Set<K> keySet() {
432    return new KeySet();
433  }
434
435  @WeakOuter
436  private final class KeySet extends Maps.KeySet<K, V> {
437    KeySet() {
438      super(HashBiMap.this);
439    }
440
441    @Override
442    public Iterator<K> iterator() {
443      return new Itr<K>() {
444        @Override
445        K output(BiEntry<K, V> entry) {
446          return entry.key;
447        }
448      };
449    }
450
451    @Override
452    public boolean remove(@Nullable Object o) {
453      BiEntry<K, V> entry = seekByKey(o, smearedHash(o));
454      if (entry == null) {
455        return false;
456      } else {
457        delete(entry);
458        entry.prevInKeyInsertionOrder = null;
459        entry.nextInKeyInsertionOrder = null;
460        return true;
461      }
462    }
463  }
464
465  @Override
466  public Set<V> values() {
467    return inverse().keySet();
468  }
469
470  @Override
471  Iterator<Entry<K, V>> entryIterator() {
472    return new Itr<Entry<K, V>>() {
473      @Override
474      Entry<K, V> output(BiEntry<K, V> entry) {
475        return new MapEntry(entry);
476      }
477
478      class MapEntry extends AbstractMapEntry<K, V> {
479        BiEntry<K, V> delegate;
480
481        MapEntry(BiEntry<K, V> entry) {
482          this.delegate = entry;
483        }
484
485        @Override
486        public K getKey() {
487          return delegate.key;
488        }
489
490        @Override
491        public V getValue() {
492          return delegate.value;
493        }
494
495        @Override
496        public V setValue(V value) {
497          V oldValue = delegate.value;
498          int valueHash = smearedHash(value);
499          if (valueHash == delegate.valueHash && Objects.equal(value, oldValue)) {
500            return value;
501          }
502          checkArgument(seekByValue(value, valueHash) == null, "value already present: %s", value);
503          delete(delegate);
504          BiEntry<K, V> newEntry =
505              new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash);
506          insert(newEntry, delegate);
507          delegate.prevInKeyInsertionOrder = null;
508          delegate.nextInKeyInsertionOrder = null;
509          expectedModCount = modCount;
510          if (toRemove == delegate) {
511            toRemove = newEntry;
512          }
513          delegate = newEntry;
514          return oldValue;
515        }
516      }
517    };
518  }
519
520  @RetainedWith
521  private transient BiMap<V, K> inverse;
522
523  @Override
524  public BiMap<V, K> inverse() {
525    return (inverse == null) ? inverse = new Inverse() : inverse;
526  }
527
528  private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
529    BiMap<K, V> forward() {
530      return HashBiMap.this;
531    }
532
533    @Override
534    public int size() {
535      return size;
536    }
537
538    @Override
539    public void clear() {
540      forward().clear();
541    }
542
543    @Override
544    public boolean containsKey(@Nullable Object value) {
545      return forward().containsValue(value);
546    }
547
548    @Override
549    public K get(@Nullable Object value) {
550      return Maps.keyOrNull(seekByValue(value, smearedHash(value)));
551    }
552
553    @Override
554    public K put(@Nullable V value, @Nullable K key) {
555      return putInverse(value, key, false);
556    }
557
558    @Override
559    public K forcePut(@Nullable V value, @Nullable K key) {
560      return putInverse(value, key, true);
561    }
562
563    @Override
564    public K remove(@Nullable Object value) {
565      BiEntry<K, V> entry = seekByValue(value, smearedHash(value));
566      if (entry == null) {
567        return null;
568      } else {
569        delete(entry);
570        entry.prevInKeyInsertionOrder = null;
571        entry.nextInKeyInsertionOrder = null;
572        return entry.key;
573      }
574    }
575
576    @Override
577    public BiMap<K, V> inverse() {
578      return forward();
579    }
580
581    @Override
582    public Set<V> keySet() {
583      return new InverseKeySet();
584    }
585
586    @WeakOuter
587    private final class InverseKeySet extends Maps.KeySet<V, K> {
588      InverseKeySet() {
589        super(Inverse.this);
590      }
591
592      @Override
593      public boolean remove(@Nullable Object o) {
594        BiEntry<K, V> entry = seekByValue(o, smearedHash(o));
595        if (entry == null) {
596          return false;
597        } else {
598          delete(entry);
599          return true;
600        }
601      }
602
603      @Override
604      public Iterator<V> iterator() {
605        return new Itr<V>() {
606          @Override
607          V output(BiEntry<K, V> entry) {
608            return entry.value;
609          }
610        };
611      }
612    }
613
614    @Override
615    public Set<K> values() {
616      return forward().keySet();
617    }
618
619    @Override
620    public Set<Entry<V, K>> entrySet() {
621      return new Maps.EntrySet<V, K>() {
622
623        @Override
624        Map<V, K> map() {
625          return Inverse.this;
626        }
627
628        @Override
629        public Iterator<Entry<V, K>> iterator() {
630          return new Itr<Entry<V, K>>() {
631            @Override
632            Entry<V, K> output(BiEntry<K, V> entry) {
633              return new InverseEntry(entry);
634            }
635
636            class InverseEntry extends AbstractMapEntry<V, K> {
637              BiEntry<K, V> delegate;
638
639              InverseEntry(BiEntry<K, V> entry) {
640                this.delegate = entry;
641              }
642
643              @Override
644              public V getKey() {
645                return delegate.value;
646              }
647
648              @Override
649              public K getValue() {
650                return delegate.key;
651              }
652
653              @Override
654              public K setValue(K key) {
655                K oldKey = delegate.key;
656                int keyHash = smearedHash(key);
657                if (keyHash == delegate.keyHash && Objects.equal(key, oldKey)) {
658                  return key;
659                }
660                checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key);
661                delete(delegate);
662                BiEntry<K, V> newEntry =
663                    new BiEntry<K, V>(key, keyHash, delegate.value, delegate.valueHash);
664                delegate = newEntry;
665                insert(newEntry, null);
666                expectedModCount = modCount;
667                // This is safe because entries can only get bumped up to earlier in the iteration,
668                // so they can't get revisited.
669                return oldKey;
670              }
671            }
672          };
673        }
674      };
675    }
676
677    Object writeReplace() {
678      return new InverseSerializedForm<K, V>(HashBiMap.this);
679    }
680  }
681
682  private static final class InverseSerializedForm<K, V> implements Serializable {
683    private final HashBiMap<K, V> bimap;
684
685    InverseSerializedForm(HashBiMap<K, V> bimap) {
686      this.bimap = bimap;
687    }
688
689    Object readResolve() {
690      return bimap.inverse();
691    }
692  }
693
694  /**
695   * @serialData the number of entries, first key, first value, second key, second value, and so on.
696   */
697  @GwtIncompatible // java.io.ObjectOutputStream
698  private void writeObject(ObjectOutputStream stream) throws IOException {
699    stream.defaultWriteObject();
700    Serialization.writeMap(this, stream);
701  }
702
703  @GwtIncompatible // java.io.ObjectInputStream
704  private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
705    stream.defaultReadObject();
706    init(16);
707    int size = Serialization.readCount(stream);
708    Serialization.populateMap(this, stream, size);
709  }
710
711  @GwtIncompatible // Not needed in emulated source
712  private static final long serialVersionUID = 0;
713}