summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/util/AbstractMap.java
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2005-07-16 00:30:23 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2005-07-16 00:30:23 +0000
commitc8875fb97fc03779a5bba09872227b1d08e5d52a (patch)
treea0b991cf5866ae1d616639b906ac001811d74508 /libjava/classpath/java/util/AbstractMap.java
parentc40c1730800ed292b6db39a83d592476fa59623c (diff)
downloadgcc-c8875fb97fc03779a5bba09872227b1d08e5d52a.tar.gz
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@102074 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/java/util/AbstractMap.java')
-rw-r--r--libjava/classpath/java/util/AbstractMap.java749
1 files changed, 749 insertions, 0 deletions
diff --git a/libjava/classpath/java/util/AbstractMap.java b/libjava/classpath/java/util/AbstractMap.java
new file mode 100644
index 00000000000..7cd6436a308
--- /dev/null
+++ b/libjava/classpath/java/util/AbstractMap.java
@@ -0,0 +1,749 @@
+/* AbstractMap.java -- Abstract implementation of most of Map
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 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;
+
+/**
+ * An abstract implementation of Map to make it easier to create your own
+ * implementations. In order to create an unmodifiable Map, subclass
+ * AbstractMap and implement the <code>entrySet</code> (usually via an
+ * AbstractSet). To make it modifiable, also implement <code>put</code>,
+ * and have <code>entrySet().iterator()</code> support <code>remove</code>.
+ * <p>
+ *
+ * It is recommended that classes which extend this support at least the
+ * no-argument constructor, and a constructor which accepts another Map.
+ * Further methods in this class may be overridden if you have a more
+ * efficient implementation.
+ *
+ * @author Original author unknown
+ * @author Bryce McKinlay
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @see Map
+ * @see Collection
+ * @see HashMap
+ * @see LinkedHashMap
+ * @see TreeMap
+ * @see WeakHashMap
+ * @see IdentityHashMap
+ * @since 1.2
+ * @status updated to 1.4
+ */
+public abstract class AbstractMap implements Map
+{
+ /** An "enum" of iterator types. */
+ // Package visible for use by subclasses.
+ static final int KEYS = 0,
+ VALUES = 1,
+ ENTRIES = 2;
+
+ /**
+ * The cache for {@link #keySet()}.
+ */
+ // Package visible for use by subclasses.
+ Set keys;
+
+ /**
+ * The cache for {@link #values()}.
+ */
+ // Package visible for use by subclasses.
+ Collection values;
+
+ /**
+ * The main constructor, for use by subclasses.
+ */
+ protected AbstractMap()
+ {
+ }
+
+ /**
+ * Returns a set view of the mappings in this Map. Each element in the
+ * set must be an implementation of Map.Entry. The set is backed by
+ * the map, so that changes in one show up in the other. Modifications
+ * made while an iterator is in progress cause undefined behavior. If
+ * the set supports removal, these methods must be valid:
+ * <code>Iterator.remove</code>, <code>Set.remove</code>,
+ * <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
+ * Element addition is not supported via this set.
+ *
+ * @return the entry set
+ * @see Map.Entry
+ */
+ public abstract Set entrySet();
+
+ /**
+ * Remove all entries from this Map (optional operation). This default
+ * implementation calls entrySet().clear(). NOTE: If the entry set does
+ * not permit clearing, then this will fail, too. Subclasses often
+ * override this for efficiency. Your implementation of entrySet() should
+ * not call <code>AbstractMap.clear</code> unless you want an infinite loop.
+ *
+ * @throws UnsupportedOperationException if <code>entrySet().clear()</code>
+ * does not support clearing.
+ * @see Set#clear()
+ */
+ public void clear()
+ {
+ entrySet().clear();
+ }
+
+ /**
+ * Create a shallow copy of this Map, no keys or values are copied. The
+ * default implementation simply calls <code>super.clone()</code>.
+ *
+ * @return the shallow clone
+ * @throws CloneNotSupportedException if a subclass is not Cloneable
+ * @see Cloneable
+ * @see Object#clone()
+ */
+ protected Object clone() throws CloneNotSupportedException
+ {
+ AbstractMap copy = (AbstractMap) super.clone();
+ // Clear out the caches; they are stale.
+ copy.keys = null;
+ copy.values = null;
+ return copy;
+ }
+
+ /**
+ * Returns true if this contains a mapping for the given key. This
+ * implementation does a linear search, O(n), over the
+ * <code>entrySet()</code>, returning <code>true</code> if a match
+ * is found, <code>false</code> if the iteration ends. Many subclasses
+ * can implement this more efficiently.
+ *
+ * @param key the key to search for
+ * @return true if the map contains the key
+ * @throws NullPointerException if key is <code>null</code> but the map
+ * does not permit null keys
+ * @see #containsValue(Object)
+ */
+ public boolean containsKey(Object key)
+ {
+ Iterator entries = entrySet().iterator();
+ int pos = size();
+ while (--pos >= 0)
+ if (equals(key, ((Map.Entry) entries.next()).getKey()))
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns true if this contains at least one mapping with the given value.
+ * This implementation does a linear search, O(n), over the
+ * <code>entrySet()</code>, returning <code>true</code> if a match
+ * is found, <code>false</code> if the iteration ends. A match is
+ * defined as a value, v, where <code>(value == null ? v == null :
+ * value.equals(v))</code>. Subclasses are unlikely to implement
+ * this more efficiently.
+ *
+ * @param value the value to search for
+ * @return true if the map contains the value
+ * @see #containsKey(Object)
+ */
+ public boolean containsValue(Object value)
+ {
+ Iterator entries = entrySet().iterator();
+ int pos = size();
+ while (--pos >= 0)
+ if (equals(value, ((Map.Entry) entries.next()).getValue()))
+ return true;
+ return false;
+ }
+
+ /**
+ * Compares the specified object with this map for equality. Returns
+ * <code>true</code> if the other object is a Map with the same mappings,
+ * that is,<br>
+ * <code>o instanceof Map && entrySet().equals(((Map) o).entrySet();</code>
+ *
+ * @param o the object to be compared
+ * @return true if the object equals this map
+ * @see Set#equals(Object)
+ */
+ public boolean equals(Object o)
+ {
+ return (o == this ||
+ (o instanceof Map &&
+ entrySet().equals(((Map) o).entrySet())));
+ }
+
+ /**
+ * Returns the value mapped by the given key. Returns <code>null</code> if
+ * there is no mapping. However, in Maps that accept null values, you
+ * must rely on <code>containsKey</code> to determine if a mapping exists.
+ * This iteration takes linear time, searching entrySet().iterator() of
+ * the key. Many implementations override this method.
+ *
+ * @param key the key to look up
+ * @return the value associated with the key, or null if key not in map
+ * @throws NullPointerException if this map does not accept null keys
+ * @see #containsKey(Object)
+ */
+ public Object get(Object key)
+ {
+ Iterator entries = entrySet().iterator();
+ int pos = size();
+ while (--pos >= 0)
+ {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if (equals(key, entry.getKey()))
+ return entry.getValue();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash code for this map. As defined in Map, this is the sum
+ * of all hashcodes for each Map.Entry object in entrySet, or basically
+ * entrySet().hashCode().
+ *
+ * @return the hash code
+ * @see Map.Entry#hashCode()
+ * @see Set#hashCode()
+ */
+ public int hashCode()
+ {
+ return entrySet().hashCode();
+ }
+
+ /**
+ * Returns true if the map contains no mappings. This is implemented by
+ * <code>size() == 0</code>.
+ *
+ * @return true if the map is empty
+ * @see #size()
+ */
+ public boolean isEmpty()
+ {
+ return size() == 0;
+ }
+
+ /**
+ * Returns a set view of this map's keys. The set is backed by the map,
+ * so changes in one show up in the other. Modifications while an iteration
+ * is in progress produce undefined behavior. The set supports removal
+ * if entrySet() does, but does not support element addition.
+ * <p>
+ *
+ * This implementation creates an AbstractSet, where the iterator wraps
+ * the entrySet iterator, size defers to the Map's size, and contains
+ * defers to the Map's containsKey. The set is created on first use, and
+ * returned on subsequent uses, although since no synchronization occurs,
+ * there is a slight possibility of creating two sets.
+ *
+ * @return a Set view of the keys
+ * @see Set#iterator()
+ * @see #size()
+ * @see #containsKey(Object)
+ * @see #values()
+ */
+ public Set keySet()
+ {
+ if (keys == null)
+ keys = new AbstractSet()
+ {
+ /**
+ * Retrieves the number of keys in the backing map.
+ *
+ * @return The number of keys.
+ */
+ public int size()
+ {
+ return AbstractMap.this.size();
+ }
+
+ /**
+ * Returns true if the backing map contains the
+ * supplied key.
+ *
+ * @param key The key to search for.
+ * @return True if the key was found, false otherwise.
+ */
+ public boolean contains(Object key)
+ {
+ return containsKey(key);
+ }
+
+ /**
+ * Returns an iterator which iterates over the keys
+ * in the backing map, using a wrapper around the
+ * iterator returned by <code>entrySet()</code>.
+ *
+ * @return An iterator over the keys.
+ */
+ public Iterator iterator()
+ {
+ return new Iterator()
+ {
+ /**
+ * The iterator returned by <code>entrySet()</code>.
+ */
+ private final Iterator map_iterator = entrySet().iterator();
+
+ /**
+ * Returns true if a call to <code>next()</code> will
+ * return another key.
+ *
+ * @return True if the iterator has not yet reached
+ * the last key.
+ */
+ public boolean hasNext()
+ {
+ return map_iterator.hasNext();
+ }
+
+ /**
+ * Returns the key from the next entry retrieved
+ * by the underlying <code>entrySet()</code> iterator.
+ *
+ * @return The next key.
+ */
+ public Object next()
+ {
+ return ((Map.Entry) map_iterator.next()).getKey();
+ }
+
+ /**
+ * Removes the map entry which has a key equal
+ * to that returned by the last call to
+ * <code>next()</code>.
+ *
+ * @throws UnsupportedOperationException if the
+ * map doesn't support removal.
+ */
+ public void remove()
+ {
+ map_iterator.remove();
+ }
+ };
+ }
+ };
+ return keys;
+ }
+
+ /**
+ * Associates the given key to the given value (optional operation). If the
+ * map already contains the key, its value is replaced. This implementation
+ * simply throws an UnsupportedOperationException. Be aware that in a map
+ * that permits <code>null</code> values, a null return does not always
+ * imply that the mapping was created.
+ *
+ * @param key the key to map
+ * @param value the value to be mapped
+ * @return the previous value of the key, or null if there was no mapping
+ * @throws UnsupportedOperationException if the operation is not supported
+ * @throws ClassCastException if the key or value is of the wrong type
+ * @throws IllegalArgumentException if something about this key or value
+ * prevents it from existing in this map
+ * @throws NullPointerException if the map forbids null keys or values
+ * @see #containsKey(Object)
+ */
+ public Object put(Object key, Object value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Copies all entries of the given map to this one (optional operation). If
+ * the map already contains a key, its value is replaced. This implementation
+ * simply iterates over the map's entrySet(), calling <code>put</code>,
+ * so it is not supported if puts are not.
+ *
+ * @param m the mapping to load into this map
+ * @throws UnsupportedOperationException if the operation is not supported
+ * by this map.
+ * @throws ClassCastException if a key or value is of the wrong type for
+ * adding to this map.
+ * @throws IllegalArgumentException if something about a key or value
+ * prevents it from existing in this map.
+ * @throws NullPointerException if the map forbids null keys or values.
+ * @throws NullPointerException if <code>m</code> is null.
+ * @see #put(Object, Object)
+ */
+ public void putAll(Map m)
+ {
+ Iterator entries = m.entrySet().iterator();
+ int pos = m.size();
+ while (--pos >= 0)
+ {
+ Map.Entry entry = (Map.Entry) entries.next();
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Removes the mapping for this key if present (optional operation). This
+ * implementation iterates over the entrySet searching for a matching
+ * key, at which point it calls the iterator's <code>remove</code> method.
+ * It returns the result of <code>getValue()</code> on the entry, if found,
+ * or null if no entry is found. Note that maps which permit null values
+ * may also return null if the key was removed. If the entrySet does not
+ * support removal, this will also fail. This is O(n), so many
+ * implementations override it for efficiency.
+ *
+ * @param key the key to remove
+ * @return the value the key mapped to, or null if not present.
+ * Null may also be returned if null values are allowed
+ * in the map and the value of this mapping is null.
+ * @throws UnsupportedOperationException if deletion is unsupported
+ * @see Iterator#remove()
+ */
+ public Object remove(Object key)
+ {
+ Iterator entries = entrySet().iterator();
+ int pos = size();
+ while (--pos >= 0)
+ {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if (equals(key, entry.getKey()))
+ {
+ // Must get the value before we remove it from iterator.
+ Object r = entry.getValue();
+ entries.remove();
+ return r;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the number of key-value mappings in the map. If there are more
+ * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is
+ * implemented as <code>entrySet().size()</code>.
+ *
+ * @return the number of mappings
+ * @see Set#size()
+ */
+ public int size()
+ {
+ return entrySet().size();
+ }
+
+ /**
+ * Returns a String representation of this map. This is a listing of the
+ * map entries (which are specified in Map.Entry as being
+ * <code>getKey() + "=" + getValue()</code>), separated by a comma and
+ * space (", "), and surrounded by braces ('{' and '}'). This implementation
+ * uses a StringBuffer and iterates over the entrySet to build the String.
+ * Note that this can fail with an exception if underlying keys or
+ * values complete abruptly in toString().
+ *
+ * @return a String representation
+ * @see Map.Entry#toString()
+ */
+ public String toString()
+ {
+ Iterator entries = entrySet().iterator();
+ StringBuffer r = new StringBuffer("{");
+ for (int pos = size(); pos > 0; pos--)
+ {
+ Map.Entry entry = (Map.Entry) entries.next();
+ r.append(entry.getKey());
+ r.append('=');
+ r.append(entry.getValue());
+ if (pos > 1)
+ r.append(", ");
+ }
+ r.append("}");
+ return r.toString();
+ }
+
+ /**
+ * Returns a collection or bag view of this map's values. The collection
+ * is backed by the map, so changes in one show up in the other.
+ * Modifications while an iteration is in progress produce undefined
+ * behavior. The collection supports removal if entrySet() does, but
+ * does not support element addition.
+ * <p>
+ *
+ * This implementation creates an AbstractCollection, where the iterator
+ * wraps the entrySet iterator, size defers to the Map's size, and contains
+ * defers to the Map's containsValue. The collection is created on first
+ * use, and returned on subsequent uses, although since no synchronization
+ * occurs, there is a slight possibility of creating two collections.
+ *
+ * @return a Collection view of the values
+ * @see Collection#iterator()
+ * @see #size()
+ * @see #containsValue(Object)
+ * @see #keySet()
+ */
+ public Collection values()
+ {
+ if (values == null)
+ values = new AbstractCollection()
+ {
+ /**
+ * Returns the number of values stored in
+ * the backing map.
+ *
+ * @return The number of values.
+ */
+ public int size()
+ {
+ return AbstractMap.this.size();
+ }
+
+ /**
+ * Returns true if the backing map contains
+ * the supplied value.
+ *
+ * @param value The value to search for.
+ * @return True if the value was found, false otherwise.
+ */
+ public boolean contains(Object value)
+ {
+ return containsValue(value);
+ }
+
+ /**
+ * Returns an iterator which iterates over the
+ * values in the backing map, by using a wrapper
+ * around the iterator returned by <code>entrySet()</code>.
+ *
+ * @return An iterator over the values.
+ */
+ public Iterator iterator()
+ {
+ return new Iterator()
+ {
+ /**
+ * The iterator returned by <code>entrySet()</code>.
+ */
+ private final Iterator map_iterator = entrySet().iterator();
+
+ /**
+ * Returns true if a call to <code>next()</call> will
+ * return another value.
+ *
+ * @return True if the iterator has not yet reached
+ * the last value.
+ */
+ public boolean hasNext()
+ {
+ return map_iterator.hasNext();
+ }
+
+ /**
+ * Returns the value from the next entry retrieved
+ * by the underlying <code>entrySet()</code> iterator.
+ *
+ * @return The next value.
+ */
+ public Object next()
+ {
+ return ((Map.Entry) map_iterator.next()).getValue();
+ }
+
+ /**
+ * Removes the map entry which has a key equal
+ * to that returned by the last call to
+ * <code>next()</code>.
+ *
+ * @throws UnsupportedOperationException if the
+ * map doesn't support removal.
+ */
+ public void remove()
+ {
+ map_iterator.remove();
+ }
+ };
+ }
+ };
+ return values;
+ }
+
+ /**
+ * Compare two objects according to Collection semantics.
+ *
+ * @param o1 the first object
+ * @param o2 the second object
+ * @return o1 == null ? o2 == null : o1.equals(o2)
+ */
+ // Package visible for use throughout java.util.
+ // It may be inlined since it is final.
+ static final boolean equals(Object o1, Object o2)
+ {
+ return o1 == null ? o2 == null : o1.equals(o2);
+ }
+
+ /**
+ * Hash an object according to Collection semantics.
+ *
+ * @param o the object to hash
+ * @return o1 == null ? 0 : o1.hashCode()
+ */
+ // Package visible for use throughout java.util.
+ // It may be inlined since it is final.
+ static final int hashCode(Object o)
+ {
+ return o == null ? 0 : o.hashCode();
+ }
+
+ /**
+ * A class which implements Map.Entry. It is shared by HashMap, TreeMap,
+ * Hashtable, and Collections. It is not specified by the JDK, but makes
+ * life much easier.
+ *
+ * @author Jon Zeppieri
+ * @author Eric Blake (ebb9@email.byu.edu)
+ */
+ // XXX - FIXME Use fully qualified implements as gcj 3.1 workaround.
+ // Bug still exists in 3.4.1
+ static class BasicMapEntry implements Map.Entry
+ {
+ /**
+ * The key. Package visible for direct manipulation.
+ */
+ Object key;
+
+ /**
+ * The value. Package visible for direct manipulation.
+ */
+ Object value;
+
+ /**
+ * Basic constructor initializes the fields.
+ * @param newKey the key
+ * @param newValue the value
+ */
+ BasicMapEntry(Object newKey, Object newValue)
+ {
+ key = newKey;
+ value = newValue;
+ }
+
+ /**
+ * Compares the specified object with this entry. Returns true only if
+ * the object is a mapping of identical key and value. In other words,
+ * this must be:<br>
+ * <pre>(o instanceof Map.Entry)
+ * && (getKey() == null ? ((HashMap) o).getKey() == null
+ * : getKey().equals(((HashMap) o).getKey()))
+ * && (getValue() == null ? ((HashMap) o).getValue() == null
+ * : getValue().equals(((HashMap) o).getValue()))</pre>
+ *
+ * @param o the object to compare
+ * @return <code>true</code> if it is equal
+ */
+ public final boolean equals(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ // Optimize for our own entries.
+ if (o instanceof BasicMapEntry)
+ {
+ BasicMapEntry e = (BasicMapEntry) o;
+ return (AbstractMap.equals(key, e.key)
+ && AbstractMap.equals(value, e.value));
+ }
+ Map.Entry e = (Map.Entry) o;
+ return (AbstractMap.equals(key, e.getKey())
+ && AbstractMap.equals(value, e.getValue()));
+ }
+
+ /**
+ * Get the key corresponding to this entry.
+ *
+ * @return the key
+ */
+ public final Object getKey()
+ {
+ return key;
+ }
+
+ /**
+ * Get the value corresponding to this entry. If you already called
+ * Iterator.remove(), the behavior undefined, but in this case it works.
+ *
+ * @return the value
+ */
+ public final Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Returns the hash code of the entry. This is defined as the exclusive-or
+ * of the hashcodes of the key and value (using 0 for null). In other
+ * words, this must be:<br>
+ * <pre>(getKey() == null ? 0 : getKey().hashCode())
+ * ^ (getValue() == null ? 0 : getValue().hashCode())</pre>
+ *
+ * @return the hash code
+ */
+ public final int hashCode()
+ {
+ return (AbstractMap.hashCode(key) ^ AbstractMap.hashCode(value));
+ }
+
+ /**
+ * Replaces the value with the specified object. This writes through
+ * to the map, unless you have already called Iterator.remove(). It
+ * may be overridden to restrict a null value.
+ *
+ * @param newVal the new value to store
+ * @return the old value
+ * @throws NullPointerException if the map forbids null values.
+ * @throws UnsupportedOperationException if the map doesn't support
+ * <code>put()</code>.
+ * @throws ClassCastException if the value is of a type unsupported
+ * by the map.
+ * @throws IllegalArgumentException if something else about this
+ * value prevents it being stored in the map.
+ */
+ public Object setValue(Object newVal)
+ {
+ Object r = value;
+ value = newVal;
+ return r;
+ }
+
+ /**
+ * This provides a string representation of the entry. It is of the form
+ * "key=value", where string concatenation is used on key and value.
+ *
+ * @return the string representation
+ */
+ public final String toString()
+ {
+ return key + "=" + value;
+ }
+ } // class BasicMapEntry
+}