1090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors 3090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 4090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * you may not use this file except in compliance with the License. 6090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * You may obtain a copy of the License at 7090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 8090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 10090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * See the License for the specific language governing permissions and 14090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * limitations under the License. 15090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 16090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 17090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpackage com.google.common.collect; 18090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 19090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport static com.google.common.base.Preconditions.checkArgument; 20090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtCompatible; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtIncompatible; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 24090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.io.IOException; 25090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.io.ObjectInputStream; 26090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.io.ObjectOutputStream; 27090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.EnumMap; 28090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.Map; 29090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 30090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/** 31090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * A {@code BiMap} backed by two {@code EnumMap} instances. Null keys and values 32090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * are not permitted. An {@code EnumBiMap} and its inverse are both 33090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * serializable. 34090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 35090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Mike Bostock 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 2.0 (imported from Google Collections Library) 37090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@GwtCompatible(emulated = true) 39090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpublic final class EnumBiMap<K extends Enum<K>, V extends Enum<V>> 40090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson extends AbstractBiMap<K, V> { 41090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private transient Class<K> keyType; 42090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private transient Class<V> valueType; 43090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 44090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 45090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns a new, empty {@code EnumBiMap} using the specified key and value 46090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * types. 47090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 48090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @param keyType the key type 49090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @param valueType the value type 50090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 51090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> 52090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson create(Class<K> keyType, Class<V> valueType) { 53090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new EnumBiMap<K, V>(keyType, valueType); 54090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 55090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 56090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 57090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Returns a new bimap with the same mappings as the specified map. If the 58090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * specified map is an {@code EnumBiMap}, the new bimap has the same types as 59090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * the provided map. Otherwise, the specified map must contain at least one 60090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * mapping, in order to determine the key and value types. 61090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 62090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @param map the map whose mappings are to be placed in this map 63090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @throws IllegalArgumentException if map is not an {@code EnumBiMap} 64090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * instance and contains no mappings 65090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 66090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> 67090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson create(Map<K, V> map) { 68090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map)); 69090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson bimap.putAll(map); 70090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return bimap; 71090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 72090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 73090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private EnumBiMap(Class<K> keyType, Class<V> valueType) { 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert super(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)), 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WellBehavedMap.wrap(new EnumMap<V, K>(valueType))); 76090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.keyType = keyType; 77090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.valueType = valueType; 78090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 79090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 80090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) { 81090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (map instanceof EnumBiMap) { 82090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return ((EnumBiMap<K, ?>) map).keyType(); 83090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 84090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (map instanceof EnumHashBiMap) { 85090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return ((EnumHashBiMap<K, ?>) map).keyType(); 86090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 87090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson checkArgument(!map.isEmpty()); 88090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return map.keySet().iterator().next().getDeclaringClass(); 89090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 90090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 91090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) { 92090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (map instanceof EnumBiMap) { 93090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return ((EnumBiMap<?, V>) map).valueType; 94090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 95090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson checkArgument(!map.isEmpty()); 96090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return map.values().iterator().next().getDeclaringClass(); 97090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 98090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 99090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** Returns the associated key type. */ 100090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Class<K> keyType() { 101090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return keyType; 102090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 103090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 104090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** Returns the associated value type. */ 105090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public Class<V> valueType() { 106090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return valueType; 107090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 108090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 109090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson /** 110090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @serialData the key class, value class, number of entries, first key, first 111090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * value, second key, second value, and so on. 112090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @GwtIncompatible("java.io.ObjectOutputStream") 114090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private void writeObject(ObjectOutputStream stream) throws IOException { 115090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson stream.defaultWriteObject(); 116090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson stream.writeObject(keyType); 117090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson stream.writeObject(valueType); 118090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Serialization.writeMap(this, stream); 119090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 120090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 121090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") // reading fields populated by writeObject 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @GwtIncompatible("java.io.ObjectInputStream") 123090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private void readObject(ObjectInputStream stream) 124090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throws IOException, ClassNotFoundException { 125090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson stream.defaultReadObject(); 126090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson keyType = (Class<K>) stream.readObject(); 127090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson valueType = (Class<V>) stream.readObject(); 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert setDelegates( 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WellBehavedMap.wrap(new EnumMap<K, V>(keyType)), 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WellBehavedMap.wrap(new EnumMap<V, K>(valueType))); 131090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Serialization.populateMap(this, stream); 132090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 133090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @GwtIncompatible("not needed in emulated source.") 135090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private static final long serialVersionUID = 0; 136090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson} 137