mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			406 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* 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;
 | |
|   }
 | |
| 
 | |
| }
 |