11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2008 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.collect;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkArgument;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtCompatible;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.ImmutableSet.ArrayImmutableSet;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.ImmutableSet.TransformedImmutableSet;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.Nullable;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.concurrent.Immutable;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Implementation of {@link ImmutableMap} with two or more entries.
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Jesse Wilson
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kevin Bourrillion
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Gregory Kick
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@GwtCompatible(serializable = true, emulated = true)
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertfinal class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // entries in insertion order
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final transient LinkedEntry<K, V>[] entries;
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // array of linked lists of entries
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final transient LinkedEntry<K, V>[] table;
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // 'and' with an int to get a table index
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final transient int mask;
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final transient int keySetHashCode;
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // TODO(gak): investigate avoiding the creation of ImmutableEntries since we
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // re-copy them anyway.
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  RegularImmutableMap(Entry<?, ?>... immutableEntries) {
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int size = immutableEntries.length;
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entries = createEntryArray(size);
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int tableSize = chooseTableSize(size);
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table = createEntryArray(tableSize);
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    mask = tableSize - 1;
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int keySetHashCodeMutable = 0;
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int entryIndex = 0; entryIndex < size; entryIndex++) {
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // each of our 6 callers carefully put only Entry<K, V>s into the array!
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @SuppressWarnings("unchecked")
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Entry<K, V> entry = (Entry<K, V>) immutableEntries[entryIndex];
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      K key = entry.getKey();
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int keyHashCode = key.hashCode();
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      keySetHashCodeMutable += keyHashCode;
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int tableIndex = Hashing.smear(keyHashCode) & mask;
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Nullable LinkedEntry<K, V> existing = table[tableIndex];
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // prepend, not append, so the entries can be immutable
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LinkedEntry<K, V> linkedEntry =
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          newLinkedEntry(key, entry.getValue(), existing);
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      table[tableIndex] = linkedEntry;
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entries[entryIndex] = linkedEntry;
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (existing != null) {
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        checkArgument(!key.equals(existing.getKey()), "duplicate key: %s", key);
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        existing = existing.next();
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    keySetHashCode = keySetHashCodeMutable;
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static int chooseTableSize(int size) {
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // least power of 2 greater than size
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int tableSize = Integer.highestOneBit(size) << 1;
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkArgument(tableSize > 0, "table too large: %s", size);
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return tableSize;
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Creates a {@link LinkedEntry} array to hold parameterized entries. The
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * result must never be upcast back to LinkedEntry[] (or Object[], etc.), or
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * allowed to escape the class.
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked") // Safe as long as the javadocs are followed
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private LinkedEntry<K, V>[] createEntryArray(int size) {
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new LinkedEntry[size];
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static <K, V> LinkedEntry<K, V> newLinkedEntry(K key, V value,
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Nullable LinkedEntry<K, V> next) {
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (next == null)
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ? new TerminalEntry<K, V>(key, value)
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        : new NonTerminalEntry<K, V>(key, value, next);
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private interface LinkedEntry<K, V> extends Entry<K, V> {
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /** Returns the next entry in the list or {@code null} if none exists. */
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Nullable LinkedEntry<K, V> next();
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /** {@code LinkedEntry} implementation that has a next value. */
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Immutable
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("serial") // this class is never serialized
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class NonTerminalEntry<K, V>
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      extends ImmutableEntry<K, V> implements LinkedEntry<K, V> {
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final LinkedEntry<K, V> next;
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    NonTerminalEntry(K key, V value, LinkedEntry<K, V> next) {
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(key, value);
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.next = next;
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public LinkedEntry<K, V> next() {
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return next;
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * {@code LinkedEntry} implementation that serves as the last entry in the
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * list.  I.e. no next entry
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Immutable
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("serial") // this class is never serialized
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class TerminalEntry<K, V> extends ImmutableEntry<K, V>
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      implements LinkedEntry<K, V> {
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TerminalEntry(K key, V value) {
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(key, value);
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Nullable @Override public LinkedEntry<K, V> next() {
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public V get(@Nullable Object key) {
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (key == null) {
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = Hashing.smear(key.hashCode()) & mask;
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (LinkedEntry<K, V> entry = table[index];
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        entry != null;
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        entry = entry.next()) {
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      K candidateKey = entry.getKey();
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      /*
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       * Assume that equals uses the == optimization when appropriate, and that
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       * it would check hash codes as an optimization when appropriate. If we
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       * did these things, it would just make things worse for the most
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       * performance-conscious users.
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert       */
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (key.equals(candidateKey)) {
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return entry.getValue();
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return null;
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public int size() {
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return entries.length;
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public boolean isEmpty() {
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return false;
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public boolean containsValue(@Nullable Object value) {
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (value == null) {
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (Entry<K, V> entry : entries) {
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (entry.getValue().equals(value)) {
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return true;
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return false;
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override boolean isPartialView() {
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return false;
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private transient ImmutableSet<Entry<K, V>> entrySet;
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public ImmutableSet<Entry<K, V>> entrySet() {
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ImmutableSet<Entry<K, V>> es = entrySet;
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (es == null) ? (entrySet = new EntrySet<K, V>(this)) : es;
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("serial") // uses writeReplace(), not default serialization
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class EntrySet<K, V> extends ArrayImmutableSet<Entry<K, V>> {
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final transient RegularImmutableMap<K, V> map;
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    EntrySet(RegularImmutableMap<K, V> map) {
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(map.entries);
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.map = map;
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public boolean contains(Object target) {
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (target instanceof Entry) {
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Entry<?, ?> entry = (Entry<?, ?>) target;
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        V mappedValue = map.get(entry.getKey());
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return mappedValue != null && mappedValue.equals(entry.getValue());
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private transient ImmutableSet<K> keySet;
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public ImmutableSet<K> keySet() {
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ImmutableSet<K> ks = keySet;
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (ks == null) ? (keySet = new KeySet<K, V>(this)) : ks;
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("serial") // uses writeReplace(), not default serialization
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class KeySet<K, V>
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      extends TransformedImmutableSet<Entry<K, V>, K> {
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final RegularImmutableMap<K, V> map;
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    KeySet(RegularImmutableMap<K, V> map) {
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(map.entries, map.keySetHashCode);
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.map = map;
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override K transform(Entry<K, V> element) {
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return element.getKey();
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public boolean contains(Object target) {
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return map.containsKey(target);
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean isPartialView() {
2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return true;
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private transient ImmutableCollection<V> values;
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public ImmutableCollection<V> values() {
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ImmutableCollection<V> v = values;
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (v == null) ? (values = new Values<V>(this)) : v;
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("serial") // uses writeReplace(), not default serialization
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class Values<V> extends ImmutableCollection<V> {
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final RegularImmutableMap<?, V> map;
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Values(RegularImmutableMap<?, V> map) {
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.map = map;
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int size() {
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return map.entries.length;
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public UnmodifiableIterator<V> iterator() {
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return new AbstractIndexedListIterator<V>(map.entries.length) {
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override protected V get(int index) {
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return map.entries[index].getValue();
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public boolean contains(Object target) {
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return map.containsValue(target);
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override boolean isPartialView() {
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return true;
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override public String toString() {
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    StringBuilder result
2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        = Collections2.newStringBuilderForCollection(size()).append('{');
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Collections2.STANDARD_JOINER.appendTo(result, entries);
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return result.append('}').toString();
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // This class is never actually serialized directly, but we have to make the
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // warning go away (and suppressing would suppress for all nested classes too)
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final long serialVersionUID = 0;
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
294