• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.util.EnumMap;
25 import java.util.Map;
26 
27 /**
28  * A {@code BiMap} backed by two {@code EnumMap} instances. Null keys and values
29  * are not permitted. An {@code EnumBiMap} and its inverse are both
30  * serializable.
31  *
32  * @author Mike Bostock
33  * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
34  */
35 public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>>
36     extends AbstractBiMap<K, V> {
37   private transient Class<K> keyType;
38   private transient Class<V> valueType;
39 
40   /**
41    * Returns a new, empty {@code EnumBiMap} using the specified key and value
42    * types.
43    *
44    * @param keyType the key type
45    * @param valueType the value type
46    */
47   public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V>
create(Class<K> keyType, Class<V> valueType)48       create(Class<K> keyType, Class<V> valueType) {
49     return new EnumBiMap<K, V>(keyType, valueType);
50   }
51 
52   /**
53    * Returns a new bimap with the same mappings as the specified map. If the
54    * specified map is an {@code EnumBiMap}, the new bimap has the same types as
55    * the provided map. Otherwise, the specified map must contain at least one
56    * mapping, in order to determine the key and value types.
57    *
58    * @param map the map whose mappings are to be placed in this map
59    * @throws IllegalArgumentException if map is not an {@code EnumBiMap}
60    *     instance and contains no mappings
61    */
62   public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V>
create(Map<K, V> map)63       create(Map<K, V> map) {
64     EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map));
65     bimap.putAll(map);
66     return bimap;
67   }
68 
EnumBiMap(Class<K> keyType, Class<V> valueType)69   private EnumBiMap(Class<K> keyType, Class<V> valueType) {
70     super(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
71     this.keyType = keyType;
72     this.valueType = valueType;
73   }
74 
inferKeyType(Map<K, ?> map)75   static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) {
76     if (map instanceof EnumBiMap) {
77       return ((EnumBiMap<K, ?>) map).keyType();
78     }
79     if (map instanceof EnumHashBiMap) {
80       return ((EnumHashBiMap<K, ?>) map).keyType();
81     }
82     checkArgument(!map.isEmpty());
83     return map.keySet().iterator().next().getDeclaringClass();
84   }
85 
inferValueType(Map<?, V> map)86   private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) {
87     if (map instanceof EnumBiMap) {
88       return ((EnumBiMap<?, V>) map).valueType;
89     }
90     checkArgument(!map.isEmpty());
91     return map.values().iterator().next().getDeclaringClass();
92   }
93 
94   /** Returns the associated key type. */
keyType()95   public Class<K> keyType() {
96     return keyType;
97   }
98 
99   /** Returns the associated value type. */
valueType()100   public Class<V> valueType() {
101     return valueType;
102   }
103 
104   /**
105    * @serialData the key class, value class, number of entries, first key, first
106    *     value, second key, second value, and so on.
107    */
writeObject(ObjectOutputStream stream)108   private void writeObject(ObjectOutputStream stream) throws IOException {
109     stream.defaultWriteObject();
110     stream.writeObject(keyType);
111     stream.writeObject(valueType);
112     Serialization.writeMap(this, stream);
113   }
114 
115   @SuppressWarnings("unchecked") // reading fields populated by writeObject
readObject(ObjectInputStream stream)116   private void readObject(ObjectInputStream stream)
117       throws IOException, ClassNotFoundException {
118     stream.defaultReadObject();
119     keyType = (Class<K>) stream.readObject();
120     valueType = (Class<V>) stream.readObject();
121     setDelegates(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
122     Serialization.populateMap(this, stream);
123   }
124 
125   private static final long serialVersionUID = 0;
126 }
127