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;
020
021import com.google.common.annotations.GwtCompatible;
022
023import java.util.Collection;
024import java.util.Map;
025
026/**
027 * An immutable {@link BiMap} with reliable user-specified iteration order. Does
028 * not permit null keys or values. An {@code ImmutableBiMap} and its inverse
029 * have the same iteration ordering.
030 *
031 * <p>An instance of {@code ImmutableBiMap} contains its own data and will
032 * <i>never</i> change. {@code ImmutableBiMap} is convenient for
033 * {@code public static final} maps ("constant maps") and also lets you easily
034 * make a "defensive copy" of a bimap provided to your class by a caller.
035 *
036 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
037 * it has no public or protected constructors. Thus, instances of this class are
038 * guaranteed to be immutable.
039 *
040 * @author Jared Levy
041 * @since 2.0 (imported from Google Collections Library)
042 */
043@GwtCompatible(serializable = true, emulated = true)
044public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
045    implements BiMap<K, V> {
046
047  /**
048   * Returns the empty bimap.
049   */
050  // Casting to any type is safe because the set will never hold any elements.
051  @SuppressWarnings("unchecked")
052  public static <K, V> ImmutableBiMap<K, V> of() {
053    return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
054  }
055
056  /**
057   * Returns an immutable bimap containing a single entry.
058   */
059  public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
060    checkNotNull(k1, "null key in entry: null=%s", v1);
061    checkNotNull(v1, "null value in entry: %s=null", k1);
062    return new SingletonImmutableBiMap<K, V>(k1, v1);
063  }
064
065  /**
066   * Returns an immutable map containing the given entries, in order.
067   *
068   * @throws IllegalArgumentException if duplicate keys or values are added
069   */
070  public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
071    return new Builder<K, V>()
072        .put(k1, v1)
073        .put(k2, v2)
074        .build();
075  }
076
077  /**
078   * Returns an immutable map containing the given entries, in order.
079   *
080   * @throws IllegalArgumentException if duplicate keys or values are added
081   */
082  public static <K, V> ImmutableBiMap<K, V> of(
083      K k1, V v1, K k2, V v2, K k3, V v3) {
084    return new Builder<K, V>()
085        .put(k1, v1)
086        .put(k2, v2)
087        .put(k3, v3)
088        .build();
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(
097      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
098    return new Builder<K, V>()
099        .put(k1, v1)
100        .put(k2, v2)
101        .put(k3, v3)
102        .put(k4, v4)
103        .build();
104  }
105
106  /**
107   * Returns an immutable map containing the given entries, in order.
108   *
109   * @throws IllegalArgumentException if duplicate keys or values are added
110   */
111  public static <K, V> ImmutableBiMap<K, V> of(
112      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
113    return new Builder<K, V>()
114        .put(k1, v1)
115        .put(k2, v2)
116        .put(k3, v3)
117        .put(k4, v4)
118        .put(k5, v5)
119        .build();
120  }
121
122  // looking for of() with > 5 entries? Use the builder instead.
123
124  /**
125   * Returns a new builder. The generated builder is equivalent to the builder
126   * created by the {@link Builder} constructor.
127   */
128  public static <K, V> Builder<K, V> builder() {
129    return new Builder<K, V>();
130  }
131
132  /**
133   * A builder for creating immutable bimap instances, especially {@code public
134   * static final} bimaps ("constant bimaps"). Example: <pre>   {@code
135   *
136   *   static final ImmutableBiMap<String, Integer> WORD_TO_INT =
137   *       new ImmutableBiMap.Builder<String, Integer>()
138   *           .put("one", 1)
139   *           .put("two", 2)
140   *           .put("three", 3)
141   *           .build();}</pre>
142   *
143   * For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods
144   * are even more convenient.
145   *
146   * <p>Builder instances can be reused - it is safe to call {@link #build}
147   * multiple times to build multiple bimaps in series. Each bimap is a superset
148   * of the bimaps created before it.
149   *
150   * @since 2.0 (imported from Google Collections Library)
151   */
152  public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
153
154    /**
155     * Creates a new builder. The returned builder is equivalent to the builder
156     * generated by {@link ImmutableBiMap#builder}.
157     */
158    public Builder() {}
159
160    /**
161     * Associates {@code key} with {@code value} in the built bimap. Duplicate
162     * keys or values are not allowed, and will cause {@link #build} to fail.
163     */
164    @Override public Builder<K, V> put(K key, V value) {
165      super.put(key, value);
166      return this;
167    }
168
169    /**
170     * Associates all of the given map's keys and values in the built bimap.
171     * Duplicate keys or values are not allowed, and will cause {@link #build}
172     * to fail.
173     *
174     * @throws NullPointerException if any key or value in {@code map} is null
175     */
176    @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
177      super.putAll(map);
178      return this;
179    }
180
181    /**
182     * Returns a newly-created immutable bimap.
183     *
184     * @throws IllegalArgumentException if duplicate keys or values were added
185     */
186    @Override public ImmutableBiMap<K, V> build() {
187      return fromEntries(entries);
188    }
189  }
190
191  /**
192   * Returns an immutable bimap containing the same entries as {@code map}. If
193   * {@code map} somehow contains entries with duplicate keys (for example, if
194   * it is a {@code SortedMap} whose comparator is not <i>consistent with
195   * equals</i>), the results of this method are undefined.
196   *
197   * <p>Despite the method name, this method attempts to avoid actually copying
198   * the data when it is safe to do so. The exact circumstances under which a
199   * copy will or will not be performed are undocumented and subject to change.
200   *
201   * @throws IllegalArgumentException if two keys have the same value
202   * @throws NullPointerException if any key or value in {@code map} is null
203   */
204  public static <K, V> ImmutableBiMap<K, V> copyOf(
205      Map<? extends K, ? extends V> map) {
206    if (map instanceof ImmutableBiMap) {
207      @SuppressWarnings("unchecked") // safe since map is not writable
208      ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
209      // TODO(user): if we need to make a copy of a BiMap because the
210      // forward map is a view, don't make a copy of the non-view delegate map
211      if (!bimap.isPartialView()) {
212        return bimap;
213      }
214    }
215
216    return fromEntries(ImmutableList.copyOf(map.entrySet()));
217  }
218
219  static <K, V> ImmutableBiMap<K, V> fromEntries(
220      Collection<? extends Entry<? extends K, ? extends V>> entries) {
221    switch (entries.size()) {
222      case 0:
223        return of();
224      case 1: {
225        Entry<? extends K, ? extends V> entry = Iterables.getOnlyElement(entries);
226        return new SingletonImmutableBiMap<K, V>(entry.getKey(), entry.getValue());
227      }
228      default:
229        return new RegularImmutableBiMap<K, V>(entries);
230    }
231  }
232
233  ImmutableBiMap() {}
234
235  /**
236   * {@inheritDoc}
237   *
238   * <p>The inverse of an {@code ImmutableBiMap} is another
239   * {@code ImmutableBiMap}.
240   */
241  @Override
242  public abstract ImmutableBiMap<V, K> inverse();
243
244  /**
245   * Returns an immutable set of the values in this map. The values are in the
246   * same order as the parameters used to build this map.
247   */
248  @Override public ImmutableSet<V> values() {
249    return inverse().keySet();
250  }
251
252  /**
253   * Guaranteed to throw an exception and leave the bimap unmodified.
254   *
255   * @throws UnsupportedOperationException always
256   * @deprecated Unsupported operation.
257   */
258  @Deprecated
259  @Override
260  public V forcePut(K key, V value) {
261    throw new UnsupportedOperationException();
262  }
263
264  /**
265   * Serialized type for all ImmutableBiMap instances. It captures the logical
266   * contents and they are reconstructed using public factory methods. This
267   * ensures that the implementation types remain as implementation details.
268   *
269   * Since the bimap is immutable, ImmutableBiMap doesn't require special logic
270   * for keeping the bimap and its inverse in sync during serialization, the way
271   * AbstractBiMap does.
272   */
273  private static class SerializedForm extends ImmutableMap.SerializedForm {
274    SerializedForm(ImmutableBiMap<?, ?> bimap) {
275      super(bimap);
276    }
277    @Override Object readResolve() {
278      Builder<Object, Object> builder = new Builder<Object, Object>();
279      return createMap(builder);
280    }
281    private static final long serialVersionUID = 0;
282  }
283
284  @Override Object writeReplace() {
285    return new SerializedForm(this);
286  }
287}