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.collect.CollectPreconditions.checkNonnegative;
020
021import com.google.common.annotations.Beta;
022import com.google.common.annotations.GwtCompatible;
023import com.google.errorprone.annotations.CanIgnoreReturnValue;
024import java.util.Arrays;
025import java.util.Comparator;
026import java.util.Map;
027import java.util.function.Function;
028import java.util.stream.Collector;
029import java.util.stream.Collectors;
030
031/**
032 * A {@link BiMap} whose contents will never change, with many other important properties detailed
033 * at {@link ImmutableCollection}.
034 *
035 * @author Jared Levy
036 * @since 2.0
037 */
038@GwtCompatible(serializable = true, emulated = true)
039public abstract class ImmutableBiMap<K, V> extends ImmutableBiMapFauxverideShim<K, V>
040    implements BiMap<K, V> {
041
042  /**
043   * Returns a {@link Collector} that accumulates elements into an {@code ImmutableBiMap} whose keys
044   * and values are the result of applying the provided mapping functions to the input elements.
045   * Entries appear in the result {@code ImmutableBiMap} in encounter order.
046   *
047   * <p>If the mapped keys or values contain duplicates (according to {@link Object#equals(Object)},
048   * an {@code IllegalArgumentException} is thrown when the collection operation is performed. (This
049   * differs from the {@code Collector} returned by {@link Collectors#toMap(Function, Function)},
050   * which throws an {@code IllegalStateException}.)
051   *
052   * @since 21.0
053   */
054  @Beta
055  public static <T, K, V> Collector<T, ?, ImmutableBiMap<K, V>> toImmutableBiMap(
056      Function<? super T, ? extends K> keyFunction,
057      Function<? super T, ? extends V> valueFunction) {
058    return CollectCollectors.toImmutableBiMap(keyFunction, valueFunction);
059  }
060
061  /** Returns the empty bimap. */
062  // Casting to any type is safe because the set will never hold any elements.
063  @SuppressWarnings("unchecked")
064  public static <K, V> ImmutableBiMap<K, V> of() {
065    return (ImmutableBiMap<K, V>) RegularImmutableBiMap.EMPTY;
066  }
067
068  /** Returns an immutable bimap containing a single entry. */
069  public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
070    return new SingletonImmutableBiMap<>(k1, v1);
071  }
072
073  /**
074   * Returns an immutable map containing the given entries, in order.
075   *
076   * @throws IllegalArgumentException if duplicate keys or values are added
077   */
078  public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
079    return RegularImmutableBiMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2));
080  }
081
082  /**
083   * Returns an immutable map containing the given entries, in order.
084   *
085   * @throws IllegalArgumentException if duplicate keys or values are added
086   */
087  public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
088    return RegularImmutableBiMap.fromEntries(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
089  }
090
091  /**
092   * Returns an immutable map containing the given entries, in order.
093   *
094   * @throws IllegalArgumentException if duplicate keys or values are added
095   */
096  public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
097    return RegularImmutableBiMap.fromEntries(
098        entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
099  }
100
101  /**
102   * Returns an immutable map containing the given entries, in order.
103   *
104   * @throws IllegalArgumentException if duplicate keys or values are added
105   */
106  public static <K, V> ImmutableBiMap<K, V> of(
107      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
108    return RegularImmutableBiMap.fromEntries(
109        entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5));
110  }
111
112  // looking for of() with > 5 entries? Use the builder instead.
113
114  /**
115   * Returns a new builder. The generated builder is equivalent to the builder created by the {@link
116   * Builder} constructor.
117   */
118  public static <K, V> Builder<K, V> builder() {
119    return new Builder<>();
120  }
121
122  /**
123   * Returns a new builder, expecting the specified number of entries to be added.
124   *
125   * <p>If {@code expectedSize} is exactly the number of entries added to the builder before {@link
126   * Builder#build} is called, the builder is likely to perform better than an unsized {@link
127   * #builder()} would have.
128   *
129   * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to,
130   * but not exactly, the number of entries added to the builder.
131   *
132   * @since 23.1
133   */
134  @Beta
135  public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) {
136    checkNonnegative(expectedSize, "expectedSize");
137    return new Builder<>(expectedSize);
138  }
139
140  /**
141   * A builder for creating immutable bimap instances, especially {@code public static final} bimaps
142   * ("constant bimaps"). Example:
143   *
144   * <pre>{@code
145   * static final ImmutableBiMap<String, Integer> WORD_TO_INT =
146   *     new ImmutableBiMap.Builder<String, Integer>()
147   *         .put("one", 1)
148   *         .put("two", 2)
149   *         .put("three", 3)
150   *         .build();
151   * }</pre>
152   *
153   * <p>For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods are even more
154   * convenient.
155   *
156   * <p>By default, a {@code Builder} will generate bimaps that iterate over entries in the order
157   * they were inserted into the builder. For example, in the above example, {@code
158   * WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the order {@code "one"=1,
159   * "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect the same order. If you
160   * want a different order, consider using {@link #orderEntriesByValue(Comparator)}, which changes
161   * this builder to sort entries by value.
162   *
163   * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build
164   * multiple bimaps in series. Each bimap is a superset of the bimaps created before it.
165   *
166   * @since 2.0
167   */
168  public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
169
170    /**
171     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
172     * ImmutableBiMap#builder}.
173     */
174    public Builder() {}
175
176    Builder(int size) {
177      super(size);
178    }
179
180    /**
181     * Associates {@code key} with {@code value} in the built bimap. Duplicate keys or values are
182     * not allowed, and will cause {@link #build} to fail.
183     */
184    @CanIgnoreReturnValue
185    @Override
186    public Builder<K, V> put(K key, V value) {
187      super.put(key, value);
188      return this;
189    }
190
191    /**
192     * Adds the given {@code entry} to the bimap. Duplicate keys or values are not allowed, and will
193     * cause {@link #build} to fail.
194     *
195     * @since 19.0
196     */
197    @CanIgnoreReturnValue
198    @Override
199    public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
200      super.put(entry);
201      return this;
202    }
203
204    /**
205     * Associates all of the given map's keys and values in the built bimap. Duplicate keys or
206     * values are not allowed, and will cause {@link #build} to fail.
207     *
208     * @throws NullPointerException if any key or value in {@code map} is null
209     */
210    @CanIgnoreReturnValue
211    @Override
212    public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
213      super.putAll(map);
214      return this;
215    }
216
217    /**
218     * Adds all of the given entries to the built bimap. Duplicate keys or values are not allowed,
219     * and will cause {@link #build} to fail.
220     *
221     * @throws NullPointerException if any key, value, or entry is null
222     * @since 19.0
223     */
224    @CanIgnoreReturnValue
225    @Beta
226    @Override
227    public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) {
228      super.putAll(entries);
229      return this;
230    }
231
232    /**
233     * Configures this {@code Builder} to order entries by value according to the specified
234     * comparator.
235     *
236     * <p>The sort order is stable, that is, if two entries have values that compare as equivalent,
237     * the entry that was inserted first will be first in the built map's iteration order.
238     *
239     * @throws IllegalStateException if this method was already called
240     * @since 19.0
241     */
242    @CanIgnoreReturnValue
243    @Beta
244    @Override
245    public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) {
246      super.orderEntriesByValue(valueComparator);
247      return this;
248    }
249
250    @Override
251    @CanIgnoreReturnValue
252    Builder<K, V> combine(ImmutableMap.Builder<K, V> builder) {
253      super.combine(builder);
254      return this;
255    }
256
257    /**
258     * Returns a newly-created immutable bimap. The iteration order of the returned bimap is the
259     * order in which entries were inserted into the builder, unless {@link #orderEntriesByValue}
260     * was called, in which case entries are sorted by value.
261     *
262     * @throws IllegalArgumentException if duplicate keys or values were added
263     */
264    @Override
265    public ImmutableBiMap<K, V> build() {
266      switch (size) {
267        case 0:
268          return of();
269        case 1:
270          return of(entries[0].getKey(), entries[0].getValue());
271        default:
272          /*
273           * If entries is full, then this implementation may end up using the entries array
274           * directly and writing over the entry objects with non-terminal entries, but this is
275           * safe; if this Builder is used further, it will grow the entries array (so it can't
276           * affect the original array), and future build() calls will always copy any entry
277           * objects that cannot be safely reused.
278           */
279          if (valueComparator != null) {
280            if (entriesUsed) {
281              entries = Arrays.copyOf(entries, size);
282            }
283            Arrays.sort(
284                entries,
285                0,
286                size,
287                Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction()));
288          }
289          entriesUsed = size == entries.length;
290          return RegularImmutableBiMap.fromEntryArray(size, entries);
291      }
292    }
293  }
294
295  /**
296   * Returns an immutable bimap containing the same entries as {@code map}. If {@code map} somehow
297   * contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose
298   * comparator is not <i>consistent with equals</i>), the results of this method are undefined.
299   *
300   * <p>The returned {@code BiMap} iterates over entries in the same order as the {@code entrySet}
301   * of the original map.
302   *
303   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
304   * safe to do so. The exact circumstances under which a copy will or will not be performed are
305   * undocumented and subject to change.
306   *
307   * @throws IllegalArgumentException if two keys have the same value or two values have the same
308   *     key
309   * @throws NullPointerException if any key or value in {@code map} is null
310   */
311  public static <K, V> ImmutableBiMap<K, V> copyOf(Map<? extends K, ? extends V> map) {
312    if (map instanceof ImmutableBiMap) {
313      @SuppressWarnings("unchecked") // safe since map is not writable
314      ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
315      // TODO(lowasser): if we need to make a copy of a BiMap because the
316      // forward map is a view, don't make a copy of the non-view delegate map
317      if (!bimap.isPartialView()) {
318        return bimap;
319      }
320    }
321    return copyOf(map.entrySet());
322  }
323
324  /**
325   * Returns an immutable bimap containing the given entries. The returned bimap iterates over
326   * entries in the same order as the original iterable.
327   *
328   * @throws IllegalArgumentException if two keys have the same value or two values have the same
329   *     key
330   * @throws NullPointerException if any key, value, or entry is null
331   * @since 19.0
332   */
333  @Beta
334  public static <K, V> ImmutableBiMap<K, V> copyOf(
335      Iterable<? extends Entry<? extends K, ? extends V>> entries) {
336    @SuppressWarnings("unchecked") // we'll only be using getKey and getValue, which are covariant
337    Entry<K, V>[] entryArray = (Entry<K, V>[]) Iterables.toArray(entries, EMPTY_ENTRY_ARRAY);
338    switch (entryArray.length) {
339      case 0:
340        return of();
341      case 1:
342        Entry<K, V> entry = entryArray[0];
343        return of(entry.getKey(), entry.getValue());
344      default:
345        /*
346         * The current implementation will end up using entryArray directly, though it will write
347         * over the (arbitrary, potentially mutable) Entry objects actually stored in entryArray.
348         */
349        return RegularImmutableBiMap.fromEntries(entryArray);
350    }
351  }
352
353  ImmutableBiMap() {}
354
355  /**
356   * {@inheritDoc}
357   *
358   * <p>The inverse of an {@code ImmutableBiMap} is another {@code ImmutableBiMap}.
359   */
360  @Override
361  public abstract ImmutableBiMap<V, K> inverse();
362
363  /**
364   * Returns an immutable set of the values in this map, in the same order they appear in {@link
365   * #entrySet}.
366   */
367  @Override
368  public ImmutableSet<V> values() {
369    return inverse().keySet();
370  }
371
372  @Override
373  final ImmutableSet<V> createValues() {
374    throw new AssertionError("should never be called");
375  }
376
377  /**
378   * Guaranteed to throw an exception and leave the bimap unmodified.
379   *
380   * @throws UnsupportedOperationException always
381   * @deprecated Unsupported operation.
382   */
383  @CanIgnoreReturnValue
384  @Deprecated
385  @Override
386  public V forcePut(K key, V value) {
387    throw new UnsupportedOperationException();
388  }
389
390  /**
391   * Serialized type for all ImmutableBiMap instances. It captures the logical contents and they are
392   * reconstructed using public factory methods. This ensures that the implementation types remain
393   * as implementation details.
394   *
395   * <p>Since the bimap is immutable, ImmutableBiMap doesn't require special logic for keeping the
396   * bimap and its inverse in sync during serialization, the way AbstractBiMap does.
397   */
398  private static class SerializedForm extends ImmutableMap.SerializedForm {
399    SerializedForm(ImmutableBiMap<?, ?> bimap) {
400      super(bimap);
401    }
402
403    @Override
404    Object readResolve() {
405      Builder<Object, Object> builder = new Builder<>();
406      return createMap(builder);
407    }
408
409    private static final long serialVersionUID = 0;
410  }
411
412  @Override
413  Object writeReplace() {
414    return new SerializedForm(this);
415  }
416}