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 BiEntry<K, V> nextInKToVBucket;
090    @Nullable BiEntry<K, V> nextInVToKBucket;
091
092    @Nullable BiEntry<K, V> nextInKeyInsertionOrder;
093    @Nullable BiEntry<K, V> prevInKeyInsertionOrder;
094
095    BiEntry(K key, int keyHash, V value, int valueHash) {
096      super(key, value);
097      this.keyHash = keyHash;
098      this.valueHash = valueHash;
099    }
100  }
101
102  private static final double LOAD_FACTOR = 1.0;
103
104  private transient BiEntry<K, V>[] hashTableKToV;
105  private transient BiEntry<K, V>[] hashTableVToK;
106  private transient BiEntry<K, V> firstInKeyInsertionOrder;
107  private transient BiEntry<K, V> lastInKeyInsertionOrder;
108  private transient int size;
109  private transient int mask;
110  private transient int modCount;
111
112  private HashBiMap(int expectedSize) {
113    init(expectedSize);
114  }
115
116  private void init(int expectedSize) {
117    checkNonnegative(expectedSize, "expectedSize");
118    int tableSize = Hashing.closedTableSize(expectedSize, LOAD_FACTOR);
119    this.hashTableKToV = createTable(tableSize);
120    this.hashTableVToK = createTable(tableSize);
121    this.firstInKeyInsertionOrder = null;
122    this.lastInKeyInsertionOrder = null;
123    this.size = 0;
124    this.mask = tableSize - 1;
125    this.modCount = 0;
126  }
127
128  /**
129   * Finds and removes {@code entry} from the bucket linked lists in both the
130   * key-to-value direction and the value-to-key direction.
131   */
132  private void delete(BiEntry<K, V> entry) {
133    int keyBucket = entry.keyHash & mask;
134    BiEntry<K, V> prevBucketEntry = null;
135    for (BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket];
136        true;
137        bucketEntry = bucketEntry.nextInKToVBucket) {
138      if (bucketEntry == entry) {
139        if (prevBucketEntry == null) {
140          hashTableKToV[keyBucket] = entry.nextInKToVBucket;
141        } else {
142          prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket;
143        }
144        break;
145      }
146      prevBucketEntry = bucketEntry;
147    }
148
149    int valueBucket = entry.valueHash & mask;
150    prevBucketEntry = null;
151    for (BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];
152        true;
153        bucketEntry = bucketEntry.nextInVToKBucket) {
154      if (bucketEntry == entry) {
155        if (prevBucketEntry == null) {
156          hashTableVToK[valueBucket] = entry.nextInVToKBucket;
157        } else {
158          prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket;
159        }
160        break;
161      }
162      prevBucketEntry = bucketEntry;
163    }
164
165    if (entry.prevInKeyInsertionOrder == null) {
166      firstInKeyInsertionOrder = entry.nextInKeyInsertionOrder;
167    } else {
168      entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry.nextInKeyInsertionOrder;
169    }
170
171    if (entry.nextInKeyInsertionOrder == null) {
172      lastInKeyInsertionOrder = entry.prevInKeyInsertionOrder;
173    } else {
174      entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry.prevInKeyInsertionOrder;
175    }
176
177    size--;
178    modCount++;
179  }
180
181  private void insert(BiEntry<K, V> entry, @Nullable BiEntry<K, V> oldEntryForKey) {
182    int keyBucket = entry.keyHash & mask;
183    entry.nextInKToVBucket = hashTableKToV[keyBucket];
184    hashTableKToV[keyBucket] = entry;
185
186    int valueBucket = entry.valueHash & mask;
187    entry.nextInVToKBucket = hashTableVToK[valueBucket];
188    hashTableVToK[valueBucket] = entry;
189
190    if (oldEntryForKey == null) {
191      entry.prevInKeyInsertionOrder = lastInKeyInsertionOrder;
192      entry.nextInKeyInsertionOrder = null;
193      if (lastInKeyInsertionOrder == null) {
194        firstInKeyInsertionOrder = entry;
195      } else {
196        lastInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
197      }
198      lastInKeyInsertionOrder = entry;
199    } else {
200      entry.prevInKeyInsertionOrder = oldEntryForKey.prevInKeyInsertionOrder;
201      if (entry.prevInKeyInsertionOrder == null) {
202        firstInKeyInsertionOrder = entry;
203      } else {
204        entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
205      }
206      entry.nextInKeyInsertionOrder = oldEntryForKey.nextInKeyInsertionOrder;
207      if (entry.nextInKeyInsertionOrder == null) {
208        lastInKeyInsertionOrder = entry;
209      } else {
210        entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry;
211      }
212    }
213
214    size++;
215    modCount++;
216  }
217
218  private BiEntry<K, V> seekByKey(@Nullable Object key, int keyHash) {
219    for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask];
220        entry != null;
221        entry = entry.nextInKToVBucket) {
222      if (keyHash == entry.keyHash && Objects.equal(key, entry.key)) {
223        return entry;
224      }
225    }
226    return null;
227  }
228
229  private BiEntry<K, V> seekByValue(@Nullable Object value, int valueHash) {
230    for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask];
231        entry != null;
232        entry = entry.nextInVToKBucket) {
233      if (valueHash == entry.valueHash && Objects.equal(value, entry.value)) {
234        return entry;
235      }
236    }
237    return null;
238  }
239
240  @Override
241  public boolean containsKey(@Nullable Object key) {
242    return seekByKey(key, smearedHash(key)) != null;
243  }
244
245  @Override
246  public boolean containsValue(@Nullable Object value) {
247    return seekByValue(value, smearedHash(value)) != null;
248  }
249
250  @Nullable
251  @Override
252  public V get(@Nullable Object key) {
253    return Maps.valueOrNull(seekByKey(key, smearedHash(key)));
254  }
255
256  @Override
257  public V put(@Nullable K key, @Nullable V value) {
258    return put(key, value, false);
259  }
260
261  @Override
262  public V forcePut(@Nullable K key, @Nullable V value) {
263    return put(key, value, true);
264  }
265
266  private V put(@Nullable K key, @Nullable V value, boolean force) {
267    int keyHash = smearedHash(key);
268    int valueHash = smearedHash(value);
269
270    BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
271    if (oldEntryForKey != null
272        && valueHash == oldEntryForKey.valueHash
273        && Objects.equal(value, oldEntryForKey.value)) {
274      return value;
275    }
276
277    BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
278    if (oldEntryForValue != null) {
279      if (force) {
280        delete(oldEntryForValue);
281      } else {
282        throw new IllegalArgumentException("value already present: " + value);
283      }
284    }
285
286    BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
287    if (oldEntryForKey != null) {
288      delete(oldEntryForKey);
289      insert(newEntry, oldEntryForKey);
290      oldEntryForKey.prevInKeyInsertionOrder = null;
291      oldEntryForKey.nextInKeyInsertionOrder = null;
292      rehashIfNecessary();
293      return oldEntryForKey.value;
294    } else {
295      insert(newEntry, null);
296      rehashIfNecessary();
297      return null;
298    }
299  }
300
301  @Nullable
302  private K putInverse(@Nullable V value, @Nullable K key, boolean force) {
303    int valueHash = smearedHash(value);
304    int keyHash = smearedHash(key);
305
306    BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
307    if (oldEntryForValue != null
308        && keyHash == oldEntryForValue.keyHash
309        && Objects.equal(key, oldEntryForValue.key)) {
310      return key;
311    }
312
313    BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
314    if (oldEntryForKey != null) {
315      if (force) {
316        delete(oldEntryForKey);
317      } else {
318        throw new IllegalArgumentException("value already present: " + key);
319      }
320    }
321
322    if (oldEntryForValue != null) {
323      delete(oldEntryForValue);
324    }
325    BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
326    insert(newEntry, oldEntryForKey);
327    if (oldEntryForKey != null) {
328      oldEntryForKey.prevInKeyInsertionOrder = null;
329      oldEntryForKey.nextInKeyInsertionOrder = null;
330    }
331    rehashIfNecessary();
332    return Maps.keyOrNull(oldEntryForValue);
333  }
334
335  private void rehashIfNecessary() {
336    BiEntry<K, V>[] oldKToV = hashTableKToV;
337    if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
338      int newTableSize = oldKToV.length * 2;
339
340      this.hashTableKToV = createTable(newTableSize);
341      this.hashTableVToK = createTable(newTableSize);
342      this.mask = newTableSize - 1;
343      this.size = 0;
344
345      for (BiEntry<K, V> entry = firstInKeyInsertionOrder;
346          entry != null;
347          entry = entry.nextInKeyInsertionOrder) {
348        insert(entry, entry);
349      }
350      this.modCount++;
351    }
352  }
353
354  @SuppressWarnings("unchecked")
355  private BiEntry<K, V>[] createTable(int length) {
356    return new BiEntry[length];
357  }
358
359  @Override
360  public V remove(@Nullable Object key) {
361    BiEntry<K, V> entry = seekByKey(key, smearedHash(key));
362    if (entry == null) {
363      return null;
364    } else {
365      delete(entry);
366      entry.prevInKeyInsertionOrder = null;
367      entry.nextInKeyInsertionOrder = null;
368      return entry.value;
369    }
370  }
371
372  @Override
373  public void clear() {
374    size = 0;
375    Arrays.fill(hashTableKToV, null);
376    Arrays.fill(hashTableVToK, null);
377    firstInKeyInsertionOrder = null;
378    lastInKeyInsertionOrder = null;
379    modCount++;
380  }
381
382  @Override
383  public int size() {
384    return size;
385  }
386
387  abstract class Itr<T> implements Iterator<T> {
388    BiEntry<K, V> next = firstInKeyInsertionOrder;
389    BiEntry<K, V> toRemove = null;
390    int expectedModCount = modCount;
391
392    @Override
393    public boolean hasNext() {
394      if (modCount != expectedModCount) {
395        throw new ConcurrentModificationException();
396      }
397      return next != null;
398    }
399
400    @Override
401    public T next() {
402      if (!hasNext()) {
403        throw new NoSuchElementException();
404      }
405
406      BiEntry<K, V> entry = next;
407      next = entry.nextInKeyInsertionOrder;
408      toRemove = entry;
409      return output(entry);
410    }
411
412    @Override
413    public void remove() {
414      if (modCount != expectedModCount) {
415        throw new ConcurrentModificationException();
416      }
417      checkRemove(toRemove != null);
418      delete(toRemove);
419      expectedModCount = modCount;
420      toRemove = null;
421    }
422
423    abstract T output(BiEntry<K, V> entry);
424  }
425
426  @Override
427  public Set<K> keySet() {
428    return new KeySet();
429  }
430
431  @WeakOuter
432  private final class KeySet extends Maps.KeySet<K, V> {
433    KeySet() {
434      super(HashBiMap.this);
435    }
436
437    @Override
438    public Iterator<K> iterator() {
439      return new Itr<K>() {
440        @Override
441        K output(BiEntry<K, V> entry) {
442          return entry.key;
443        }
444      };
445    }
446
447    @Override
448    public boolean remove(@Nullable Object o) {
449      BiEntry<K, V> entry = seekByKey(o, smearedHash(o));
450      if (entry == null) {
451        return false;
452      } else {
453        delete(entry);
454        entry.prevInKeyInsertionOrder = null;
455        entry.nextInKeyInsertionOrder = null;
456        return true;
457      }
458    }
459  }
460
461  @Override
462  public Set<V> values() {
463    return inverse().keySet();
464  }
465
466  @Override
467  Iterator<Entry<K, V>> entryIterator() {
468    return new Itr<Entry<K, V>>() {
469      @Override
470      Entry<K, V> output(BiEntry<K, V> entry) {
471        return new MapEntry(entry);
472      }
473
474      class MapEntry extends AbstractMapEntry<K, V> {
475        BiEntry<K, V> delegate;
476
477        MapEntry(BiEntry<K, V> entry) {
478          this.delegate = entry;
479        }
480
481        @Override
482        public K getKey() {
483          return delegate.key;
484        }
485
486        @Override
487        public V getValue() {
488          return delegate.value;
489        }
490
491        @Override
492        public V setValue(V value) {
493          V oldValue = delegate.value;
494          int valueHash = smearedHash(value);
495          if (valueHash == delegate.valueHash && Objects.equal(value, oldValue)) {
496            return value;
497          }
498          checkArgument(seekByValue(value, valueHash) == null, "value already present: %s", value);
499          delete(delegate);
500          BiEntry<K, V> newEntry =
501              new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash);
502          insert(newEntry, delegate);
503          delegate.prevInKeyInsertionOrder = null;
504          delegate.nextInKeyInsertionOrder = null;
505          expectedModCount = modCount;
506          if (toRemove == delegate) {
507            toRemove = newEntry;
508          }
509          delegate = newEntry;
510          return oldValue;
511        }
512      }
513    };
514  }
515
516  private transient BiMap<V, K> inverse;
517
518  @Override
519  public BiMap<V, K> inverse() {
520    return (inverse == null) ? inverse = new Inverse() : inverse;
521  }
522
523  private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
524    BiMap<K, V> forward() {
525      return HashBiMap.this;
526    }
527
528    @Override
529    public int size() {
530      return size;
531    }
532
533    @Override
534    public void clear() {
535      forward().clear();
536    }
537
538    @Override
539    public boolean containsKey(@Nullable Object value) {
540      return forward().containsValue(value);
541    }
542
543    @Override
544    public K get(@Nullable Object value) {
545      return Maps.keyOrNull(seekByValue(value, smearedHash(value)));
546    }
547
548    @Override
549    public K put(@Nullable V value, @Nullable K key) {
550      return putInverse(value, key, false);
551    }
552
553    @Override
554    public K forcePut(@Nullable V value, @Nullable K key) {
555      return putInverse(value, key, true);
556    }
557
558    @Override
559    public K remove(@Nullable Object value) {
560      BiEntry<K, V> entry = seekByValue(value, smearedHash(value));
561      if (entry == null) {
562        return null;
563      } else {
564        delete(entry);
565        entry.prevInKeyInsertionOrder = null;
566        entry.nextInKeyInsertionOrder = null;
567        return entry.key;
568      }
569    }
570
571    @Override
572    public BiMap<K, V> inverse() {
573      return forward();
574    }
575
576    @Override
577    public Set<V> keySet() {
578      return new InverseKeySet();
579    }
580
581    @WeakOuter
582    private final class InverseKeySet extends Maps.KeySet<V, K> {
583      InverseKeySet() {
584        super(Inverse.this);
585      }
586
587      @Override
588      public boolean remove(@Nullable Object o) {
589        BiEntry<K, V> entry = seekByValue(o, smearedHash(o));
590        if (entry == null) {
591          return false;
592        } else {
593          delete(entry);
594          return true;
595        }
596      }
597
598      @Override
599      public Iterator<V> iterator() {
600        return new Itr<V>() {
601          @Override
602          V output(BiEntry<K, V> entry) {
603            return entry.value;
604          }
605        };
606      }
607    }
608
609    @Override
610    public Set<K> values() {
611      return forward().keySet();
612    }
613
614    @Override
615    public Set<Entry<V, K>> entrySet() {
616      return new Maps.EntrySet<V, K>() {
617
618        @Override
619        Map<V, K> map() {
620          return Inverse.this;
621        }
622
623        @Override
624        public Iterator<Entry<V, K>> iterator() {
625          return new Itr<Entry<V, K>>() {
626            @Override
627            Entry<V, K> output(BiEntry<K, V> entry) {
628              return new InverseEntry(entry);
629            }
630
631            class InverseEntry extends AbstractMapEntry<V, K> {
632              BiEntry<K, V> delegate;
633
634              InverseEntry(BiEntry<K, V> entry) {
635                this.delegate = entry;
636              }
637
638              @Override
639              public V getKey() {
640                return delegate.value;
641              }
642
643              @Override
644              public K getValue() {
645                return delegate.key;
646              }
647
648              @Override
649              public K setValue(K key) {
650                K oldKey = delegate.key;
651                int keyHash = smearedHash(key);
652                if (keyHash == delegate.keyHash && Objects.equal(key, oldKey)) {
653                  return key;
654                }
655                checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key);
656                delete(delegate);
657                BiEntry<K, V> newEntry =
658                    new BiEntry<K, V>(key, keyHash, delegate.value, delegate.valueHash);
659                delegate = newEntry;
660                insert(newEntry, null);
661                expectedModCount = modCount;
662                // This is safe because entries can only get bumped up to earlier in the iteration,
663                // so they can't get revisited.
664                return oldKey;
665              }
666            }
667          };
668        }
669      };
670    }
671
672    Object writeReplace() {
673      return new InverseSerializedForm<K, V>(HashBiMap.this);
674    }
675  }
676
677  private static final class InverseSerializedForm<K, V> implements Serializable {
678    private final HashBiMap<K, V> bimap;
679
680    InverseSerializedForm(HashBiMap<K, V> bimap) {
681      this.bimap = bimap;
682    }
683
684    Object readResolve() {
685      return bimap.inverse();
686    }
687  }
688
689  /**
690   * @serialData the number of entries, first key, first value, second key, second value, and so on.
691   */
692  @GwtIncompatible("java.io.ObjectOutputStream")
693  private void writeObject(ObjectOutputStream stream) throws IOException {
694    stream.defaultWriteObject();
695    Serialization.writeMap(this, stream);
696  }
697
698  @GwtIncompatible("java.io.ObjectInputStream")
699  private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
700    stream.defaultReadObject();
701    init(16);
702    int size = Serialization.readCount(stream);
703    Serialization.populateMap(this, stream, size);
704  }
705
706  @GwtIncompatible("Not needed in emulated source")
707  private static final long serialVersionUID = 0;
708}