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