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;
022
023import com.google.common.annotations.Beta;
024import com.google.common.annotations.GwtCompatible;
025import com.google.errorprone.annotations.CanIgnoreReturnValue;
026import com.google.errorprone.annotations.concurrent.LazyInit;
027import com.google.j2objc.annotations.WeakOuter;
028import java.io.Serializable;
029import java.util.AbstractMap;
030import java.util.Arrays;
031import java.util.Collection;
032import java.util.Collections;
033import java.util.Comparator;
034import java.util.Iterator;
035import java.util.Map;
036import java.util.SortedMap;
037import javax.annotation.Nullable;
038
039/**
040 * A {@link Map} whose contents will never change, with many other important properties detailed at
041 * {@link ImmutableCollection}.
042 *
043 * <p>See the Guava User Guide article on <a href=
044 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>.
045 *
046 * @author Jesse Wilson
047 * @author Kevin Bourrillion
048 * @since 2.0
049 */
050@GwtCompatible(serializable = true, emulated = true)
051@SuppressWarnings("serial") // we're overriding default serialization
052public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
053
054  /**
055   * Returns the empty map. This map behaves and performs comparably to {@link
056   * Collections#emptyMap}, and is preferable mainly for consistency and maintainability of your
057   * code.
058   */
059  @SuppressWarnings("unchecked")
060  public static <K, V> ImmutableMap<K, V> of() {
061    return (ImmutableMap<K, V>) RegularImmutableMap.EMPTY;
062  }
063
064  /**
065   * Returns an immutable map containing a single entry. This map behaves and performs comparably to
066   * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable
067   * mainly for consistency and maintainability of your code.
068   */
069  public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
070    checkEntryNotNull(k1, v1);
071    return RegularImmutableMap.create(1, new Object[] {k1, v1});
072  }
073
074  /**
075   * Returns an immutable map containing the given entries, in order.
076   *
077   * @throws IllegalArgumentException if duplicate keys are provided
078   */
079  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
080    checkEntryNotNull(k1, v1);
081    checkEntryNotNull(k2, v2);
082    return RegularImmutableMap.create(2, new Object[] {k1, v1, k2, v2});
083  }
084
085  /**
086   * Returns an immutable map containing the given entries, in order.
087   *
088   * @throws IllegalArgumentException if duplicate keys are provided
089   */
090  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
091    checkEntryNotNull(k1, v1);
092    checkEntryNotNull(k2, v2);
093    checkEntryNotNull(k3, v3);
094    return RegularImmutableMap.create(3, new Object[] {k1, v1, k2, v2, k3, v3});
095  }
096
097  /**
098   * Returns an immutable map containing the given entries, in order.
099   *
100   * @throws IllegalArgumentException if duplicate keys are provided
101   */
102  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
103    checkEntryNotNull(k1, v1);
104    checkEntryNotNull(k2, v2);
105    checkEntryNotNull(k3, v3);
106    checkEntryNotNull(k4, v4);
107    return RegularImmutableMap.create(4, new Object[] {k1, v1, k2, v2, k3, v3, k4, v4});
108  }
109
110  /**
111   * Returns an immutable map containing the given entries, in order.
112   *
113   * @throws IllegalArgumentException if duplicate keys are provided
114   */
115  public static <K, V> ImmutableMap<K, V> of(
116      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
117    checkEntryNotNull(k1, v1);
118    checkEntryNotNull(k2, v2);
119    checkEntryNotNull(k3, v3);
120    checkEntryNotNull(k4, v4);
121    checkEntryNotNull(k5, v5);
122    return RegularImmutableMap.create(5, new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5});
123  }
124
125  // looking for of() with > 5 entries? Use the builder instead.
126
127  /**
128   * Verifies that {@code key} and {@code value} are non-null, and returns a new
129   * immutable entry with those values.
130   * <p>A call to {@link Map.Entry#setValue} on the returned entry will always
131   * throw {@link UnsupportedOperationException}.
132   */
133  static <K, V> Entry<K, V> entryOf(K key, V value) {
134    checkEntryNotNull(key, value);
135    return new AbstractMap.SimpleImmutableEntry<K, V>(key, value);
136  }
137
138  /**
139   * Returns a new builder. The generated builder is equivalent to the builder created by the {@link
140   * Builder} constructor.
141   */
142  public static <K, V> Builder<K, V> builder() {
143    return new Builder<K, V>();
144  }
145
146  static void checkNoConflict(
147      boolean safe, String conflictDescription, Entry<?, ?> entry1, Entry<?, ?> entry2) {
148    if (!safe) {
149      throw new IllegalArgumentException(
150          "Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2);
151    }
152  }
153
154  /**
155   * A builder for creating immutable map instances, especially {@code public
156   * static final} maps ("constant maps"). Example: <pre>   {@code
157   *
158   * static final ImmutableMap<String, Integer> WORD_TO_INT =
159   *     new ImmutableMap.Builder<String, Integer>()
160   *         .put("one", 1)
161   *         .put("two", 2)
162   *         .put("three", 3)
163   *         .build();
164   * }</pre>
165   *
166   * <p>For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are even more
167   * convenient.
168   *
169   * <p>By default, a {@code Builder} will generate maps that iterate over entries in the order
170   * they were inserted into the builder, equivalently to {@code LinkedHashMap}.  For example, in
171   * the above example, {@code WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in
172   * the order {@code "one"=1, "two"=2, "three"=3}, and {@code keySet()} and {@code values()}
173   * respect the same order.   If you want a different order, consider using 
174   * {@link ImmutableSortedMap} to sort by keys, or call {@link #orderEntriesByValue(Comparator)}, 
175   * which changes this builder to sort entries by value.
176   *
177   * <p>Builder instances can be reused - it is safe to call {@link #build}
178   * multiple times to build multiple maps in series. Each map is a superset of
179   * the maps created before it.
180   *
181   * @since 2.0
182   */
183  public static class Builder<K, V> {
184    Comparator<? super V> valueComparator;
185    Object[] alternatingKeysAndValues;
186    int size;
187    boolean entriesUsed;
188
189    /**
190     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
191     * ImmutableMap#builder}.
192     */
193    public Builder() {
194      this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY);
195    }
196
197    @SuppressWarnings("unchecked")
198    Builder(int initialCapacity) {
199      this.alternatingKeysAndValues = new Object[2 * initialCapacity];
200      this.size = 0;
201      this.entriesUsed = false;
202    }
203
204    private void ensureCapacity(int minCapacity) {
205      if (minCapacity * 2 > alternatingKeysAndValues.length) {
206        alternatingKeysAndValues =
207            Arrays.copyOf(
208                alternatingKeysAndValues,
209                ImmutableCollection.Builder.expandedCapacity(
210                    alternatingKeysAndValues.length, minCapacity * 2));
211        entriesUsed = false;
212      }
213    }
214
215    /**
216     * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed,
217     * and will cause {@link #build} to fail.
218     */
219    @CanIgnoreReturnValue
220    public Builder<K, V> put(K key, V value) {
221      ensureCapacity(size + 1);
222      checkEntryNotNull(key, value);
223      alternatingKeysAndValues[2 * size] = key;
224      alternatingKeysAndValues[2 * size + 1] = value;
225      size++;
226      return this;
227    }
228
229    /**
230     * Adds the given {@code entry} to the map, making it immutable if necessary. Duplicate keys are
231     * not allowed, and will cause {@link #build} to fail.
232     *
233     * @since 11.0
234     */
235    @CanIgnoreReturnValue
236    public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
237      return put(entry.getKey(), entry.getValue());
238    }
239
240    /**
241     * Associates all of the given map's keys and values in the built map. Duplicate keys are not
242     * allowed, and will cause {@link #build} to fail.
243     *
244     * @throws NullPointerException if any key or value in {@code map} is null
245     */
246    @CanIgnoreReturnValue
247    public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
248      return putAll(map.entrySet());
249    }
250
251    /**
252     * Adds all of the given entries to the built map. Duplicate keys are not allowed, and will
253     * cause {@link #build} to fail.
254     *
255     * @throws NullPointerException if any key, value, or entry is null
256     * @since 19.0
257     */
258    @CanIgnoreReturnValue
259    @Beta
260    public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) {
261      if (entries instanceof Collection) {
262        ensureCapacity(size + ((Collection<?>) entries).size());
263      }
264      for (Entry<? extends K, ? extends V> entry : entries) {
265        put(entry);
266      }
267      return this;
268    }
269
270    /**
271     * Configures this {@code Builder} to order entries by value according to the specified
272     * comparator.
273     *
274     * <p>The sort order is stable, that is, if two entries have values that compare as equivalent,
275     * the entry that was inserted first will be first in the built map's iteration order.
276     *
277     * @throws IllegalStateException if this method was already called
278     * @since 19.0
279     */
280    @CanIgnoreReturnValue
281    @Beta
282    public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) {
283      checkState(this.valueComparator == null, "valueComparator was already set");
284      this.valueComparator = checkNotNull(valueComparator, "valueComparator");
285      return this;
286    }
287
288    /*
289     * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap
290     * versions throw an IllegalStateException instead?
291     */
292
293    /**
294     * Returns a newly-created immutable map.  The iteration order of the returned map is
295     * the order in which entries were inserted into the builder, unless
296     * {@link #orderEntriesByValue} was called, in which case entries are sorted by value.
297     *
298     * @throws IllegalArgumentException if duplicate keys were added
299     */
300    @SuppressWarnings("unchecked")
301    public ImmutableMap<K, V> build() {
302      /*
303       * If entries is full, then this implementation may end up using the entries array
304       * directly and writing over the entry objects with non-terminal entries, but this is
305       * safe; if this Builder is used further, it will grow the entries array (so it can't
306       * affect the original array), and future build() calls will always copy any entry
307       * objects that cannot be safely reused.
308       */
309      sortEntries();
310      entriesUsed = true;
311      return RegularImmutableMap.create(size, alternatingKeysAndValues);
312    }
313
314    void sortEntries() {
315      if (valueComparator != null) {
316        if (entriesUsed) {
317          alternatingKeysAndValues = Arrays.copyOf(alternatingKeysAndValues, 2 * size);
318        }
319        Entry<K, V>[] entries = new Entry[size];
320        for (int i = 0; i < size; i++) {
321          entries[i] =
322              new AbstractMap.SimpleImmutableEntry<K, V>(
323                  (K) alternatingKeysAndValues[2 * i], (V) alternatingKeysAndValues[2 * i + 1]);
324        }
325        Arrays.sort(
326            entries, 0, size, Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction()));
327        for (int i = 0; i < size; i++) {
328          alternatingKeysAndValues[2 * i] = entries[i].getKey();
329          alternatingKeysAndValues[2 * i + 1] = entries[i].getValue();
330        }
331      }
332    }
333  }
334
335  /**
336   * Returns an immutable map containing the same entries as {@code map}. The returned map iterates
337   * over entries in the same order as the {@code entrySet} of the original map.  If {@code map}
338   * somehow contains entries with duplicate keys (for example, if it is a {@code SortedMap}
339   * whose comparator is not <i>consistent with equals</i>), the results of this method are
340   * undefined.
341   *
342   * <p>Despite the method name, this method attempts to avoid actually copying
343   * the data when it is safe to do so. The exact circumstances under which a
344   * copy will or will not be performed are undocumented and subject to change.
345   *
346   * @throws NullPointerException if any key or value in {@code map} is null
347   */
348  public static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V> map) {
349    if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) {
350      @SuppressWarnings("unchecked") // safe since map is not writable
351      ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
352      if (!kvMap.isPartialView()) {
353        return kvMap;
354      }
355    }
356    return copyOf(map.entrySet());
357  }
358
359  /**
360   * Returns an immutable map containing the specified entries. The returned map iterates over
361   * entries in the same order as the original iterable.
362   *
363   * @throws NullPointerException if any key, value, or entry is null
364   * @throws IllegalArgumentException if two entries have the same key
365   * @since 19.0
366   */
367  @Beta
368  public static <K, V> ImmutableMap<K, V> copyOf(
369      Iterable<? extends Entry<? extends K, ? extends V>> entries) {
370    int initialCapacity =
371        (entries instanceof Collection)
372            ? ((Collection<?>) entries).size()
373            : ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY;
374    ImmutableMap.Builder<K, V> builder = new ImmutableMap.Builder<K, V>(initialCapacity);
375    builder.putAll(entries);
376    return builder.build();
377  }
378
379  static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
380
381  abstract static class IteratorBasedImmutableMap<K, V> extends ImmutableMap<K, V> {
382    abstract UnmodifiableIterator<Entry<K, V>> entryIterator();
383
384    @Override
385    ImmutableSet<K> createKeySet() {
386      return new ImmutableMapKeySet<>(this);
387    }
388
389    @Override
390    ImmutableSet<Entry<K, V>> createEntrySet() {
391      @WeakOuter
392      class EntrySetImpl extends ImmutableMapEntrySet<K, V> {
393        @Override
394        ImmutableMap<K, V> map() {
395          return IteratorBasedImmutableMap.this;
396        }
397
398        @Override
399        public UnmodifiableIterator<Entry<K, V>> iterator() {
400          return entryIterator();
401        }
402      }
403      return new EntrySetImpl();
404    }
405
406    @Override
407    ImmutableCollection<V> createValues() {
408      return new ImmutableMapValues<>(this);
409    }
410  }
411
412  ImmutableMap() {}
413
414  /**
415   * Guaranteed to throw an exception and leave the map unmodified.
416   *
417   * @throws UnsupportedOperationException always
418   * @deprecated Unsupported operation.
419   */
420  @CanIgnoreReturnValue
421  @Deprecated
422  @Override
423  public final V put(K k, V v) {
424    throw new UnsupportedOperationException();
425  }
426
427  /**
428   * Guaranteed to throw an exception and leave the map unmodified.
429   *
430   * @throws UnsupportedOperationException always
431   * @deprecated Unsupported operation.
432   */
433  @CanIgnoreReturnValue
434  @Deprecated
435  @Override
436  public final V remove(Object o) {
437    throw new UnsupportedOperationException();
438  }
439
440  /**
441   * Guaranteed to throw an exception and leave the map unmodified.
442   *
443   * @throws UnsupportedOperationException always
444   * @deprecated Unsupported operation.
445   */
446  @Deprecated
447  @Override
448  public final void putAll(Map<? extends K, ? extends V> map) {
449    throw new UnsupportedOperationException();
450  }
451
452  /**
453   * Guaranteed to throw an exception and leave the map unmodified.
454   *
455   * @throws UnsupportedOperationException always
456   * @deprecated Unsupported operation.
457   */
458  @Deprecated
459  @Override
460  public final void clear() {
461    throw new UnsupportedOperationException();
462  }
463
464  @Override
465  public boolean isEmpty() {
466    return size() == 0;
467  }
468
469  @Override
470  public boolean containsKey(@Nullable Object key) {
471    return get(key) != null;
472  }
473
474  @Override
475  public boolean containsValue(@Nullable Object value) {
476    return values().contains(value);
477  }
478
479  // Overriding to mark it Nullable
480  @Override
481  public abstract V get(@Nullable Object key);
482
483  @LazyInit private transient ImmutableSet<Entry<K, V>> entrySet;
484
485  /**
486   * Returns an immutable set of the mappings in this map.  The iteration order is specified by
487   * the method used to create this map.  Typically, this is insertion order.
488   */
489  @Override
490  public ImmutableSet<Entry<K, V>> entrySet() {
491    ImmutableSet<Entry<K, V>> result = entrySet;
492    return (result == null) ? entrySet = createEntrySet() : result;
493  }
494
495  abstract ImmutableSet<Entry<K, V>> createEntrySet();
496
497  @LazyInit private transient ImmutableSet<K> keySet;
498
499  /**
500   * Returns an immutable set of the keys in this map, in the same order that they appear in
501   * {@link #entrySet}.
502   */
503  @Override
504  public ImmutableSet<K> keySet() {
505    ImmutableSet<K> result = keySet;
506    return (result == null) ? keySet = createKeySet() : result;
507  }
508
509  /*
510   * This could have a good default implementation of return new ImmutableKeySet<K, V>(this),
511   * but ProGuard can't figure out how to eliminate that default when RegularImmutableMap
512   * overrides it.
513   */
514  abstract ImmutableSet<K> createKeySet();
515
516  UnmodifiableIterator<K> keyIterator() {
517    final UnmodifiableIterator<Entry<K, V>> entryIterator = entrySet().iterator();
518    return new UnmodifiableIterator<K>() {
519      @Override
520      public boolean hasNext() {
521        return entryIterator.hasNext();
522      }
523
524      @Override
525      public K next() {
526        return entryIterator.next().getKey();
527      }
528    };
529  }
530
531  @LazyInit private transient ImmutableCollection<V> values;
532
533  /**
534   * Returns an immutable collection of the values in this map, in the same order that they appear
535   * in {@link #entrySet}.
536   */
537  @Override
538  public ImmutableCollection<V> values() {
539    ImmutableCollection<V> result = values;
540    return (result == null) ? values = createValues() : result;
541  }
542
543  /*
544   * This could have a good default implementation of {@code return new
545   * ImmutableMapValues<K, V>(this)}, but ProGuard can't figure out how to eliminate that default
546   * when RegularImmutableMap overrides it.
547   */
548  abstract ImmutableCollection<V> createValues();
549
550  // cached so that this.multimapView().inverse() only computes inverse once
551  @LazyInit private transient ImmutableSetMultimap<K, V> multimapView;
552
553  /**
554   * Returns a multimap view of the map.
555   *
556   * @since 14.0
557   */
558  public ImmutableSetMultimap<K, V> asMultimap() {
559    if (isEmpty()) {
560      return ImmutableSetMultimap.of();
561    }
562    ImmutableSetMultimap<K, V> result = multimapView;
563    return (result == null)
564        ? (multimapView =
565            new ImmutableSetMultimap<>(new MapViewOfValuesAsSingletonSets(), size(), null))
566        : result;
567  }
568
569  @WeakOuter
570  private final class MapViewOfValuesAsSingletonSets
571      extends IteratorBasedImmutableMap<K, ImmutableSet<V>> {
572
573    @Override
574    public int size() {
575      return ImmutableMap.this.size();
576    }
577
578    @Override
579    ImmutableSet<K> createKeySet() {
580      return ImmutableMap.this.keySet();
581    }
582
583    @Override
584    public boolean containsKey(@Nullable Object key) {
585      return ImmutableMap.this.containsKey(key);
586    }
587
588    @Override
589    public ImmutableSet<V> get(@Nullable Object key) {
590      V outerValue = ImmutableMap.this.get(key);
591      return (outerValue == null) ? null : ImmutableSet.of(outerValue);
592    }
593
594    @Override
595    boolean isPartialView() {
596      return ImmutableMap.this.isPartialView();
597    }
598
599    @Override
600    public int hashCode() {
601      // ImmutableSet.of(value).hashCode() == value.hashCode(), so the hashes are the same
602      return ImmutableMap.this.hashCode();
603    }
604
605    @Override
606    boolean isHashCodeFast() {
607      return ImmutableMap.this.isHashCodeFast();
608    }
609
610    @Override
611    UnmodifiableIterator<Entry<K, ImmutableSet<V>>> entryIterator() {
612      final Iterator<Entry<K, V>> backingIterator = ImmutableMap.this.entrySet().iterator();
613      return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
614        @Override
615        public boolean hasNext() {
616          return backingIterator.hasNext();
617        }
618
619        @Override
620        public Entry<K, ImmutableSet<V>> next() {
621          final Entry<K, V> backingEntry = backingIterator.next();
622          return new AbstractMapEntry<K, ImmutableSet<V>>() {
623            @Override
624            public K getKey() {
625              return backingEntry.getKey();
626            }
627
628            @Override
629            public ImmutableSet<V> getValue() {
630              return ImmutableSet.of(backingEntry.getValue());
631            }
632          };
633        }
634      };
635    }
636  }
637
638  @Override
639  public boolean equals(@Nullable Object object) {
640    return Maps.equalsImpl(this, object);
641  }
642
643  abstract boolean isPartialView();
644
645  @Override
646  public int hashCode() {
647    return Sets.hashCodeImpl(entrySet());
648  }
649
650  boolean isHashCodeFast() {
651    return false;
652  }
653
654  @Override
655  public String toString() {
656    return Maps.toStringImpl(this);
657  }
658
659  /**
660   * Serialized type for all ImmutableMap instances. It captures the logical contents and they are
661   * reconstructed using public factory methods. This ensures that the implementation types remain
662   * as implementation details.
663   */
664  static class SerializedForm implements Serializable {
665    private final Object[] keys;
666    private final Object[] values;
667
668    SerializedForm(ImmutableMap<?, ?> map) {
669      keys = new Object[map.size()];
670      values = new Object[map.size()];
671      int i = 0;
672      for (Entry<?, ?> entry : map.entrySet()) {
673        keys[i] = entry.getKey();
674        values[i] = entry.getValue();
675        i++;
676      }
677    }
678
679    Object readResolve() {
680      Builder<Object, Object> builder = new Builder<>(keys.length);
681      return createMap(builder);
682    }
683
684    Object createMap(Builder<Object, Object> builder) {
685      for (int i = 0; i < keys.length; i++) {
686        builder.put(keys[i], values[i]);
687      }
688      return builder.build();
689    }
690
691    private static final long serialVersionUID = 0;
692  }
693
694  Object writeReplace() {
695    return new SerializedForm(this);
696  }
697}