classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] [generics] Patch: FYI: EnumSet and EnumMap


From: Tom Tromey
Subject: [cp-patches] [generics] Patch: FYI: EnumSet and EnumMap
Date: 03 Sep 2004 14:40:14 -0600

I'm checking this in on the generics branch.

This is an implementation of EnumSet and EnumMap.
Not compiled or tested or documented, that stuff comes later.

Tom

Index: ChangeLog
from  Tom Tromey  <address@hidden>

        * java/util/EnumMap.java: New file.
        * java/util/EnumSet.java: New file.
        * java/util/BitSet.java (containsAll): New method.

Index: java/util/BitSet.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/util/BitSet.java,v
retrieving revision 1.13
diff -u -r1.13 BitSet.java
--- java/util/BitSet.java 30 Apr 2002 14:03:11 -0000 1.13
+++ java/util/BitSet.java 3 Sep 2004 20:53:32 -0000
@@ -1,5 +1,5 @@
 /* BitSet.java -- A vector of bits.
-   Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2004  Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -735,4 +735,15 @@
         bits = nd;
       }
   }
+
+  // This is used by EnumSet for efficiency.
+  final boolean containsAll(BitSet other)
+  {
+    for (int i = bs.bits.length - 1; i >= 0; i--)
+      {
+       if ((bits[i] & bs.bits[i]) != bs.bits[i])
+         return false;
+      }
+    return true;
+  }
 }
Index: java/util/EnumMap.java
===================================================================
RCS file: java/util/EnumMap.java
diff -N java/util/EnumMap.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/util/EnumMap.java 3 Sep 2004 20:53:33 -0000
@@ -0,0 +1,385 @@
+/* EnumMap.java - Map where keys are enum constants
+   Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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;
+
+/** @since 1.5 */
+public class EnumMap<K extends Enum<K>, V>
+  extends AbstractMap<K, V>
+  implements Cloneable, Serializable
+{
+  V[] store;
+  int cardinality;
+  Class<K> enumClass;
+
+  /**
+   * The cache for address@hidden #entrySet()}.
+   */
+  transient Set<Map.Entry<K, V>> entries;
+
+  static final Object emptySlot = new Object();
+
+  public EnumMap(Class<K> keyType)
+  {
+    store = new V[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<K, ? extends V>)
+      {
+       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 = new V[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<K>))
+      return false;
+    Enum<K> e = (Enum<K>) key;
+    if (e.enumClass != enumClass)
+      return false;
+    return store[e.ordinal()] != emptySlot;
+  }
+
+  public V get(Object key)
+  {
+    if (! (key instanceof Enum<K>))
+      return null;
+    Enum<K> e = (Enum<K>) key;
+    if (e.enumClass != enumClass)
+      return null;
+    return store[e.ordinal()];
+  }
+
+  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<K>))
+      return null;
+    Enum<K> e = (Enum<K>) key;
+    if (e.enumClass != enumClass)
+      return null;
+    V result = store[e.ordinal()];
+    if (result == emptySlot)
+      result = null;
+    else
+      --cardinality;
+    store[e.ordinal()] = 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] = 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);
+         }
+       };
+      }
+    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 K next()
+             {
+               ++count;
+               for (++index; store[index] == emptySlot; ++index)
+                 ;
+               return store[index];
+             }
+
+             public void remove()
+             {
+               --cardinality;
+               store[index] = 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 K 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.BasicMapEntry<K, 
V>(enumClass.getEnumConstants()[index],
+                                                          store[index])
+               {
+                 public V setValue(K newVal)
+                 {
+                   value = newVal;
+                   return put(key, newVal);
+                 }
+               };
+             }
+
+             public void remove()
+             {
+               --cardinality;
+               store[index] = emptySlot;
+             }
+           };
+         }
+
+         public void clear()
+         {
+           EnumMap.this.clear();
+         }
+
+         public boolean contains(Object o)
+         {
+           if (! (o instanceof Map.Entry<K, V>))
+             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<K, V>))
+             return false;
+           Map.Entry<K, V> other = (Map.Entry<K, V>) o;
+           return EnumMap.this.remove(other.getKey());
+         }
+       };
+      }
+    return entries;
+  }
+
+  public boolean equals(Object o)
+  {
+    if (! (o instanceof EnumMap<K, V>))
+      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> r = (EnumMap<K, V>) super.clone();
+    r.store = (V[]) store.clone();
+    return r;
+  }
+}
Index: java/util/EnumSet.java
===================================================================
RCS file: java/util/EnumSet.java
diff -N java/util/EnumSet.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/util/EnumSet.java 3 Sep 2004 20:53:33 -0000
@@ -0,0 +1,346 @@
+/* EnumSet.java - Set of enum objects
+   Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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;
+
+/** @since 1.5 */
+// FIXME: serialization is special.
+public class EnumSet<T extends Enum<T>>
+  extends AbstractSet<T>
+  implements Cloneable, Serializable
+{
+  BitSet store;
+  int cardinality;
+  Class<T> enumClass;
+
+  EnumSet()
+  {
+  }
+
+  public EnumSet<T> clone()
+  {
+    EnumSet<T> r = super.clone();
+    r.store = store.clone();
+    return r;
+  }
+
+  public int size()
+  {
+    return cardinality;
+  }
+
+  public Iterator<T> iterator()
+  {
+    return new Iterator<T>()
+    {
+      int next = -1;
+      int count = 0;
+
+      public boolean hasNext()
+      {
+       return count < cardinality;
+      }
+
+      public T next()
+      {
+       next = store.nextSetBit(next + 1);
+       ++count;
+       return enumClass.getEnumConstants()[next];
+      }
+
+      public void remove()
+      {
+       if (! store.get(next))
+         {
+           store.clear(next);
+           --cardinality;
+         }
+      }
+    };
+  }
+
+  public boolean add(T val)
+  {
+    if (store.get(val.ordinal()))
+      return false;
+    store.set(val.ordinal());
+    ++cardinality;
+    return true;
+  }
+
+  public boolean addAll(Collection<? extends T> c)
+  {
+    boolean result = false;
+    if (c instanceof EnumSet<T>)
+      {
+       EnumSet<T> other = (EnumSet<T>) c;
+       if (enumClass == other.enumClass)
+         {
+           store.or(other.store);
+           int save = cardinality;
+           cardinality = store.cardinality();
+           result = save != cardinality;
+         }
+      }
+    else
+      {
+       for (T val : c)
+         {
+           if (add (val))
+             result = true;
+         }
+      }
+    return result;
+  }
+
+  public void clear()
+  {
+    store.clear();
+    cardinality = 0;
+  }
+
+  public boolean contains(Object o)
+  {
+    if (! (o instanceof Enum<T>))
+      return false;
+    Enum<T> e = (Enum<T>) o;
+    if (e.getDeclaringClass() != enumClass)
+      return false;
+    return store.get(e.ordinal());
+  }
+
+  public boolean containsAll(Collection<?> c)
+  {
+    if (c instanceof EnumSet<T>)
+      {
+       EnumSet<T> other = (EnumSet<T>) c;
+       if (enumClass == other.enumClass)
+         return store.containsAll(other.store);
+       return false;
+      }
+    return super.containsAll(c);
+  }
+
+  public boolean remove(Object o)
+  {
+    if (! (o instanceof Enum<T>))
+      return false;
+    Enum<T> e = (Enum<T>) o;
+    if (e.getDeclaringClass() != enumClass)
+      return false;
+    store.clear(e.ordinal());
+    --cardinality;
+    return true;
+  }
+
+  public boolean removeAll(Collection<?> c)
+  {
+    if (c instanceof EnumSet<T>)
+      {
+       EnumSet<T> other = (EnumSet<T>) c;
+       if (enumClass != other.enumClass)
+         return false;
+       store.andNot(other.store);
+       int save = cardinality;
+       cardinality = store.cardinality();
+       return save != cardinality;
+      }
+    return super.removeAll(c);
+  }
+
+  public boolean retainAll(Collection<?> c)
+  {
+    if (c instanceof EnumSet<T>)
+      {
+       EnumSet<T> other = (EnumSet<T>) c;
+       if (enumClass != other.enumClass)
+         return false;
+       store.and(other.store);
+       int save = cardinality;
+       cardinality = store.cardinality();
+       return save != cardinality;
+      }
+    return super.retainAll(c);
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> allOf(Class<T> eltType)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.store = new BitSet(eltType.getEnumConstants().length);
+    r.store.set(0, r.store.size());
+    r.cardinality = r.store.size();
+    r.enumClass = eltType;
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> noneOf(Class<T> eltType)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.store = new BitSet(eltType.getEnumConstants().length);
+    r.enumClass = eltType;
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> copyOf(EnumSet<T> other)
+  {
+    // We can't just use `other.clone' since we don't want to make a
+    // subclass.
+    EnumSet<T> r = new EnumSet<T>();
+    r.store = other.store.clone();
+    r.cardinality = other.cardinality;
+    r.enumClass = other.enumClass;
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> copyOf(Collection<T> other)
+  {
+    if (other instanceof EnumSet<T>)
+      return copyOf((EnumSet<T>) other);
+    EnumSet<T> r = new EnumSet<T>();
+    for (T val : other)
+      {
+       if (r.store == null)
+         {
+           r.enumClass = val.getDeclaringClass();
+           r.store = new BitSet(r.enumClass.getEnumConstants().length);
+         }
+       r.store.set(val.ordinal());
+      }
+    // The collection must contain at least one element.
+    if (r.store == null)
+      throw new IllegalArgumentException();
+    r.cardinality = r.store.cardinality();
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> complementOf(EnumSet<T> other)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.store = other.store.clone();
+    r.store.flip(0, r.store.size());
+    r.cardinality = r.store.size() - other.cardinality;
+    r.enumClass = other.enumClass;
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> of(T first)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.enumClass = first.getDeclaringClass();
+    r.store = new BitSet(r.enumClass.getEnumConstants().length);
+    r.store.set(first.ordinal());
+    r.cardinality = 1;
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> of(T first, T second)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.enumClass = first.getDeclaringClass();
+    r.store = new BitSet(r.enumClass.getEnumConstants().length);
+    r.store.set(first.ordinal());
+    r.store.set(second.ordinal());
+    r.cardinality = r.store.cardinality();
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> of(T first, T second, T third)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.enumClass = first.getDeclaringClass();
+    r.store = new BitSet(r.enumClass.getEnumConstants().length);
+    r.store.set(first.ordinal());
+    r.store.set(second.ordinal());
+    r.store.set(third.ordinal());
+    r.cardinality = r.store.cardinality();
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> of(T first, T second, T third,
+                                                 T fourth)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.enumClass = first.getDeclaringClass();
+    r.store = new BitSet(r.enumClass.getEnumConstants().length);
+    r.store.set(first.ordinal());
+    r.store.set(second.ordinal());
+    r.store.set(third.ordinal());
+    r.store.set(fourth.ordinal());
+    r.cardinality = r.store.cardinality();
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> of(T first, T second, T third,
+                                                 T fourth, T fifth)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.enumClass = first.getDeclaringClass();
+    r.store = new BitSet(r.enumClass.getEnumConstants().length);
+    r.store.set(first.ordinal());
+    r.store.set(second.ordinal());
+    r.store.set(third.ordinal());
+    r.store.set(fourth.ordinal());
+    r.store.set(fifth.ordinal());
+    r.cardinality = r.store.cardinality();
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> of(T first, T... rest)
+  {
+    EnumSet<T> r = new EnumSet<T>();
+    r.enumClass = first.getDeclaringClass();
+    r.store = new BitSet(r.enumClass.getEnumConstants().length);
+    r.store.set(first.ordinal());
+    for (T val : rest)
+      r.store.set(val.ordinal());
+    r.cardinality = r.store.cardinality();
+    return r;
+  }
+
+  public static <T extends Enum<T>> EnumSet<T> range(T from, T to)
+  {
+    if (from.compareTo(to) > 0)
+      throw new IllegalArgumentException();
+    EnumSet<T> r = new EnumSet<T>();
+    r.store = new BitSet(from.getDeclaringClass().getEnumConstants().length);
+    r.store.set(from.ordinal(), to.ordinal() + 1);
+    r.enumClass = from.getDeclaringClass();
+    r.cardinality = to.ordinal() - from.ordinal() + 1;
+    return r;
+  }
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]