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