001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * 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, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package java.util;
017:
018: /**
019: * A {@link java.util.Map} of {@link Enum}s. <a
020: * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumMap.html">[Sun
021: * docs]</a>
022: *
023: * @param <K> key type
024: * @param <V> value type
025: */
026: public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> {
027:
028: private class EntrySet extends AbstractSet<Entry<K, V>> {
029:
030: public Iterator<Map.Entry<K, V>> iterator() {
031: return new Iterator<Entry<K, V>>() {
032: Iterator<K> it = keySet.iterator();
033:
034: K key;
035:
036: public boolean hasNext() {
037: return it.hasNext();
038: }
039:
040: public Entry<K, V> next() {
041: key = it.next();
042: return new MapEntryImpl<K, V>(key, values.get(key
043: .ordinal()));
044: }
045:
046: public void remove() {
047: if (key == null) {
048: throw new IllegalStateException(
049: "No current value");
050: }
051: EnumMap.this .remove(key);
052: key = null;
053: }
054: };
055: }
056:
057: public int size() {
058: return keySet.size();
059: }
060: }
061:
062: K[] allEnums;
063:
064: EnumSet<K> keySet;
065:
066: ArrayList<V> values;
067:
068: public EnumMap(Class<K> type) {
069: init(type);
070: }
071:
072: public EnumMap(EnumMap<K, ? extends V> m) {
073: init(m);
074: }
075:
076: public EnumMap(Map<K, ? extends V> m) {
077: if (m instanceof EnumMap) {
078: init((EnumMap<K, ? extends V>) m);
079: } else {
080: if (m.isEmpty()) {
081: throw new IllegalArgumentException(
082: "The map must not be empty.");
083: }
084: init(m.keySet().iterator().next().getDeclaringClass());
085: putAll(m);
086: }
087: }
088:
089: @Override
090: public void clear() {
091: keySet.clear();
092: Collections.fill(values, null);
093: }
094:
095: public EnumMap<K, V> clone() {
096: return new EnumMap<K, V>(this );
097: }
098:
099: @Override
100: public boolean containsKey(Object key) {
101: return keySet.contains(key);
102: }
103:
104: @Override
105: public boolean containsValue(Object value) {
106: if (value != null) {
107: return values.contains(value);
108: }
109:
110: for (int i = 0, n = values.size(); i < n; ++i) {
111: V v = values.get(i);
112: if (v == null && keySet.contains(allEnums[i])) {
113: return true;
114: }
115: }
116: return false;
117: }
118:
119: @Override
120: public Set<Map.Entry<K, V>> entrySet() {
121: return new EntrySet();
122: }
123:
124: @Override
125: public boolean equals(Object o) {
126: if (!(o instanceof EnumMap)) {
127: return super .equals(o);
128: }
129:
130: EnumMap<?, ?> enumMap = (EnumMap<?, ?>) o;
131: return keySet.equals(enumMap.keySet())
132: && values.equals(enumMap.values());
133: }
134:
135: @Override
136: public V get(Object k) {
137: return keySet.contains(k) ? values.get(asKey(k).ordinal())
138: : null;
139: }
140:
141: @Override
142: public V put(K key, V value) {
143: keySet.add(key);
144: return values.set(key.ordinal(), value);
145: }
146:
147: @Override
148: public V remove(Object key) {
149: return keySet.remove(key) ? values.set(asKey(key).ordinal(),
150: null) : null;
151: }
152:
153: @Override
154: public int size() {
155: return keySet.size();
156: }
157:
158: /**
159: * Returns <code>key</code> as <code>K</code>. Doesn't actually perform
160: * any runtime checks. Should only be called when you are sure
161: * <code>key</code> is of type <code>K</code>.
162: */
163: @SuppressWarnings("unchecked")
164: private K asKey(Object key) {
165: return (K) key;
166: }
167:
168: private void init(Class<K> type) {
169: allEnums = type.getEnumConstants();
170: keySet = EnumSet.noneOf(type);
171: int length = allEnums.length;
172: values = new ArrayList<V>(length);
173: for (int i = 0; i < length; ++i) {
174: values.add(null);
175: }
176: }
177:
178: private void init(EnumMap<K, ? extends V> m) {
179: allEnums = m.allEnums;
180: keySet = m.keySet.clone();
181: values = new ArrayList<V>(m.values);
182: }
183: }
|