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