001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.base.Preconditions.checkState;
021import static com.google.common.collect.CollectPreconditions.checkEntryNotNull;
022import static com.google.common.collect.CollectPreconditions.checkNonnegative;
023
024import com.google.common.annotations.Beta;
025import com.google.common.annotations.GwtCompatible;
026import com.google.errorprone.annotations.CanIgnoreReturnValue;
027import com.google.errorprone.annotations.concurrent.LazyInit;
028import com.google.j2objc.annotations.WeakOuter;
029import java.io.Serializable;
030import java.util.AbstractMap;
031import java.util.Arrays;
032import java.util.Collection;
033import java.util.Collections;
034import java.util.Comparator;
035import java.util.EnumMap;
036import java.util.Iterator;
037import java.util.LinkedHashMap;
038import java.util.Map;
039import java.util.Map.Entry;
040import java.util.SortedMap;
041import java.util.Spliterator;
042import java.util.Spliterators;
043import java.util.function.BiFunction;
044import java.util.function.BinaryOperator;
045import java.util.function.Function;
046import java.util.stream.Collector;
047import java.util.stream.Collectors;
048import org.checkerframework.checker.nullness.compatqual.NullableDecl;
049
050/**
051 * A {@link Map} whose contents will never change, with many other important properties detailed at
052 * {@link ImmutableCollection}.
053 *
054 * <p>See the Guava User Guide article on <a href=
055 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>.
056 *
057 * @author Jesse Wilson
058 * @author Kevin Bourrillion
059 * @since 2.0
060 */
061@GwtCompatible(serializable = true, emulated = true)
062@SuppressWarnings("serial") // we're overriding default serialization
063public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
064
065  /**
066   * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys
067   * and values are the result of applying the provided mapping functions to the input elements.
068   * Entries appear in the result {@code ImmutableMap} in encounter order.
069   *
070   * <p>If the mapped keys contain duplicates (according to {@link Object#equals(Object)}, an {@code
071   * IllegalArgumentException} is thrown when the collection operation is performed. (This differs
072   * from the {@code Collector} returned by {@link Collectors#toMap(Function, Function)}, which
073   * throws an {@code IllegalStateException}.)
074   *
075   * @since 21.0
076   */
077  @Beta
078  public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
079      Function<? super T, ? extends K> keyFunction,
080      Function<? super T, ? extends V> valueFunction) {
081    return CollectCollectors.toImmutableMap(keyFunction, valueFunction);
082  }
083
084  /**
085   * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys
086   * and values are the result of applying the provided mapping functions to the input elements.
087   *
088   * <p>If the mapped keys contain duplicates (according to {@link Object#equals(Object)}), the
089   * values are merged using the specified merging function. Entries will appear in the encounter
090   * order of the first occurrence of the key.
091   *
092   * @since 21.0
093   */
094  @Beta
095  public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
096      Function<? super T, ? extends K> keyFunction,
097      Function<? super T, ? extends V> valueFunction,
098      BinaryOperator<V> mergeFunction) {
099    checkNotNull(keyFunction);
100    checkNotNull(valueFunction);
101    checkNotNull(mergeFunction);
102    return Collectors.collectingAndThen(
103        Collectors.toMap(keyFunction, valueFunction, mergeFunction, LinkedHashMap::new),
104        ImmutableMap::copyOf);
105  }
106
107  /**
108   * Returns the empty map. This map behaves and performs comparably to {@link
109   * Collections#emptyMap}, and is preferable mainly for consistency and maintainability of your
110   * code.
111   */
112  @SuppressWarnings("unchecked")
113  public static <K, V> ImmutableMap<K, V> of() {
114    return (ImmutableMap<K, V>) RegularImmutableMap.EMPTY;
115  }
116
117  /**
118   * Returns an immutable map containing a single entry. This map behaves and performs comparably to
119   * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable
120   * mainly for consistency and maintainability of your code.
121   */
122  public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
123    return ImmutableBiMap.of(k1, v1);
124  }
125
126  /**
127   * Returns an immutable map containing the given entries, in order.
128   *
129   * @throws IllegalArgumentException if duplicate keys are provided
130   */
131  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
132    return RegularImmutableMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2));
133  }
134
135  /**
136   * Returns an immutable map containing the given entries, in order.
137   *
138   * @throws IllegalArgumentException if duplicate keys are provided
139   */
140  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
141    return RegularImmutableMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
142  }
143
144  /**
145   * Returns an immutable map containing the given entries, in order.
146   *
147   * @throws IllegalArgumentException if duplicate keys are provided
148   */
149  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
150    return RegularImmutableMap.fromEntries(
151        entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
152  }
153
154  /**
155   * Returns an immutable map containing the given entries, in order.
156   *
157   * @throws IllegalArgumentException if duplicate keys are provided
158   */
159  public static <K, V> ImmutableMap<K, V> of(
160      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
161    return RegularImmutableMap.fromEntries(
162        entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5));
163  }
164
165  // looking for of() with > 5 entries? Use the builder instead.
166
167  /**
168   * Verifies that {@code key} and {@code value} are non-null, and returns a new immutable entry
169   * with those values.
170   *
171   * <p>A call to {@link Entry#setValue} on the returned entry will always throw {@link
172   * UnsupportedOperationException}.
173   */
174  static <K, V> Entry<K, V> entryOf(K key, V value) {
175    checkEntryNotNull(key, value);
176    return new AbstractMap.SimpleImmutableEntry<>(key, value);
177  }
178
179  /**
180   * Returns a new builder. The generated builder is equivalent to the builder created by the {@link
181   * Builder} constructor.
182   */
183  public static <K, V> Builder<K, V> builder() {
184    return new Builder<>();
185  }
186
187  /**
188   * Returns a new builder, expecting the specified number of entries to be added.
189   *
190   * <p>If {@code expectedSize} is exactly the number of entries added to the builder before {@link
191   * Builder#build} is called, the builder is likely to perform better than an unsized {@link
192   * #builder()} would have.
193   *
194   * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to,
195   * but not exactly, the number of entries added to the builder.
196   *
197   * @since 23.1
198   */
199  @Beta
200  public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) {
201    checkNonnegative(expectedSize, "expectedSize");
202    return new Builder<>(expectedSize);
203  }
204
205  static void checkNoConflict(
206      boolean safe, String conflictDescription, Entry<?, ?> entry1, Entry<?, ?> entry2) {
207    if (!safe) {
208      throw new IllegalArgumentException(
209          "Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2);
210    }
211  }
212
213  /**
214   * A builder for creating immutable map instances, especially {@code public static final} maps
215   * ("constant maps"). Example:
216   *
217   * <pre>{@code
218   * static final ImmutableMap<String, Integer> WORD_TO_INT =
219   *     new ImmutableMap.Builder<String, Integer>()
220   *         .put("one", 1)
221   *         .put("two", 2)
222   *         .put("three", 3)
223   *         .build();
224   * }</pre>
225   *
226   * <p>For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are even more
227   * convenient.
228   *
229   * <p>By default, a {@code Builder} will generate maps that iterate over entries in the order they
230   * were inserted into the builder, equivalently to {@code LinkedHashMap}. For example, in the
231   * above example, {@code WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the
232   * order {@code "one"=1, "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect
233   * the same order. If you want a different order, consider using {@link ImmutableSortedMap} to
234   * sort by keys, or call {@link #orderEntriesByValue(Comparator)}, which changes this builder to
235   * sort entries by value.
236   *
237   * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build
238   * multiple maps in series. Each map is a superset of the maps created before it.
239   *
240   * @since 2.0
241   */
242  public static class Builder<K, V> {
243    Comparator<? super V> valueComparator;
244    Entry<K, V>[] entries;
245    int size;
246    boolean entriesUsed;
247
248    /**
249     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
250     * ImmutableMap#builder}.
251     */
252    public Builder() {
253      this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY);
254    }
255
256    @SuppressWarnings("unchecked")
257    Builder(int initialCapacity) {
258      this.entries = new Entry[initialCapacity];
259      this.size = 0;
260      this.entriesUsed = false;
261    }
262
263    private void ensureCapacity(int minCapacity) {
264      if (minCapacity > entries.length) {
265        entries =
266            Arrays.copyOf(
267                entries, ImmutableCollection.Builder.expandedCapacity(entries.length, minCapacity));
268        entriesUsed = false;
269      }
270    }
271
272    /**
273     * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed,
274     * and will cause {@link #build} to fail.
275     */
276    @CanIgnoreReturnValue
277    public Builder<K, V> put(K key, V value) {
278      ensureCapacity(size + 1);
279      Entry<K, V> entry = entryOf(key, value);
280      // don't inline this: we want to fail atomically if key or value is null
281      entries[size++] = entry;
282      return this;
283    }
284
285    /**
286     * Adds the given {@code entry} to the map, making it immutable if necessary. Duplicate keys are
287     * not allowed, and will cause {@link #build} to fail.
288     *
289     * @since 11.0
290     */
291    @CanIgnoreReturnValue
292    public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
293      return put(entry.getKey(), entry.getValue());
294    }
295
296    /**
297     * Associates all of the given map's keys and values in the built map. Duplicate keys are not
298     * allowed, and will cause {@link #build} to fail.
299     *
300     * @throws NullPointerException if any key or value in {@code map} is null
301     */
302    @CanIgnoreReturnValue
303    public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
304      return putAll(map.entrySet());
305    }
306
307    /**
308     * Adds all of the given entries to the built map. Duplicate keys are not allowed, and will
309     * cause {@link #build} to fail.
310     *
311     * @throws NullPointerException if any key, value, or entry is null
312     * @since 19.0
313     */
314    @CanIgnoreReturnValue
315    @Beta
316    public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) {
317      if (entries instanceof Collection) {
318        ensureCapacity(size + ((Collection<?>) entries).size());
319      }
320      for (Entry<? extends K, ? extends V> entry : entries) {
321        put(entry);
322      }
323      return this;
324    }
325
326    /**
327     * Configures this {@code Builder} to order entries by value according to the specified
328     * comparator.
329     *
330     * <p>The sort order is stable, that is, if two entries have values that compare as equivalent,
331     * the entry that was inserted first will be first in the built map's iteration order.
332     *
333     * @throws IllegalStateException if this method was already called
334     * @since 19.0
335     */
336    @CanIgnoreReturnValue
337    @Beta
338    public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) {
339      checkState(this.valueComparator == null, "valueComparator was already set");
340      this.valueComparator = checkNotNull(valueComparator, "valueComparator");
341      return this;
342    }
343
344    @CanIgnoreReturnValue
345    Builder<K, V> combine(Builder<K, V> other) {
346      checkNotNull(other);
347      ensureCapacity(this.size + other.size);
348      System.arraycopy(other.entries, 0, this.entries, this.size, other.size);
349      this.size += other.size;
350      return this;
351    }
352
353    /*
354     * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap
355     * versions throw an IllegalStateException instead?
356     */
357
358    /**
359     * Returns a newly-created immutable map. The iteration order of the returned map is the order
360     * in which entries were inserted into the builder, unless {@link #orderEntriesByValue} was
361     * called, in which case entries are sorted by value.
362     *
363     * @throws IllegalArgumentException if duplicate keys were added
364     */
365    public ImmutableMap<K, V> build() {
366      /*
367       * If entries is full, then this implementation may end up using the entries array
368       * directly and writing over the entry objects with non-terminal entries, but this is
369       * safe; if this Builder is used further, it will grow the entries array (so it can't
370       * affect the original array), and future build() calls will always copy any entry
371       * objects that cannot be safely reused.
372       */
373      if (valueComparator != null) {
374        if (entriesUsed) {
375          entries = Arrays.copyOf(entries, size);
376        }
377        Arrays.sort(
378            entries, 0, size, Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction()));
379      }
380      entriesUsed = size == entries.length;
381      switch (size) {
382        case 0:
383          return of();
384        case 1:
385          return of(entries[0].getKey(), entries[0].getValue());
386        default:
387          return RegularImmutableMap.fromEntryArray(size, entries);
388      }
389    }
390  }
391
392  /**
393   * Returns an immutable map containing the same entries as {@code map}. The returned map iterates
394   * over entries in the same order as the {@code entrySet} of the original map. If {@code map}
395   * somehow contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose
396   * comparator is not <i>consistent with equals</i>), the results of this method are undefined.
397   *
398   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
399   * safe to do so. The exact circumstances under which a copy will or will not be performed are
400   * undocumented and subject to change.
401   *
402   * @throws NullPointerException if any key or value in {@code map} is null
403   */
404  public static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V> map) {
405    if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) {
406      @SuppressWarnings("unchecked") // safe since map is not writable
407      ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
408      if (!kvMap.isPartialView()) {
409        return kvMap;
410      }
411    } else if (map instanceof EnumMap) {
412      @SuppressWarnings("unchecked") // safe since map is not writable
413      ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) copyOfEnumMap((EnumMap<?, ?>) map);
414      return kvMap;
415    }
416    return copyOf(map.entrySet());
417  }
418
419  /**
420   * Returns an immutable map containing the specified entries. The returned map iterates over
421   * entries in the same order as the original iterable.
422   *
423   * @throws NullPointerException if any key, value, or entry is null
424   * @throws IllegalArgumentException if two entries have the same key
425   * @since 19.0
426   */
427  @Beta
428  public static <K, V> ImmutableMap<K, V> copyOf(
429      Iterable<? extends Entry<? extends K, ? extends V>> entries) {
430    @SuppressWarnings("unchecked") // we'll only be using getKey and getValue, which are covariant
431    Entry<K, V>[] entryArray = (Entry<K, V>[]) Iterables.toArray(entries, EMPTY_ENTRY_ARRAY);
432    switch (entryArray.length) {
433      case 0:
434        return of();
435      case 1:
436        Entry<K, V> onlyEntry = entryArray[0];
437        return of(onlyEntry.getKey(), onlyEntry.getValue());
438      default:
439        /*
440         * The current implementation will end up using entryArray directly, though it will write
441         * over the (arbitrary, potentially mutable) Entry objects actually stored in entryArray.
442         */
443        return RegularImmutableMap.fromEntries(entryArray);
444    }
445  }
446
447  private static <K extends Enum<K>, V> ImmutableMap<K, V> copyOfEnumMap(
448      EnumMap<K, ? extends V> original) {
449    EnumMap<K, V> copy = new EnumMap<>(original);
450    for (Entry<?, ?> entry : copy.entrySet()) {
451      checkEntryNotNull(entry.getKey(), entry.getValue());
452    }
453    return ImmutableEnumMap.asImmutable(copy);
454  }
455
456  static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
457
458  abstract static class IteratorBasedImmutableMap<K, V> extends ImmutableMap<K, V> {
459    abstract UnmodifiableIterator<Entry<K, V>> entryIterator();
460
461    Spliterator<Entry<K, V>> entrySpliterator() {
462      return Spliterators.spliterator(
463          entryIterator(),
464          size(),
465          Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.IMMUTABLE | Spliterator.ORDERED);
466    }
467
468    @Override
469    ImmutableSet<K> createKeySet() {
470      return new ImmutableMapKeySet<>(this);
471    }
472
473    @Override
474    ImmutableSet<Entry<K, V>> createEntrySet() {
475      @WeakOuter
476      class EntrySetImpl extends ImmutableMapEntrySet<K, V> {
477        @Override
478        ImmutableMap<K, V> map() {
479          return IteratorBasedImmutableMap.this;
480        }
481
482        @Override
483        public UnmodifiableIterator<Entry<K, V>> iterator() {
484          return entryIterator();
485        }
486      }
487      return new EntrySetImpl();
488    }
489
490    @Override
491    ImmutableCollection<V> createValues() {
492      return new ImmutableMapValues<>(this);
493    }
494  }
495
496  ImmutableMap() {}
497
498  /**
499   * Guaranteed to throw an exception and leave the map unmodified.
500   *
501   * @throws UnsupportedOperationException always
502   * @deprecated Unsupported operation.
503   */
504  @CanIgnoreReturnValue
505  @Deprecated
506  @Override
507  public final V put(K k, V v) {
508    throw new UnsupportedOperationException();
509  }
510
511  /**
512   * Guaranteed to throw an exception and leave the map unmodified.
513   *
514   * @throws UnsupportedOperationException always
515   * @deprecated Unsupported operation.
516   */
517  @CanIgnoreReturnValue
518  @Deprecated
519  @Override
520  public final V putIfAbsent(K key, V value) {
521    throw new UnsupportedOperationException();
522  }
523
524  /**
525   * Guaranteed to throw an exception and leave the map unmodified.
526   *
527   * @throws UnsupportedOperationException always
528   * @deprecated Unsupported operation.
529   */
530  @Deprecated
531  @Override
532  public final boolean replace(K key, V oldValue, V newValue) {
533    throw new UnsupportedOperationException();
534  }
535
536  /**
537   * Guaranteed to throw an exception and leave the map unmodified.
538   *
539   * @throws UnsupportedOperationException always
540   * @deprecated Unsupported operation.
541   */
542  @Deprecated
543  @Override
544  public final V replace(K key, V value) {
545    throw new UnsupportedOperationException();
546  }
547
548  /**
549   * Guaranteed to throw an exception and leave the map unmodified.
550   *
551   * @throws UnsupportedOperationException always
552   * @deprecated Unsupported operation.
553   */
554  @Deprecated
555  @Override
556  public final V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
557    throw new UnsupportedOperationException();
558  }
559
560  /**
561   * Guaranteed to throw an exception and leave the map unmodified.
562   *
563   * @throws UnsupportedOperationException always
564   * @deprecated Unsupported operation.
565   */
566  @Deprecated
567  @Override
568  public final V computeIfPresent(
569      K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
570    throw new UnsupportedOperationException();
571  }
572
573  /**
574   * Guaranteed to throw an exception and leave the map unmodified.
575   *
576   * @throws UnsupportedOperationException always
577   * @deprecated Unsupported operation.
578   */
579  @Deprecated
580  @Override
581  public final V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
582    throw new UnsupportedOperationException();
583  }
584
585  /**
586   * Guaranteed to throw an exception and leave the map unmodified.
587   *
588   * @throws UnsupportedOperationException always
589   * @deprecated Unsupported operation.
590   */
591  @Deprecated
592  @Override
593  public final V merge(
594      K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
595    throw new UnsupportedOperationException();
596  }
597
598  /**
599   * Guaranteed to throw an exception and leave the map unmodified.
600   *
601   * @throws UnsupportedOperationException always
602   * @deprecated Unsupported operation.
603   */
604  @Deprecated
605  @Override
606  public final void putAll(Map<? extends K, ? extends V> map) {
607    throw new UnsupportedOperationException();
608  }
609
610  /**
611   * Guaranteed to throw an exception and leave the map unmodified.
612   *
613   * @throws UnsupportedOperationException always
614   * @deprecated Unsupported operation.
615   */
616  @Deprecated
617  @Override
618  public final void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
619    throw new UnsupportedOperationException();
620  }
621
622  /**
623   * Guaranteed to throw an exception and leave the map unmodified.
624   *
625   * @throws UnsupportedOperationException always
626   * @deprecated Unsupported operation.
627   */
628  @Deprecated
629  @Override
630  public final V remove(Object o) {
631    throw new UnsupportedOperationException();
632  }
633
634  /**
635   * Guaranteed to throw an exception and leave the map unmodified.
636   *
637   * @throws UnsupportedOperationException always
638   * @deprecated Unsupported operation.
639   */
640  @Deprecated
641  @Override
642  public final boolean remove(Object key, Object value) {
643    throw new UnsupportedOperationException();
644  }
645
646  /**
647   * Guaranteed to throw an exception and leave the map unmodified.
648   *
649   * @throws UnsupportedOperationException always
650   * @deprecated Unsupported operation.
651   */
652  @Deprecated
653  @Override
654  public final void clear() {
655    throw new UnsupportedOperationException();
656  }
657
658  @Override
659  public boolean isEmpty() {
660    return size() == 0;
661  }
662
663  @Override
664  public boolean containsKey(@NullableDecl Object key) {
665    return get(key) != null;
666  }
667
668  @Override
669  public boolean containsValue(@NullableDecl Object value) {
670    return values().contains(value);
671  }
672
673  // Overriding to mark it Nullable
674  @Override
675  public abstract V get(@NullableDecl Object key);
676
677  /**
678   * @since 21.0 (but only since 23.5 in the Android <a
679   *     href="https://github.com/google/guava#guava-google-core-libraries-for-java">flavor</a>).
680   *     Note, however, that Java 8 users can call this method with any version and flavor of Guava.
681   */
682  @Override
683  public final V getOrDefault(@NullableDecl Object key, @NullableDecl V defaultValue) {
684    V result = get(key);
685    return (result != null) ? result : defaultValue;
686  }
687
688  @LazyInit private transient ImmutableSet<Entry<K, V>> entrySet;
689
690  /**
691   * Returns an immutable set of the mappings in this map. The iteration order is specified by the
692   * method used to create this map. Typically, this is insertion order.
693   */
694  @Override
695  public ImmutableSet<Entry<K, V>> entrySet() {
696    ImmutableSet<Entry<K, V>> result = entrySet;
697    return (result == null) ? entrySet = createEntrySet() : result;
698  }
699
700  abstract ImmutableSet<Entry<K, V>> createEntrySet();
701
702  @LazyInit private transient ImmutableSet<K> keySet;
703
704  /**
705   * Returns an immutable set of the keys in this map, in the same order that they appear in {@link
706   * #entrySet}.
707   */
708  @Override
709  public ImmutableSet<K> keySet() {
710    ImmutableSet<K> result = keySet;
711    return (result == null) ? keySet = createKeySet() : result;
712  }
713
714  /*
715   * This could have a good default implementation of return new ImmutableKeySet<K, V>(this),
716   * but ProGuard can't figure out how to eliminate that default when RegularImmutableMap
717   * overrides it.
718   */
719  abstract ImmutableSet<K> createKeySet();
720
721  UnmodifiableIterator<K> keyIterator() {
722    final UnmodifiableIterator<Entry<K, V>> entryIterator = entrySet().iterator();
723    return new UnmodifiableIterator<K>() {
724      @Override
725      public boolean hasNext() {
726        return entryIterator.hasNext();
727      }
728
729      @Override
730      public K next() {
731        return entryIterator.next().getKey();
732      }
733    };
734  }
735
736  Spliterator<K> keySpliterator() {
737    return CollectSpliterators.map(entrySet().spliterator(), Entry::getKey);
738  }
739
740  @LazyInit private transient ImmutableCollection<V> values;
741
742  /**
743   * Returns an immutable collection of the values in this map, in the same order that they appear
744   * in {@link #entrySet}.
745   */
746  @Override
747  public ImmutableCollection<V> values() {
748    ImmutableCollection<V> result = values;
749    return (result == null) ? values = createValues() : result;
750  }
751
752  /*
753   * This could have a good default implementation of {@code return new
754   * ImmutableMapValues<K, V>(this)}, but ProGuard can't figure out how to eliminate that default
755   * when RegularImmutableMap overrides it.
756   */
757  abstract ImmutableCollection<V> createValues();
758
759  // cached so that this.multimapView().inverse() only computes inverse once
760  @LazyInit private transient ImmutableSetMultimap<K, V> multimapView;
761
762  /**
763   * Returns a multimap view of the map.
764   *
765   * @since 14.0
766   */
767  public ImmutableSetMultimap<K, V> asMultimap() {
768    if (isEmpty()) {
769      return ImmutableSetMultimap.of();
770    }
771    ImmutableSetMultimap<K, V> result = multimapView;
772    return (result == null)
773        ? (multimapView =
774            new ImmutableSetMultimap<>(new MapViewOfValuesAsSingletonSets(), size(), null))
775        : result;
776  }
777
778  @WeakOuter
779  private final class MapViewOfValuesAsSingletonSets
780      extends IteratorBasedImmutableMap<K, ImmutableSet<V>> {
781
782    @Override
783    public int size() {
784      return ImmutableMap.this.size();
785    }
786
787    @Override
788    ImmutableSet<K> createKeySet() {
789      return ImmutableMap.this.keySet();
790    }
791
792    @Override
793    public boolean containsKey(@NullableDecl Object key) {
794      return ImmutableMap.this.containsKey(key);
795    }
796
797    @Override
798    public ImmutableSet<V> get(@NullableDecl Object key) {
799      V outerValue = ImmutableMap.this.get(key);
800      return (outerValue == null) ? null : ImmutableSet.of(outerValue);
801    }
802
803    @Override
804    boolean isPartialView() {
805      return ImmutableMap.this.isPartialView();
806    }
807
808    @Override
809    public int hashCode() {
810      // ImmutableSet.of(value).hashCode() == value.hashCode(), so the hashes are the same
811      return ImmutableMap.this.hashCode();
812    }
813
814    @Override
815    boolean isHashCodeFast() {
816      return ImmutableMap.this.isHashCodeFast();
817    }
818
819    @Override
820    UnmodifiableIterator<Entry<K, ImmutableSet<V>>> entryIterator() {
821      final Iterator<Entry<K, V>> backingIterator = ImmutableMap.this.entrySet().iterator();
822      return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
823        @Override
824        public boolean hasNext() {
825          return backingIterator.hasNext();
826        }
827
828        @Override
829        public Entry<K, ImmutableSet<V>> next() {
830          final Entry<K, V> backingEntry = backingIterator.next();
831          return new AbstractMapEntry<K, ImmutableSet<V>>() {
832            @Override
833            public K getKey() {
834              return backingEntry.getKey();
835            }
836
837            @Override
838            public ImmutableSet<V> getValue() {
839              return ImmutableSet.of(backingEntry.getValue());
840            }
841          };
842        }
843      };
844    }
845  }
846
847  @Override
848  public boolean equals(@NullableDecl Object object) {
849    return Maps.equalsImpl(this, object);
850  }
851
852  abstract boolean isPartialView();
853
854  @Override
855  public int hashCode() {
856    return Sets.hashCodeImpl(entrySet());
857  }
858
859  boolean isHashCodeFast() {
860    return false;
861  }
862
863  @Override
864  public String toString() {
865    return Maps.toStringImpl(this);
866  }
867
868  /**
869   * Serialized type for all ImmutableMap instances. It captures the logical contents and they are
870   * reconstructed using public factory methods. This ensures that the implementation types remain
871   * as implementation details.
872   */
873  static class SerializedForm implements Serializable {
874    private final Object[] keys;
875    private final Object[] values;
876
877    SerializedForm(ImmutableMap<?, ?> map) {
878      keys = new Object[map.size()];
879      values = new Object[map.size()];
880      int i = 0;
881      for (Entry<?, ?> entry : map.entrySet()) {
882        keys[i] = entry.getKey();
883        values[i] = entry.getValue();
884        i++;
885      }
886    }
887
888    Object readResolve() {
889      Builder<Object, Object> builder = new Builder<>(keys.length);
890      return createMap(builder);
891    }
892
893    Object createMap(Builder<Object, Object> builder) {
894      for (int i = 0; i < keys.length; i++) {
895        builder.put(keys[i], values[i]);
896      }
897      return builder.build();
898    }
899
900    private static final long serialVersionUID = 0;
901  }
902
903  Object writeReplace() {
904    return new SerializedForm(this);
905  }
906}