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;
018
019import com.google.common.annotations.GwtCompatible;
020import com.google.common.annotations.GwtIncompatible;
021import com.google.common.base.Objects;
022import com.google.errorprone.annotations.CanIgnoreReturnValue;
023import com.google.j2objc.annotations.RetainedWith;
024import java.io.IOException;
025import java.io.ObjectInputStream;
026import java.io.ObjectOutputStream;
027import java.io.Serializable;
028import java.util.AbstractMap;
029import java.util.AbstractSet;
030import java.util.Arrays;
031import java.util.ConcurrentModificationException;
032import java.util.Iterator;
033import java.util.Map;
034import java.util.NoSuchElementException;
035import java.util.Set;
036import org.checkerframework.checker.nullness.compatqual.NullableDecl;
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>This implementation guarantees insertion-based iteration order of its keys.
043 *
044 * <p>See the Guava User Guide article on <a href=
045 * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#bimap"> {@code BiMap} </a>.
046 *
047 * @author Louis Wasserman
048 * @author Mike Bostock
049 * @since 2.0
050 */
051@GwtCompatible
052public final class HashBiMap<K, V> extends AbstractMap<K, V> implements BiMap<K, V>, Serializable {
053
054  /** Returns a new, empty {@code HashBiMap} with the default initial capacity (16). */
055  public static <K, V> HashBiMap<K, V> create() {
056    return create(16);
057  }
058
059  /**
060   * Constructs a new, empty bimap with the specified expected size.
061   *
062   * @param expectedSize the expected number of entries
063   * @throws IllegalArgumentException if the specified expected size is negative
064   */
065  public static <K, V> HashBiMap<K, V> create(int expectedSize) {
066    return new HashBiMap<>(expectedSize);
067  }
068
069  /**
070   * Constructs a new bimap containing initial values from {@code map}. The bimap is created with an
071   * initial capacity sufficient to hold the mappings in the specified map.
072   */
073  public static <K, V> HashBiMap<K, V> create(Map<? extends K, ? extends V> map) {
074    HashBiMap<K, V> bimap = create(map.size());
075    bimap.putAll(map);
076    return bimap;
077  }
078
079  private static final int ABSENT = -1;
080  private static final int ENDPOINT = -2;
081
082  /** Maps an "entry" to the key of that entry. */
083  transient K[] keys;
084  /** Maps an "entry" to the value of that entry. */
085  transient V[] values;
086
087  transient int size;
088  transient int modCount;
089  /** Maps a bucket to the "entry" of its first element. */
090  private transient int[] hashTableKToV;
091  /** Maps a bucket to the "entry" of its first element. */
092  private transient int[] hashTableVToK;
093  /** Maps an "entry" to the "entry" that follows it in its bucket. */
094  private transient int[] nextInBucketKToV;
095  /** Maps an "entry" to the "entry" that follows it in its bucket. */
096  private transient int[] nextInBucketVToK;
097  /** The "entry" of the first element in insertion order. */
098  private transient int firstInInsertionOrder;
099  /** The "entry" of the last element in insertion order. */
100  private transient int lastInInsertionOrder;
101  /** Maps an "entry" to the "entry" that precedes it in insertion order. */
102  private transient int[] prevInInsertionOrder;
103  /** Maps an "entry" to the "entry" that follows it in insertion order. */
104  private transient int[] nextInInsertionOrder;
105
106  private HashBiMap(int expectedSize) {
107    init(expectedSize);
108  }
109
110  @SuppressWarnings("unchecked")
111  void init(int expectedSize) {
112    CollectPreconditions.checkNonnegative(expectedSize, "expectedSize");
113    int tableSize = Hashing.closedTableSize(expectedSize, 1.0);
114    size = 0;
115
116    keys = (K[]) new Object[expectedSize];
117    values = (V[]) new Object[expectedSize];
118
119    hashTableKToV = createFilledWithAbsent(tableSize);
120    hashTableVToK = createFilledWithAbsent(tableSize);
121    nextInBucketKToV = createFilledWithAbsent(expectedSize);
122    nextInBucketVToK = createFilledWithAbsent(expectedSize);
123
124    firstInInsertionOrder = ENDPOINT;
125    lastInInsertionOrder = ENDPOINT;
126
127    prevInInsertionOrder = createFilledWithAbsent(expectedSize);
128    nextInInsertionOrder = createFilledWithAbsent(expectedSize);
129  }
130
131  /** Returns an int array of the specified size, filled with ABSENT. */
132  private static int[] createFilledWithAbsent(int size) {
133    int[] array = new int[size];
134    Arrays.fill(array, ABSENT);
135    return array;
136  }
137
138  /** Equivalent to {@code Arrays.copyOf(array, newSize)}, save that the new elements are ABSENT. */
139  private static int[] expandAndFillWithAbsent(int[] array, int newSize) {
140    int oldSize = array.length;
141    int[] result = Arrays.copyOf(array, newSize);
142    Arrays.fill(result, oldSize, newSize, ABSENT);
143    return result;
144  }
145
146  @Override
147  public int size() {
148    return size;
149  }
150
151  /**
152   * Ensures that all of the internal structures in the HashBiMap are ready for this many elements.
153   */
154  private void ensureCapacity(int minCapacity) {
155    if (nextInBucketKToV.length < minCapacity) {
156      int oldCapacity = nextInBucketKToV.length;
157      int newCapacity = ImmutableCollection.Builder.expandedCapacity(oldCapacity, minCapacity);
158
159      keys = Arrays.copyOf(keys, newCapacity);
160      values = Arrays.copyOf(values, newCapacity);
161      nextInBucketKToV = expandAndFillWithAbsent(nextInBucketKToV, newCapacity);
162      nextInBucketVToK = expandAndFillWithAbsent(nextInBucketVToK, newCapacity);
163      prevInInsertionOrder = expandAndFillWithAbsent(prevInInsertionOrder, newCapacity);
164      nextInInsertionOrder = expandAndFillWithAbsent(nextInInsertionOrder, newCapacity);
165    }
166
167    if (hashTableKToV.length < minCapacity) {
168      int newTableSize = Hashing.closedTableSize(minCapacity, 1.0);
169      hashTableKToV = createFilledWithAbsent(newTableSize);
170      hashTableVToK = createFilledWithAbsent(newTableSize);
171
172      for (int entryToRehash = 0; entryToRehash < size; entryToRehash++) {
173        int keyHash = Hashing.smearedHash(keys[entryToRehash]);
174        int keyBucket = bucket(keyHash);
175        nextInBucketKToV[entryToRehash] = hashTableKToV[keyBucket];
176        hashTableKToV[keyBucket] = entryToRehash;
177
178        int valueHash = Hashing.smearedHash(values[entryToRehash]);
179        int valueBucket = bucket(valueHash);
180        nextInBucketVToK[entryToRehash] = hashTableVToK[valueBucket];
181        hashTableVToK[valueBucket] = entryToRehash;
182      }
183    }
184  }
185
186  /**
187   * Returns the bucket (in either the K-to-V or V-to-K tables) where elements with the specified
188   * hash could be found, if present, or could be inserted.
189   */
190  private int bucket(int hash) {
191    return hash & (hashTableKToV.length - 1);
192  }
193
194  /** Given a key, returns the index of the entry in the tables, or ABSENT if not found. */
195  int findEntryByKey(@NullableDecl Object key) {
196    return findEntryByKey(key, Hashing.smearedHash(key));
197  }
198
199  /**
200   * Given a key and its hash, returns the index of the entry in the tables, or ABSENT if not found.
201   */
202  int findEntryByKey(@NullableDecl Object key, int keyHash) {
203    return findEntry(key, keyHash, hashTableKToV, nextInBucketKToV, keys);
204  }
205
206  /** Given a value, returns the index of the entry in the tables, or ABSENT if not found. */
207  int findEntryByValue(@NullableDecl Object value) {
208    return findEntryByValue(value, Hashing.smearedHash(value));
209  }
210
211  /**
212   * Given a value and its hash, returns the index of the entry in the tables, or ABSENT if not
213   * found.
214   */
215  int findEntryByValue(@NullableDecl Object value, int valueHash) {
216    return findEntry(value, valueHash, hashTableVToK, nextInBucketVToK, values);
217  }
218
219  int findEntry(
220      @NullableDecl Object o, int oHash, int[] hashTable, int[] nextInBucket, Object[] array) {
221    for (int entry = hashTable[bucket(oHash)]; entry != ABSENT; entry = nextInBucket[entry]) {
222      if (Objects.equal(array[entry], o)) {
223        return entry;
224      }
225    }
226    return ABSENT;
227  }
228
229  @Override
230  public boolean containsKey(@NullableDecl Object key) {
231    return findEntryByKey(key) != ABSENT;
232  }
233
234  @Override
235  public boolean containsValue(@NullableDecl Object value) {
236    return findEntryByValue(value) != ABSENT;
237  }
238
239  @Override
240  @NullableDecl
241  public V get(@NullableDecl Object key) {
242    int entry = findEntryByKey(key);
243    return (entry == ABSENT) ? null : values[entry];
244  }
245
246  @NullableDecl
247  K getInverse(@NullableDecl Object value) {
248    int entry = findEntryByValue(value);
249    return (entry == ABSENT) ? null : keys[entry];
250  }
251
252  @Override
253  @CanIgnoreReturnValue
254  public V put(@NullableDecl K key, @NullableDecl V value) {
255    return put(key, value, false);
256  }
257
258  @Override
259  @NullableDecl
260  @CanIgnoreReturnValue
261  public V forcePut(@NullableDecl K key, @NullableDecl V value) {
262    return put(key, value, true);
263  }
264
265  @NullableDecl
266  V put(@NullableDecl K key, @NullableDecl V value, boolean force) {
267    int keyHash = Hashing.smearedHash(key);
268    int entryForKey = findEntryByKey(key, keyHash);
269    if (entryForKey != ABSENT) {
270      V oldValue = values[entryForKey];
271      if (Objects.equal(oldValue, value)) {
272        return value;
273      } else {
274        replaceValueInEntry(entryForKey, value, force);
275        return oldValue;
276      }
277    }
278
279    int valueHash = Hashing.smearedHash(value);
280    int valueEntry = findEntryByValue(value, valueHash);
281    if (force) {
282      if (valueEntry != ABSENT) {
283        removeEntryValueHashKnown(valueEntry, valueHash);
284      }
285    } else {
286      checkArgument(valueEntry == ABSENT, "Value already present: %s", value);
287    }
288
289    ensureCapacity(size + 1);
290    keys[size] = key;
291    values[size] = value;
292
293    insertIntoTableKToV(size, keyHash);
294    insertIntoTableVToK(size, valueHash);
295
296    setSucceeds(lastInInsertionOrder, size);
297    setSucceeds(size, ENDPOINT);
298    size++;
299    modCount++;
300    return null;
301  }
302
303  @NullableDecl
304  K putInverse(@NullableDecl V value, @NullableDecl K key, boolean force) {
305    int valueHash = Hashing.smearedHash(value);
306    int entryForValue = findEntryByValue(value, valueHash);
307    if (entryForValue != ABSENT) {
308      K oldKey = keys[entryForValue];
309      if (Objects.equal(oldKey, key)) {
310        return key;
311      } else {
312        replaceKeyInEntry(entryForValue, key, force);
313        return oldKey;
314      }
315    }
316
317    int predecessor = lastInInsertionOrder;
318    int keyHash = Hashing.smearedHash(key);
319    int keyEntry = findEntryByKey(key, keyHash);
320    if (force) {
321      if (keyEntry != ABSENT) {
322        predecessor = prevInInsertionOrder[keyEntry];
323        removeEntryKeyHashKnown(keyEntry, keyHash);
324      }
325    } else {
326      checkArgument(keyEntry == ABSENT, "Key already present: %s", key);
327    }
328
329    // insertion point for new entry is after predecessor
330    // note predecessor must still be a valid entry: either we deleted an entry that was *not*
331    // predecessor, or we didn't delete anything
332
333    ensureCapacity(size + 1);
334    keys[size] = key;
335    values[size] = value;
336
337    insertIntoTableKToV(size, keyHash);
338    insertIntoTableVToK(size, valueHash);
339
340    int successor =
341        (predecessor == ENDPOINT) ? firstInInsertionOrder : nextInInsertionOrder[predecessor];
342    setSucceeds(predecessor, size);
343    setSucceeds(size, successor);
344    size++;
345    modCount++;
346    return null;
347  }
348
349  /**
350   * Updates the pointers of the insertion order linked list so that {@code next} follows {@code
351   * prev}. {@code ENDPOINT} represents either the first or last entry in the entire map (as
352   * appropriate).
353   */
354  private void setSucceeds(int prev, int next) {
355    if (prev == ENDPOINT) {
356      firstInInsertionOrder = next;
357    } else {
358      nextInInsertionOrder[prev] = next;
359    }
360    if (next == ENDPOINT) {
361      lastInInsertionOrder = prev;
362    } else {
363      prevInInsertionOrder[next] = prev;
364    }
365  }
366
367  /**
368   * Updates the K-to-V hash table to include the entry at the specified index, which is assumed to
369   * have not yet been added.
370   */
371  private void insertIntoTableKToV(int entry, int keyHash) {
372    checkArgument(entry != ABSENT);
373    int keyBucket = bucket(keyHash);
374    nextInBucketKToV[entry] = hashTableKToV[keyBucket];
375    hashTableKToV[keyBucket] = entry;
376  }
377
378  /**
379   * Updates the V-to-K hash table to include the entry at the specified index, which is assumed to
380   * have not yet been added.
381   */
382  private void insertIntoTableVToK(int entry, int valueHash) {
383    checkArgument(entry != ABSENT);
384    int valueBucket = bucket(valueHash);
385    nextInBucketVToK[entry] = hashTableVToK[valueBucket];
386    hashTableVToK[valueBucket] = entry;
387  }
388
389  /**
390   * Updates the K-to-V hash table to remove the entry at the specified index, which is assumed to
391   * be present. Does not update any other data structures.
392   */
393  private void deleteFromTableKToV(int entry, int keyHash) {
394    checkArgument(entry != ABSENT);
395    int keyBucket = bucket(keyHash);
396
397    if (hashTableKToV[keyBucket] == entry) {
398      hashTableKToV[keyBucket] = nextInBucketKToV[entry];
399      nextInBucketKToV[entry] = ABSENT;
400      return;
401    }
402
403    int prevInBucket = hashTableKToV[keyBucket];
404    for (int entryInBucket = nextInBucketKToV[prevInBucket];
405        entryInBucket != ABSENT;
406        entryInBucket = nextInBucketKToV[entryInBucket]) {
407      if (entryInBucket == entry) {
408        nextInBucketKToV[prevInBucket] = nextInBucketKToV[entry];
409        nextInBucketKToV[entry] = ABSENT;
410        return;
411      }
412      prevInBucket = entryInBucket;
413    }
414    throw new AssertionError("Expected to find entry with key " + keys[entry]);
415  }
416
417  /**
418   * Updates the V-to-K hash table to remove the entry at the specified index, which is assumed to
419   * be present. Does not update any other data structures.
420   */
421  private void deleteFromTableVToK(int entry, int valueHash) {
422    checkArgument(entry != ABSENT);
423    int valueBucket = bucket(valueHash);
424
425    if (hashTableVToK[valueBucket] == entry) {
426      hashTableVToK[valueBucket] = nextInBucketVToK[entry];
427      nextInBucketVToK[entry] = ABSENT;
428      return;
429    }
430
431    int prevInBucket = hashTableVToK[valueBucket];
432    for (int entryInBucket = nextInBucketVToK[prevInBucket];
433        entryInBucket != ABSENT;
434        entryInBucket = nextInBucketVToK[entryInBucket]) {
435      if (entryInBucket == entry) {
436        nextInBucketVToK[prevInBucket] = nextInBucketVToK[entry];
437        nextInBucketVToK[entry] = ABSENT;
438        return;
439      }
440      prevInBucket = entryInBucket;
441    }
442    throw new AssertionError("Expected to find entry with value " + values[entry]);
443  }
444
445  /**
446   * Updates the specified entry to point to the new value: removes the old value from the V-to-K
447   * mapping and puts the new one in. The entry does not move in the insertion order of the bimap.
448   */
449  private void replaceValueInEntry(int entry, @NullableDecl V newValue, boolean force) {
450    checkArgument(entry != ABSENT);
451    int newValueHash = Hashing.smearedHash(newValue);
452    int newValueIndex = findEntryByValue(newValue, newValueHash);
453    if (newValueIndex != ABSENT) {
454      if (force) {
455        removeEntryValueHashKnown(newValueIndex, newValueHash);
456        if (entry == size) { // this entry got moved to newValueIndex
457          entry = newValueIndex;
458        }
459      } else {
460        throw new IllegalArgumentException("Value already present in map: " + newValue);
461      }
462    }
463    // we do *not* update insertion order, and it isn't a structural modification!
464    deleteFromTableVToK(entry, Hashing.smearedHash(values[entry]));
465    values[entry] = newValue;
466    insertIntoTableVToK(entry, newValueHash);
467  }
468
469  /**
470   * Updates the specified entry to point to the new value: removes the old value from the V-to-K
471   * mapping and puts the new one in. The entry is moved to the end of the insertion order, or to
472   * the position of the new key if it was previously present.
473   */
474  private void replaceKeyInEntry(int entry, @NullableDecl K newKey, boolean force) {
475    checkArgument(entry != ABSENT);
476    int newKeyHash = Hashing.smearedHash(newKey);
477    int newKeyIndex = findEntryByKey(newKey, newKeyHash);
478
479    int newPredecessor = lastInInsertionOrder;
480    int newSuccessor = ENDPOINT;
481    if (newKeyIndex != ABSENT) {
482      if (force) {
483        newPredecessor = prevInInsertionOrder[newKeyIndex];
484        newSuccessor = nextInInsertionOrder[newKeyIndex];
485        removeEntryKeyHashKnown(newKeyIndex, newKeyHash);
486        if (entry == size) { // this entry got moved to newKeyIndex
487          entry = newKeyIndex;
488        }
489      } else {
490        throw new IllegalArgumentException("Key already present in map: " + newKey);
491      }
492    }
493    if (newPredecessor == entry) {
494      newPredecessor = prevInInsertionOrder[entry];
495    } else if (newPredecessor == size) {
496      newPredecessor = newKeyIndex;
497    }
498
499    if (newSuccessor == entry) {
500      newSuccessor = nextInInsertionOrder[entry];
501    } else if (newSuccessor == size) {
502      newSuccessor = newKeyIndex;
503    }
504
505    int oldPredecessor = prevInInsertionOrder[entry];
506    int oldSuccessor = nextInInsertionOrder[entry];
507    setSucceeds(oldPredecessor, oldSuccessor); // remove from insertion order linked list
508
509    deleteFromTableKToV(entry, Hashing.smearedHash(keys[entry]));
510    keys[entry] = newKey;
511    insertIntoTableKToV(entry, Hashing.smearedHash(newKey));
512
513    // insert into insertion order linked list, usually at the end
514    setSucceeds(newPredecessor, entry);
515    setSucceeds(entry, newSuccessor);
516  }
517
518  @Override
519  @NullableDecl
520  @CanIgnoreReturnValue
521  public V remove(@NullableDecl Object key) {
522    int keyHash = Hashing.smearedHash(key);
523    int entry = findEntryByKey(key, keyHash);
524    if (entry == ABSENT) {
525      return null;
526    } else {
527      @NullableDecl V value = values[entry];
528      removeEntryKeyHashKnown(entry, keyHash);
529      return value;
530    }
531  }
532
533  @NullableDecl
534  K removeInverse(@NullableDecl Object value) {
535    int valueHash = Hashing.smearedHash(value);
536    int entry = findEntryByValue(value, valueHash);
537    if (entry == ABSENT) {
538      return null;
539    } else {
540      @NullableDecl K key = keys[entry];
541      removeEntryValueHashKnown(entry, valueHash);
542      return key;
543    }
544  }
545
546  /** Removes the entry at the specified index with no additional data. */
547  void removeEntry(int entry) {
548    removeEntryKeyHashKnown(entry, Hashing.smearedHash(keys[entry]));
549  }
550
551  /** Removes the entry at the specified index, given the hash of its key. */
552  void removeEntryKeyHashKnown(int entry, int keyHash) {
553    removeEntry(entry, keyHash, Hashing.smearedHash(values[entry]));
554  }
555
556  /** Removes the entry at the specified index, given the hash of its value. */
557  void removeEntryValueHashKnown(int entry, int valueHash) {
558    removeEntry(entry, Hashing.smearedHash(keys[entry]), valueHash);
559  }
560
561  /** Removes the entry at the specified index, given the hash of its key and value. */
562  private void removeEntry(int entry, int keyHash, int valueHash) {
563    checkArgument(entry != ABSENT);
564    deleteFromTableKToV(entry, keyHash);
565    deleteFromTableVToK(entry, valueHash);
566
567    int oldPredecessor = prevInInsertionOrder[entry];
568    int oldSuccessor = nextInInsertionOrder[entry];
569    setSucceeds(oldPredecessor, oldSuccessor);
570
571    moveEntryToIndex(size - 1, entry);
572    keys[size - 1] = null;
573    values[size - 1] = null;
574    size--;
575    modCount++;
576  }
577
578  /**
579   * Moves the entry previously positioned at {@code src} to {@code dest}. Assumes the entry
580   * previously at {@code src} has already been removed from the data structures.
581   */
582  private void moveEntryToIndex(int src, int dest) {
583    if (src == dest) {
584      return;
585    }
586    int predecessor = prevInInsertionOrder[src];
587    int successor = nextInInsertionOrder[src];
588    setSucceeds(predecessor, dest);
589    setSucceeds(dest, successor);
590
591    K key = keys[src];
592    V value = values[src];
593
594    keys[dest] = key;
595    values[dest] = value;
596
597    // update pointers in hashTableKToV
598    int keyHash = Hashing.smearedHash(key);
599    int keyBucket = bucket(keyHash);
600    if (hashTableKToV[keyBucket] == src) {
601      hashTableKToV[keyBucket] = dest;
602    } else {
603      int prevInBucket = hashTableKToV[keyBucket];
604      for (int entryInBucket = nextInBucketKToV[prevInBucket];
605          /* should never reach end */ ;
606          entryInBucket = nextInBucketKToV[entryInBucket]) {
607        if (entryInBucket == src) {
608          nextInBucketKToV[prevInBucket] = dest;
609          break;
610        }
611        prevInBucket = entryInBucket;
612      }
613    }
614    nextInBucketKToV[dest] = nextInBucketKToV[src];
615    nextInBucketKToV[src] = ABSENT;
616
617    // update pointers in hashTableVToK
618    int valueHash = Hashing.smearedHash(value);
619    int valueBucket = bucket(valueHash);
620    if (hashTableVToK[valueBucket] == src) {
621      hashTableVToK[valueBucket] = dest;
622    } else {
623      int prevInBucket = hashTableVToK[valueBucket];
624      for (int entryInBucket = nextInBucketVToK[prevInBucket];
625          /* should never reach end*/ ;
626          entryInBucket = nextInBucketVToK[entryInBucket]) {
627        if (entryInBucket == src) {
628          nextInBucketVToK[prevInBucket] = dest;
629          break;
630        }
631        prevInBucket = entryInBucket;
632      }
633    }
634    nextInBucketVToK[dest] = nextInBucketVToK[src];
635    nextInBucketVToK[src] = ABSENT;
636  }
637
638  @Override
639  public void clear() {
640    Arrays.fill(keys, 0, size, null);
641    Arrays.fill(values, 0, size, null);
642    Arrays.fill(hashTableKToV, ABSENT);
643    Arrays.fill(hashTableVToK, ABSENT);
644    Arrays.fill(nextInBucketKToV, 0, size, ABSENT);
645    Arrays.fill(nextInBucketVToK, 0, size, ABSENT);
646    Arrays.fill(prevInInsertionOrder, 0, size, ABSENT);
647    Arrays.fill(nextInInsertionOrder, 0, size, ABSENT);
648    size = 0;
649    firstInInsertionOrder = ENDPOINT;
650    lastInInsertionOrder = ENDPOINT;
651    modCount++;
652  }
653
654  /** Shared supertype of keySet, values, entrySet, and inverse.entrySet. */
655  abstract class View<T> extends AbstractSet<T> {
656    abstract T forEntry(int entry);
657
658    @Override
659    public Iterator<T> iterator() {
660      return new Iterator<T>() {
661        private int index = firstInInsertionOrder;
662        private int indexToRemove = ABSENT;
663        private int expectedModCount = modCount;
664
665        // Calls to setValue on inverse entries can move already-visited entries to the end.
666        // Make sure we don't visit those.
667        private int remaining = size;
668
669        private void checkForComodification() {
670          if (modCount != expectedModCount) {
671            throw new ConcurrentModificationException();
672          }
673        }
674
675        @Override
676        public boolean hasNext() {
677          checkForComodification();
678          return index != ENDPOINT && remaining > 0;
679        }
680
681        @Override
682        public T next() {
683          if (!hasNext()) {
684            throw new NoSuchElementException();
685          }
686          T result = forEntry(index);
687          indexToRemove = index;
688          index = nextInInsertionOrder[index];
689          remaining--;
690          return result;
691        }
692
693        @Override
694        public void remove() {
695          checkForComodification();
696          CollectPreconditions.checkRemove(indexToRemove != ABSENT);
697          removeEntry(indexToRemove);
698          if (index == size) {
699            index = indexToRemove;
700          }
701          indexToRemove = ABSENT;
702          expectedModCount = modCount;
703        }
704      };
705    }
706
707    @Override
708    public int size() {
709      return size;
710    }
711
712    @Override
713    public void clear() {
714      HashBiMap.this.clear();
715    }
716  }
717
718  private transient Set<K> keySet;
719
720  @Override
721  public Set<K> keySet() {
722    Set<K> result = keySet;
723    return (result == null) ? keySet = new KeySet() : result;
724  }
725
726  final class KeySet extends View<K> {
727    @Override
728    K forEntry(int entry) {
729      return keys[entry];
730    }
731
732    @Override
733    public boolean contains(@NullableDecl Object o) {
734      return HashBiMap.this.containsKey(o);
735    }
736
737    @Override
738    public boolean remove(@NullableDecl Object o) {
739      int oHash = Hashing.smearedHash(o);
740      int entry = findEntryByKey(o, oHash);
741      if (entry != ABSENT) {
742        removeEntryKeyHashKnown(entry, oHash);
743        return true;
744      } else {
745        return false;
746      }
747    }
748  }
749
750  private transient Set<V> valueSet;
751
752  @Override
753  public Set<V> values() {
754    Set<V> result = valueSet;
755    return (result == null) ? valueSet = new ValueSet() : result;
756  }
757
758  final class ValueSet extends View<V> {
759    @Override
760    V forEntry(int entry) {
761      return values[entry];
762    }
763
764    @Override
765    public boolean contains(@NullableDecl Object o) {
766      return HashBiMap.this.containsValue(o);
767    }
768
769    @Override
770    public boolean remove(@NullableDecl Object o) {
771      int oHash = Hashing.smearedHash(o);
772      int entry = findEntryByValue(o, oHash);
773      if (entry != ABSENT) {
774        removeEntryValueHashKnown(entry, oHash);
775        return true;
776      } else {
777        return false;
778      }
779    }
780  }
781
782  private transient Set<Entry<K, V>> entrySet;
783
784  @Override
785  public Set<Entry<K, V>> entrySet() {
786    Set<Entry<K, V>> result = entrySet;
787    return (result == null) ? entrySet = new EntrySet() : result;
788  }
789
790  final class EntrySet extends View<Entry<K, V>> {
791    @Override
792    public boolean contains(@NullableDecl Object o) {
793      if (o instanceof Entry) {
794        Entry<?, ?> e = (Entry<?, ?>) o;
795        @NullableDecl Object k = e.getKey();
796        @NullableDecl Object v = e.getValue();
797        int eIndex = findEntryByKey(k);
798        return eIndex != ABSENT && Objects.equal(v, values[eIndex]);
799      }
800      return false;
801    }
802
803    @Override
804    @CanIgnoreReturnValue
805    public boolean remove(@NullableDecl Object o) {
806      if (o instanceof Entry) {
807        Entry<?, ?> e = (Entry<?, ?>) o;
808        @NullableDecl Object k = e.getKey();
809        @NullableDecl Object v = e.getValue();
810        int kHash = Hashing.smearedHash(k);
811        int eIndex = findEntryByKey(k, kHash);
812        if (eIndex != ABSENT && Objects.equal(v, values[eIndex])) {
813          removeEntryKeyHashKnown(eIndex, kHash);
814          return true;
815        }
816      }
817      return false;
818    }
819
820    @Override
821    Entry<K, V> forEntry(int entry) {
822      return new EntryForKey(entry);
823    }
824  }
825
826  /**
827   * An {@code Entry} implementation that attempts to follow its key around the map -- that is, if
828   * the key is moved, deleted, or reinserted, it will account for that -- while not doing any extra
829   * work if the key has not moved.
830   */
831  final class EntryForKey extends AbstractMapEntry<K, V> {
832    @NullableDecl final K key;
833    int index;
834
835    EntryForKey(int index) {
836      this.key = keys[index];
837      this.index = index;
838    }
839
840    void updateIndex() {
841      if (index == ABSENT || index > size || !Objects.equal(keys[index], key)) {
842        index = findEntryByKey(key);
843      }
844    }
845
846    @Override
847    public K getKey() {
848      return key;
849    }
850
851    @Override
852    @NullableDecl
853    public V getValue() {
854      updateIndex();
855      return (index == ABSENT) ? null : values[index];
856    }
857
858    @Override
859    public V setValue(V value) {
860      updateIndex();
861      if (index == ABSENT) {
862        return HashBiMap.this.put(key, value);
863      }
864      V oldValue = values[index];
865      if (Objects.equal(oldValue, value)) {
866        return value;
867      }
868      replaceValueInEntry(index, value, false);
869      return oldValue;
870    }
871  }
872
873  @RetainedWith private transient BiMap<V, K> inverse;
874
875  @Override
876  public BiMap<V, K> inverse() {
877    BiMap<V, K> result = inverse;
878    return (result == null) ? inverse = new Inverse<K, V>(this) : result;
879  }
880
881  static class Inverse<K, V> extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
882    private final HashBiMap<K, V> forward;
883
884    Inverse(HashBiMap<K, V> forward) {
885      this.forward = forward;
886    }
887
888    @Override
889    public int size() {
890      return forward.size;
891    }
892
893    @Override
894    public boolean containsKey(@NullableDecl Object key) {
895      return forward.containsValue(key);
896    }
897
898    @Override
899    @NullableDecl
900    public K get(@NullableDecl Object key) {
901      return forward.getInverse(key);
902    }
903
904    @Override
905    public boolean containsValue(@NullableDecl Object value) {
906      return forward.containsKey(value);
907    }
908
909    @Override
910    @NullableDecl
911    @CanIgnoreReturnValue
912    public K put(@NullableDecl V value, @NullableDecl K key) {
913      return forward.putInverse(value, key, false);
914    }
915
916    @Override
917    @NullableDecl
918    @CanIgnoreReturnValue
919    public K forcePut(@NullableDecl V value, @NullableDecl K key) {
920      return forward.putInverse(value, key, true);
921    }
922
923    @Override
924    public BiMap<K, V> inverse() {
925      return forward;
926    }
927
928    @Override
929    @NullableDecl
930    @CanIgnoreReturnValue
931    public K remove(@NullableDecl Object value) {
932      return forward.removeInverse(value);
933    }
934
935    @Override
936    public void clear() {
937      forward.clear();
938    }
939
940    @Override
941    public Set<V> keySet() {
942      return forward.values();
943    }
944
945    @Override
946    public Set<K> values() {
947      return forward.keySet();
948    }
949
950    private transient Set<Entry<V, K>> inverseEntrySet;
951
952    @Override
953    public Set<Entry<V, K>> entrySet() {
954      Set<Entry<V, K>> result = inverseEntrySet;
955      return (result == null) ? inverseEntrySet = forward.new InverseEntrySet() : result;
956    }
957
958    @GwtIncompatible("serialization")
959    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
960      in.defaultReadObject();
961      this.forward.inverse = this;
962    }
963  }
964
965  class InverseEntrySet extends View<Entry<V, K>> {
966    @Override
967    public boolean contains(@NullableDecl Object o) {
968      if (o instanceof Entry) {
969        Entry<?, ?> e = (Entry<?, ?>) o;
970        Object v = e.getKey();
971        Object k = e.getValue();
972        int eIndex = findEntryByValue(v);
973        return eIndex != ABSENT && Objects.equal(keys[eIndex], k);
974      }
975      return false;
976    }
977
978    @Override
979    public boolean remove(Object o) {
980      if (o instanceof Entry) {
981        Entry<?, ?> e = (Entry<?, ?>) o;
982        Object v = e.getKey();
983        Object k = e.getValue();
984        int vHash = Hashing.smearedHash(v);
985        int eIndex = findEntryByValue(v, vHash);
986        if (eIndex != ABSENT && Objects.equal(keys[eIndex], k)) {
987          removeEntryValueHashKnown(eIndex, vHash);
988          return true;
989        }
990      }
991      return false;
992    }
993
994    @Override
995    Entry<V, K> forEntry(int entry) {
996      return new EntryForValue(entry);
997    }
998  }
999
1000  /**
1001   * An {@code Entry} implementation that attempts to follow its value around the map -- that is, if
1002   * the value is moved, deleted, or reinserted, it will account for that -- while not doing any
1003   * extra work if the value has not moved.
1004   */
1005  final class EntryForValue extends AbstractMapEntry<V, K> {
1006    final V value;
1007    int index;
1008
1009    EntryForValue(int index) {
1010      this.value = values[index];
1011      this.index = index;
1012    }
1013
1014    private void updateIndex() {
1015      if (index == ABSENT || index > size || !Objects.equal(value, values[index])) {
1016        index = findEntryByValue(value);
1017      }
1018    }
1019
1020    @Override
1021    public V getKey() {
1022      return value;
1023    }
1024
1025    @Override
1026    public K getValue() {
1027      updateIndex();
1028      return (index == ABSENT) ? null : keys[index];
1029    }
1030
1031    @Override
1032    public K setValue(K key) {
1033      updateIndex();
1034      if (index == ABSENT) {
1035        return HashBiMap.this.putInverse(value, key, false);
1036      }
1037      K oldKey = keys[index];
1038      if (Objects.equal(oldKey, key)) {
1039        return key;
1040      }
1041      replaceKeyInEntry(index, key, false);
1042      return oldKey;
1043    }
1044  }
1045
1046  /**
1047   * @serialData the number of entries, first key, first value, second key, second value, and so on.
1048   */
1049  @GwtIncompatible // java.io.ObjectOutputStream
1050  private void writeObject(ObjectOutputStream stream) throws IOException {
1051    stream.defaultWriteObject();
1052    Serialization.writeMap(this, stream);
1053  }
1054
1055  @GwtIncompatible // java.io.ObjectInputStream
1056  private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
1057    stream.defaultReadObject();
1058    int size = Serialization.readCount(stream);
1059    init(16); // resist hostile attempts to allocate gratuitous heap
1060    Serialization.populateMap(this, stream, size);
1061  }
1062}