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 static final} maps
156   * ("constant maps"). Example:
157   *
158   * <pre>{@code
159   * static final ImmutableMap<String, Integer> WORD_TO_INT =
160   *     new ImmutableMap.Builder<String, Integer>()
161   *         .put("one", 1)
162   *         .put("two", 2)
163   *         .put("three", 3)
164   *         .build();
165   * }</pre>
166   *
167   * <p>For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are even more
168   * convenient.
169   *
170   * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build
171   * multiple maps in series. Each map is a superset of the maps created before it.
172   *
173   * @since 2.0
174   */
175  public static class Builder<K, V> {
176    Comparator<? super V> valueComparator;
177    Object[] alternatingKeysAndValues;
178    int size;
179    boolean entriesUsed;
180
181    /**
182     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
183     * ImmutableMap#builder}.
184     */
185    public Builder() {
186      this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY);
187    }
188
189    @SuppressWarnings("unchecked")
190    Builder(int initialCapacity) {
191      this.alternatingKeysAndValues = new Object[2 * initialCapacity];
192      this.size = 0;
193      this.entriesUsed = false;
194    }
195
196    private void ensureCapacity(int minCapacity) {
197      if (minCapacity * 2 > alternatingKeysAndValues.length) {
198        alternatingKeysAndValues =
199            Arrays.copyOf(
200                alternatingKeysAndValues,
201                ImmutableCollection.Builder.expandedCapacity(
202                    alternatingKeysAndValues.length, minCapacity * 2));
203        entriesUsed = false;
204      }
205    }
206
207    /**
208     * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed,
209     * and will cause {@link #build} to fail.
210     */
211    @CanIgnoreReturnValue
212    public Builder<K, V> put(K key, V value) {
213      ensureCapacity(size + 1);
214      checkEntryNotNull(key, value);
215      alternatingKeysAndValues[2 * size] = key;
216      alternatingKeysAndValues[2 * size + 1] = value;
217      size++;
218      return this;
219    }
220
221    /**
222     * Adds the given {@code entry} to the map, making it immutable if necessary. Duplicate keys are
223     * not allowed, and will cause {@link #build} to fail.
224     *
225     * @since 11.0
226     */
227    @CanIgnoreReturnValue
228    public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
229      return put(entry.getKey(), entry.getValue());
230    }
231
232    /**
233     * Associates all of the given map's keys and values in the built map. Duplicate keys are not
234     * allowed, and will cause {@link #build} to fail.
235     *
236     * @throws NullPointerException if any key or value in {@code map} is null
237     */
238    @CanIgnoreReturnValue
239    public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
240      return putAll(map.entrySet());
241    }
242
243    /**
244     * Adds all of the given entries to the built map. Duplicate keys are not allowed, and will
245     * cause {@link #build} to fail.
246     *
247     * @throws NullPointerException if any key, value, or entry is null
248     * @since 19.0
249     */
250    @CanIgnoreReturnValue
251    @Beta
252    public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) {
253      if (entries instanceof Collection) {
254        ensureCapacity(size + ((Collection<?>) entries).size());
255      }
256      for (Entry<? extends K, ? extends V> entry : entries) {
257        put(entry);
258      }
259      return this;
260    }
261
262    /**
263     * Configures this {@code Builder} to order entries by value according to the specified
264     * comparator.
265     *
266     * <p>The sort order is stable, that is, if two entries have values that compare as equivalent,
267     * the entry that was inserted first will be first in the built map's iteration order.
268     *
269     * @throws IllegalStateException if this method was already called
270     * @since 19.0
271     */
272    @CanIgnoreReturnValue
273    @Beta
274    public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) {
275      checkState(this.valueComparator == null, "valueComparator was already set");
276      this.valueComparator = checkNotNull(valueComparator, "valueComparator");
277      return this;
278    }
279
280    /*
281     * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap
282     * versions throw an IllegalStateException instead?
283     */
284
285    /**
286     * Returns a newly-created immutable map.
287     *
288     * @throws IllegalArgumentException if duplicate keys were added
289     */
290    @SuppressWarnings("unchecked")
291    public ImmutableMap<K, V> build() {
292      /*
293       * If entries is full, then this implementation may end up using the entries array
294       * directly and writing over the entry objects with non-terminal entries, but this is
295       * safe; if this Builder is used further, it will grow the entries array (so it can't
296       * affect the original array), and future build() calls will always copy any entry
297       * objects that cannot be safely reused.
298       */
299      sortEntries();
300      entriesUsed = true;
301      return RegularImmutableMap.create(size, alternatingKeysAndValues);
302    }
303
304    void sortEntries() {
305      if (valueComparator != null) {
306        if (entriesUsed) {
307          alternatingKeysAndValues = Arrays.copyOf(alternatingKeysAndValues, 2 * size);
308        }
309        Entry<K, V>[] entries = new Entry[size];
310        for (int i = 0; i < size; i++) {
311          entries[i] =
312              new AbstractMap.SimpleImmutableEntry<K, V>(
313                  (K) alternatingKeysAndValues[2 * i], (V) alternatingKeysAndValues[2 * i + 1]);
314        }
315        Arrays.sort(
316            entries, 0, size, Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction()));
317        for (int i = 0; i < size; i++) {
318          alternatingKeysAndValues[2 * i] = entries[i].getKey();
319          alternatingKeysAndValues[2 * i + 1] = entries[i].getValue();
320        }
321      }
322    }
323  }
324
325  /**
326   * Returns an immutable map containing the same entries as {@code map}. If {@code map} somehow
327   * contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose
328   * comparator is not <i>consistent with equals</i>), the results of this method are undefined.
329   *
330   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
331   * safe to do so. The exact circumstances under which a copy will or will not be performed are
332   * undocumented and subject to change.
333   *
334   * @throws NullPointerException if any key or value in {@code map} is null
335   */
336  public static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V> map) {
337    if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) {
338      // TODO(lowasser): Make ImmutableMap.copyOf(immutableBiMap) call copyOf()
339      // on the ImmutableMap delegate(), rather than the bimap itself
340
341      @SuppressWarnings("unchecked") // safe since map is not writable
342      ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
343      if (!kvMap.isPartialView()) {
344        return kvMap;
345      }
346    }
347    return copyOf(map.entrySet());
348  }
349
350  /**
351   * Returns an immutable map containing the specified entries. The returned map iterates over
352   * entries in the same order as the original iterable.
353   *
354   * @throws NullPointerException if any key, value, or entry is null
355   * @throws IllegalArgumentException if two entries have the same key
356   * @since 19.0
357   */
358  @Beta
359  public static <K, V> ImmutableMap<K, V> copyOf(
360      Iterable<? extends Entry<? extends K, ? extends V>> entries) {
361    int initialCapacity =
362        (entries instanceof Collection)
363            ? ((Collection<?>) entries).size()
364            : ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY;
365    ImmutableMap.Builder<K, V> builder = new ImmutableMap.Builder<K, V>(initialCapacity);
366    builder.putAll(entries);
367    return builder.build();
368  }
369
370  static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
371
372  abstract static class IteratorBasedImmutableMap<K, V> extends ImmutableMap<K, V> {
373    abstract UnmodifiableIterator<Entry<K, V>> entryIterator();
374
375    @Override
376    ImmutableSet<K> createKeySet() {
377      return new ImmutableMapKeySet<>(this);
378    }
379
380    @Override
381    ImmutableSet<Entry<K, V>> createEntrySet() {
382      @WeakOuter
383      class EntrySetImpl extends ImmutableMapEntrySet<K, V> {
384        @Override
385        ImmutableMap<K, V> map() {
386          return IteratorBasedImmutableMap.this;
387        }
388
389        @Override
390        public UnmodifiableIterator<Entry<K, V>> iterator() {
391          return entryIterator();
392        }
393      }
394      return new EntrySetImpl();
395    }
396
397    @Override
398    ImmutableCollection<V> createValues() {
399      return new ImmutableMapValues<>(this);
400    }
401  }
402
403  ImmutableMap() {}
404
405  /**
406   * Guaranteed to throw an exception and leave the map unmodified.
407   *
408   * @throws UnsupportedOperationException always
409   * @deprecated Unsupported operation.
410   */
411  @CanIgnoreReturnValue
412  @Deprecated
413  @Override
414  public final V put(K k, V v) {
415    throw new UnsupportedOperationException();
416  }
417
418  /**
419   * Guaranteed to throw an exception and leave the map unmodified.
420   *
421   * @throws UnsupportedOperationException always
422   * @deprecated Unsupported operation.
423   */
424  @CanIgnoreReturnValue
425  @Deprecated
426  @Override
427  public final V remove(Object o) {
428    throw new UnsupportedOperationException();
429  }
430
431  /**
432   * Guaranteed to throw an exception and leave the map unmodified.
433   *
434   * @throws UnsupportedOperationException always
435   * @deprecated Unsupported operation.
436   */
437  @Deprecated
438  @Override
439  public final void putAll(Map<? extends K, ? extends V> map) {
440    throw new UnsupportedOperationException();
441  }
442
443  /**
444   * Guaranteed to throw an exception and leave the map unmodified.
445   *
446   * @throws UnsupportedOperationException always
447   * @deprecated Unsupported operation.
448   */
449  @Deprecated
450  @Override
451  public final void clear() {
452    throw new UnsupportedOperationException();
453  }
454
455  @Override
456  public boolean isEmpty() {
457    return size() == 0;
458  }
459
460  @Override
461  public boolean containsKey(@Nullable Object key) {
462    return get(key) != null;
463  }
464
465  @Override
466  public boolean containsValue(@Nullable Object value) {
467    return values().contains(value);
468  }
469
470  // Overriding to mark it Nullable
471  @Override
472  public abstract V get(@Nullable Object key);
473
474  @LazyInit private transient ImmutableSet<Entry<K, V>> entrySet;
475
476  /**
477   * Returns an immutable set of the mappings in this map. The entries are in the same order as the
478   * parameters used to build this map.
479   */
480  @Override
481  public ImmutableSet<Entry<K, V>> entrySet() {
482    ImmutableSet<Entry<K, V>> result = entrySet;
483    return (result == null) ? entrySet = createEntrySet() : result;
484  }
485
486  abstract ImmutableSet<Entry<K, V>> createEntrySet();
487
488  @LazyInit private transient ImmutableSet<K> keySet;
489
490  /**
491   * Returns an immutable set of the keys in this map. These keys are in the same order as the
492   * parameters used to build this map.
493   */
494  @Override
495  public ImmutableSet<K> keySet() {
496    ImmutableSet<K> result = keySet;
497    return (result == null) ? keySet = createKeySet() : result;
498  }
499
500  /*
501   * This could have a good default implementation of return new ImmutableKeySet<K, V>(this),
502   * but ProGuard can't figure out how to eliminate that default when RegularImmutableMap
503   * overrides it.
504   */
505  abstract ImmutableSet<K> createKeySet();
506
507  UnmodifiableIterator<K> keyIterator() {
508    final UnmodifiableIterator<Entry<K, V>> entryIterator = entrySet().iterator();
509    return new UnmodifiableIterator<K>() {
510      @Override
511      public boolean hasNext() {
512        return entryIterator.hasNext();
513      }
514
515      @Override
516      public K next() {
517        return entryIterator.next().getKey();
518      }
519    };
520  }
521
522  @LazyInit private transient ImmutableCollection<V> values;
523
524  /**
525   * Returns an immutable collection of the values in this map. The values are in the same order as
526   * the parameters used to build this map.
527   */
528  @Override
529  public ImmutableCollection<V> values() {
530    ImmutableCollection<V> result = values;
531    return (result == null) ? values = createValues() : result;
532  }
533
534  /*
535   * This could have a good default implementation of {@code return new
536   * ImmutableMapValues<K, V>(this)}, but ProGuard can't figure out how to eliminate that default
537   * when RegularImmutableMap overrides it.
538   */
539  abstract ImmutableCollection<V> createValues();
540
541  // cached so that this.multimapView().inverse() only computes inverse once
542  @LazyInit private transient ImmutableSetMultimap<K, V> multimapView;
543
544  /**
545   * Returns a multimap view of the map.
546   *
547   * @since 14.0
548   */
549  public ImmutableSetMultimap<K, V> asMultimap() {
550    if (isEmpty()) {
551      return ImmutableSetMultimap.of();
552    }
553    ImmutableSetMultimap<K, V> result = multimapView;
554    return (result == null)
555        ? (multimapView =
556            new ImmutableSetMultimap<>(new MapViewOfValuesAsSingletonSets(), size(), null))
557        : result;
558  }
559
560  @WeakOuter
561  private final class MapViewOfValuesAsSingletonSets
562      extends IteratorBasedImmutableMap<K, ImmutableSet<V>> {
563
564    @Override
565    public int size() {
566      return ImmutableMap.this.size();
567    }
568
569    @Override
570    ImmutableSet<K> createKeySet() {
571      return ImmutableMap.this.keySet();
572    }
573
574    @Override
575    public boolean containsKey(@Nullable Object key) {
576      return ImmutableMap.this.containsKey(key);
577    }
578
579    @Override
580    public ImmutableSet<V> get(@Nullable Object key) {
581      V outerValue = ImmutableMap.this.get(key);
582      return (outerValue == null) ? null : ImmutableSet.of(outerValue);
583    }
584
585    @Override
586    boolean isPartialView() {
587      return ImmutableMap.this.isPartialView();
588    }
589
590    @Override
591    public int hashCode() {
592      // ImmutableSet.of(value).hashCode() == value.hashCode(), so the hashes are the same
593      return ImmutableMap.this.hashCode();
594    }
595
596    @Override
597    boolean isHashCodeFast() {
598      return ImmutableMap.this.isHashCodeFast();
599    }
600
601    @Override
602    UnmodifiableIterator<Entry<K, ImmutableSet<V>>> entryIterator() {
603      final Iterator<Entry<K, V>> backingIterator = ImmutableMap.this.entrySet().iterator();
604      return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
605        @Override
606        public boolean hasNext() {
607          return backingIterator.hasNext();
608        }
609
610        @Override
611        public Entry<K, ImmutableSet<V>> next() {
612          final Entry<K, V> backingEntry = backingIterator.next();
613          return new AbstractMapEntry<K, ImmutableSet<V>>() {
614            @Override
615            public K getKey() {
616              return backingEntry.getKey();
617            }
618
619            @Override
620            public ImmutableSet<V> getValue() {
621              return ImmutableSet.of(backingEntry.getValue());
622            }
623          };
624        }
625      };
626    }
627  }
628
629  @Override
630  public boolean equals(@Nullable Object object) {
631    return Maps.equalsImpl(this, object);
632  }
633
634  abstract boolean isPartialView();
635
636  @Override
637  public int hashCode() {
638    return Sets.hashCodeImpl(entrySet());
639  }
640
641  boolean isHashCodeFast() {
642    return false;
643  }
644
645  @Override
646  public String toString() {
647    return Maps.toStringImpl(this);
648  }
649
650  /**
651   * Serialized type for all ImmutableMap instances. It captures the logical contents and they are
652   * reconstructed using public factory methods. This ensures that the implementation types remain
653   * as implementation details.
654   */
655  static class SerializedForm implements Serializable {
656    private final Object[] keys;
657    private final Object[] values;
658
659    SerializedForm(ImmutableMap<?, ?> map) {
660      keys = new Object[map.size()];
661      values = new Object[map.size()];
662      int i = 0;
663      for (Entry<?, ?> entry : map.entrySet()) {
664        keys[i] = entry.getKey();
665        values[i] = entry.getValue();
666        i++;
667      }
668    }
669
670    Object readResolve() {
671      Builder<Object, Object> builder = new Builder<>(keys.length);
672      return createMap(builder);
673    }
674
675    Object createMap(Builder<Object, Object> builder) {
676      for (int i = 0; i < keys.length; i++) {
677        builder.put(keys[i], values[i]);
678      }
679      return builder.build();
680    }
681
682    private static final long serialVersionUID = 0;
683  }
684
685  Object writeReplace() {
686    return new SerializedForm(this);
687  }
688}