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