summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/util/EnumMap.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/java/util/EnumMap.java')
-rw-r--r--libjava/classpath/java/util/EnumMap.java405
1 files changed, 405 insertions, 0 deletions
diff --git a/libjava/classpath/java/util/EnumMap.java b/libjava/classpath/java/util/EnumMap.java
new file mode 100644
index 000000000..78f05002f
--- /dev/null
+++ b/libjava/classpath/java/util/EnumMap.java
@@ -0,0 +1,405 @@
+/* EnumMap.java - Map where keys are enum constants
+ Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.util;
+
+import java.io.Serializable;
+
+/**
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+
+public class EnumMap<K extends Enum<K>, V>
+ extends AbstractMap<K, V>
+ implements Cloneable, Serializable
+{
+ private static final long serialVersionUID = 458661240069192865L;
+
+ V[] store;
+ int cardinality;
+ Class<K> enumClass;
+
+ /**
+ * The cache for {@link #entrySet()}.
+ */
+ transient Set<Map.Entry<K, V>> entries;
+
+ static final Object emptySlot = new Object();
+
+ public EnumMap(Class<K> keyType)
+ {
+ store = (V[]) new Object[keyType.getEnumConstants().length];
+ Arrays.fill(store, emptySlot);
+ cardinality = 0;
+ enumClass = keyType;
+ }
+
+ public EnumMap(EnumMap<K, ? extends V> map)
+ {
+ store = (V[]) map.store.clone();
+ cardinality = map.cardinality;
+ enumClass = map.enumClass;
+ }
+
+ public EnumMap(Map<K, ? extends V> map)
+ {
+ if (map instanceof EnumMap)
+ {
+ EnumMap<K, ? extends V> other = (EnumMap<K, ? extends V>) map;
+ store = (V[]) other.store.clone();
+ cardinality = other.cardinality;
+ enumClass = other.enumClass;
+ }
+ else
+ {
+ for (K key : map.keySet())
+ {
+ V value = map.get(key);
+ if (store == null)
+ {
+ enumClass = key.getDeclaringClass();
+ store = (V[]) new Object[enumClass.getEnumConstants().length];
+ }
+ int o = key.ordinal();
+ if (store[o] == emptySlot)
+ ++cardinality;
+ store[o] = value;
+ }
+ // There must be a single element.
+ if (store == null)
+ throw new IllegalArgumentException("no elements in map");
+ }
+ }
+
+ public int size()
+ {
+ return cardinality;
+ }
+
+ public boolean containsValue(Object value)
+ {
+ for (V i : store)
+ {
+ if (i != emptySlot && AbstractCollection.equals(i , value))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean containsKey(Object key)
+ {
+ if (! (key instanceof Enum))
+ return false;
+ Enum<K> e = (Enum<K>) key;
+ if (e.getDeclaringClass() != enumClass)
+ return false;
+ return store[e.ordinal()] != emptySlot;
+ }
+
+ public V get(Object key)
+ {
+ if (! (key instanceof Enum))
+ return null;
+ Enum<K> e = (Enum<K>) key;
+ if (e.getDeclaringClass() != enumClass)
+ return null;
+ V o = store[e.ordinal()];
+ return o == emptySlot ? null : o;
+ }
+
+ public V put(K key, V value)
+ {
+ int o = key.ordinal();
+ V result;
+ if (store[o] == emptySlot)
+ {
+ result = null;
+ ++cardinality;
+ }
+ else
+ result = store[o];
+ store[o] = value;
+ return result;
+ }
+
+ public V remove(Object key)
+ {
+ if (! (key instanceof Enum))
+ return null;
+ Enum<K> e = (Enum<K>) key;
+ if (e.getDeclaringClass() != enumClass)
+ return null;
+ V result = store[e.ordinal()];
+ if (result == emptySlot)
+ result = null;
+ else
+ --cardinality;
+ store[e.ordinal()] = (V) emptySlot;
+ return result;
+ }
+
+ public void putAll(Map<? extends K, ? extends V> map)
+ {
+ for (K key : map.keySet())
+ {
+ V value = map.get(key);
+
+ int o = key.ordinal();
+ if (store[o] == emptySlot)
+ ++cardinality;
+ store[o] = value;
+ }
+ }
+
+ public void clear()
+ {
+ Arrays.fill(store, emptySlot);
+ cardinality = 0;
+ }
+
+ public Set<K> keySet()
+ {
+ if (keys == null)
+ {
+ keys = new AbstractSet<K>()
+ {
+ public int size()
+ {
+ return cardinality;
+ }
+
+ public Iterator<K> iterator()
+ {
+ return new Iterator<K>()
+ {
+ int count = 0;
+ int index = -1;
+
+ public boolean hasNext()
+ {
+ return count < cardinality;
+ }
+
+ public K next()
+ {
+ ++count;
+ for (++index; store[index] == emptySlot; ++index)
+ ;
+ return enumClass.getEnumConstants()[index];
+ }
+
+ public void remove()
+ {
+ --cardinality;
+ store[index] = (V) emptySlot;
+ }
+ };
+ }
+
+ public void clear()
+ {
+ EnumMap.this.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ return contains(o);
+ }
+
+ public boolean remove(Object o)
+ {
+ return EnumMap.this.remove(o) != null;
+ }
+ };
+ }
+ return keys;
+ }
+
+ public Collection<V> values()
+ {
+ if (values == null)
+ {
+ values = new AbstractCollection<V>()
+ {
+ public int size()
+ {
+ return cardinality;
+ }
+
+ public Iterator<V> iterator()
+ {
+ return new Iterator<V>()
+ {
+ int count = 0;
+ int index = -1;
+
+ public boolean hasNext()
+ {
+ return count < cardinality;
+ }
+
+ public V next()
+ {
+ ++count;
+ for (++index; store[index] == emptySlot; ++index)
+ ;
+ return store[index];
+ }
+
+ public void remove()
+ {
+ --cardinality;
+ store[index] = (V) emptySlot;
+ }
+ };
+ }
+
+ public void clear()
+ {
+ EnumMap.this.clear();
+ }
+ };
+ }
+ return values;
+ }
+
+ public Set<Map.Entry<K, V>> entrySet()
+ {
+ if (entries == null)
+ {
+ entries = new AbstractSet<Map.Entry<K, V>>()
+ {
+ public int size()
+ {
+ return cardinality;
+ }
+
+ public Iterator<Map.Entry<K, V>> iterator()
+ {
+ return new Iterator<Map.Entry<K, V>>()
+ {
+ int count = 0;
+ int index = -1;
+
+ public boolean hasNext()
+ {
+ return count < cardinality;
+ }
+
+ public Map.Entry<K,V> next()
+ {
+ ++count;
+ for (++index; store[index] == emptySlot; ++index)
+ ;
+ // FIXME: we could just return something that
+ // only knows the index. That would be cleaner.
+ return new AbstractMap.SimpleEntry<K, V>(enumClass.getEnumConstants()[index],
+ store[index])
+ {
+ public V setValue(V newVal)
+ {
+ value = newVal;
+ return put(key, newVal);
+ }
+ };
+ }
+
+ public void remove()
+ {
+ --cardinality;
+ store[index] = (V) emptySlot;
+ }
+ };
+ }
+
+ public void clear()
+ {
+ EnumMap.this.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ Map.Entry<K, V> other = (Map.Entry<K, V>) o;
+ return (containsKey(other.getKey())
+ && AbstractCollection.equals(get(other.getKey()),
+ other.getValue()));
+ }
+
+ public boolean remove(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ Map.Entry<K, V> other = (Map.Entry<K, V>) o;
+ return EnumMap.this.remove(other.getKey()) != null;
+ }
+ };
+ }
+ return entries;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (! (o instanceof EnumMap))
+ return false;
+ EnumMap<K, V> other = (EnumMap<K, V>) o;
+ if (other.enumClass != enumClass || other.cardinality != cardinality)
+ return false;
+ return Arrays.equals(store, other.store);
+ }
+
+ public EnumMap<K, V> clone()
+ {
+ EnumMap<K, V> result;
+ try
+ {
+ result = (EnumMap<K, V>) super.clone();
+ }
+ catch (CloneNotSupportedException ignore)
+ {
+ // Can't happen.
+ result = null;
+ }
+ result.store = (V[]) store.clone();
+ return result;
+ }
+
+}