mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			928 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			928 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Java
		
	
	
	
/* IdentityHashMap.java -- a class providing a hashtable data structure,
 | 
						|
   mapping Object --> Object, which uses object identity for hashing.
 | 
						|
   Copyright (C) 2001, 2002 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;
 | 
						|
 | 
						|
import java.io.*;
 | 
						|
 | 
						|
/**
 | 
						|
 * This class provides a hashtable-backed implementation of the
 | 
						|
 * Map interface, but uses object identity to do its hashing.  In fact,
 | 
						|
 * it uses object identity for comparing values, as well. It uses a
 | 
						|
 * linear-probe hash table, which may have faster performance
 | 
						|
 * than the chaining employed by HashMap.
 | 
						|
 * <p>
 | 
						|
 *
 | 
						|
 * <em>WARNING: This is not a general purpose map. Because it uses
 | 
						|
 * System.identityHashCode and ==, instead of hashCode and equals, for
 | 
						|
 * comparison, it violated Map's general contract, and may cause
 | 
						|
 * undefined behavior when compared to other maps which are not
 | 
						|
 * IdentityHashMaps.  This is designed only for the rare cases when
 | 
						|
 * identity semantics are needed.</em> An example use is
 | 
						|
 * topology-preserving graph transformations, such as deep cloning,
 | 
						|
 * or as proxy object mapping such as in debugging.
 | 
						|
 * <p>
 | 
						|
 *
 | 
						|
 * This map permits <code>null</code> keys and values, and does not
 | 
						|
 * guarantee that elements will stay in the same order over time. The
 | 
						|
 * basic operations (<code>get</code> and <code>put</code>) take
 | 
						|
 * constant time, provided System.identityHashCode is decent. You can
 | 
						|
 * tune the behavior by specifying the expected maximum size. As more
 | 
						|
 * elements are added, the map may need to allocate a larger table,
 | 
						|
 * which can be expensive.
 | 
						|
 * <p>
 | 
						|
 *
 | 
						|
 * This implementation is unsynchronized.  If you want multi-thread
 | 
						|
 * access to be consistent, you must synchronize it, perhaps by using
 | 
						|
 * <code>Collections.synchronizedMap(new IdentityHashMap(...));</code>.
 | 
						|
 * The iterators are <i>fail-fast</i>, meaning that a structural modification
 | 
						|
 * made to the map outside of an iterator's remove method cause the
 | 
						|
 * iterator, and in the case of the entrySet, the Map.Entry, to
 | 
						|
 * fail with a {@link ConcurrentModificationException}.
 | 
						|
 *
 | 
						|
 * @author Tom Tromey <tromey@redhat.com>
 | 
						|
 * @author Eric Blake <ebb9@email.byu.edu>
 | 
						|
 * @see System#identityHashCode(Object)
 | 
						|
 * @see Collection
 | 
						|
 * @see Map
 | 
						|
 * @see HashMap
 | 
						|
 * @see TreeMap
 | 
						|
 * @see LinkedHashMap
 | 
						|
 * @see WeakHashMap
 | 
						|
 * @since 1.4
 | 
						|
 * @status updated to 1.4
 | 
						|
 */
 | 
						|
public class IdentityHashMap extends AbstractMap
 | 
						|
  implements Map, Serializable, Cloneable
 | 
						|
{
 | 
						|
  /** The default capacity. */
 | 
						|
  private static final int DEFAULT_CAPACITY = 21;
 | 
						|
 | 
						|
  /**
 | 
						|
   * This object is used to mark deleted items. Package visible for use by
 | 
						|
   * nested classes.
 | 
						|
   */
 | 
						|
  static final Object tombstone = new Object();
 | 
						|
 | 
						|
  /**
 | 
						|
   * This object is used to mark empty slots.  We need this because
 | 
						|
   * using null is ambiguous. Package visible for use by nested classes.
 | 
						|
   */
 | 
						|
  static final Object emptyslot = new Object();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Compatible with JDK 1.4.
 | 
						|
   */
 | 
						|
  private static final long serialVersionUID = 8188218128353913216L;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The number of mappings in the table. Package visible for use by nested
 | 
						|
   * classes.
 | 
						|
   * @serial
 | 
						|
   */
 | 
						|
  int size;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The table itself. Package visible for use by nested classes.
 | 
						|
   */
 | 
						|
  transient Object[] table;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The number of structural modifications made so far. Package visible for
 | 
						|
   * use by nested classes.
 | 
						|
   */
 | 
						|
  transient int modCount;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The cache for {@link #entrySet()}.
 | 
						|
   */
 | 
						|
  private transient Set entries;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The threshold for rehashing, which is 75% of (table.length / 2).
 | 
						|
   */
 | 
						|
  private transient int threshold;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a new IdentityHashMap with the default capacity (21 entries).
 | 
						|
   */
 | 
						|
  public IdentityHashMap()
 | 
						|
  {
 | 
						|
    this(DEFAULT_CAPACITY);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a new IdentityHashMap with the indicated number of
 | 
						|
   * entries.  If the number of elements added to this hash map
 | 
						|
   * exceeds this maximum, the map will grow itself; however, that
 | 
						|
   * incurs a performance penalty.
 | 
						|
   *
 | 
						|
   * @param max initial size
 | 
						|
   * @throws IllegalArgumentException if max is negative
 | 
						|
   */
 | 
						|
  public IdentityHashMap(int max)
 | 
						|
  {
 | 
						|
    if (max < 0)
 | 
						|
      throw new IllegalArgumentException();
 | 
						|
    // Need at least two slots, or hash() will break.
 | 
						|
    if (max < 2)
 | 
						|
      max = 2;
 | 
						|
    table = new Object[2 * max];
 | 
						|
    Arrays.fill(table, emptyslot);
 | 
						|
    threshold = max / 4 * 3;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a new IdentityHashMap whose contents are taken from the
 | 
						|
   * given Map.
 | 
						|
   *
 | 
						|
   * @param m The map whose elements are to be put in this map
 | 
						|
   * @throws NullPointerException if m is null
 | 
						|
   */
 | 
						|
  public IdentityHashMap(Map m)
 | 
						|
  {
 | 
						|
    this(Math.max(m.size() * 2, DEFAULT_CAPACITY));
 | 
						|
    putAll(m);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Remove all mappings from this map.
 | 
						|
   */
 | 
						|
  public void clear()
 | 
						|
  {
 | 
						|
    if (size != 0)
 | 
						|
      {
 | 
						|
        modCount++;
 | 
						|
        Arrays.fill(table, emptyslot);
 | 
						|
        size = 0;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a shallow copy where keys and values are not cloned.
 | 
						|
   */
 | 
						|
  public Object clone()
 | 
						|
  {
 | 
						|
    try
 | 
						|
      {
 | 
						|
        IdentityHashMap copy = (IdentityHashMap) super.clone();
 | 
						|
        copy.table = (Object[]) table.clone();
 | 
						|
        copy.entries = null; // invalidate the cache
 | 
						|
        return copy;
 | 
						|
      }
 | 
						|
    catch (CloneNotSupportedException e)
 | 
						|
      {
 | 
						|
        // Can't happen.
 | 
						|
        return null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Tests whether the specified key is in this map.  Unlike normal Maps,
 | 
						|
   * this test uses <code>entry == key</code> instead of
 | 
						|
   * <code>entry == null ? key == null : entry.equals(key)</code>.
 | 
						|
   *
 | 
						|
   * @param key the key to look for
 | 
						|
   * @return true if the key is contained in the map
 | 
						|
   * @see #containsValue(Object)
 | 
						|
   * @see #get(Object)
 | 
						|
   */
 | 
						|
  public boolean containsKey(Object key)
 | 
						|
  {
 | 
						|
    return key == table[hash(key)];
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns true if this HashMap contains the value.  Unlike normal maps,
 | 
						|
   * this test uses <code>entry == value</code> instead of
 | 
						|
   * <code>entry == null ? value == null : entry.equals(value)</code>.
 | 
						|
   *
 | 
						|
   * @param value the value to search for in this HashMap
 | 
						|
   * @return true if at least one key maps to the value
 | 
						|
   * @see #containsKey(Object)
 | 
						|
   */
 | 
						|
  public boolean containsValue(Object value)
 | 
						|
  {
 | 
						|
    for (int i = table.length - 1; i > 0; i -= 2)
 | 
						|
      if (table[i] == value)
 | 
						|
        return true;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a "set view" of this Map's entries. The set is backed by
 | 
						|
   * the Map, so changes in one show up in the other.  The set supports
 | 
						|
   * element removal, but not element addition.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * <em>The semantics of this set, and of its contained entries, are
 | 
						|
   * different from the contract of Set and Map.Entry in order to make
 | 
						|
   * IdentityHashMap work.  This means that while you can compare these
 | 
						|
   * objects between IdentityHashMaps, comparing them with regular sets
 | 
						|
   * or entries is likely to have undefined behavior.</em>  The entries
 | 
						|
   * in this set are reference-based, rather than the normal object
 | 
						|
   * equality.  Therefore, <code>e1.equals(e2)</code> returns
 | 
						|
   * <code>e1.getKey() == e2.getKey() && e1.getValue() == e2.getValue()</code>,
 | 
						|
   * and <code>e.hashCode()</code> returns
 | 
						|
   * <code>System.identityHashCode(e.getKey()) ^
 | 
						|
   *       System.identityHashCode(e.getValue())</code>.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * Note that the iterators for all three views, from keySet(), entrySet(),
 | 
						|
   * and values(), traverse the Map in the same sequence.
 | 
						|
   *
 | 
						|
   * @return a set view of the entries
 | 
						|
   * @see #keySet()
 | 
						|
   * @see #values()
 | 
						|
   * @see Map.Entry
 | 
						|
   */
 | 
						|
  public Set entrySet()
 | 
						|
  {
 | 
						|
    if (entries == null)
 | 
						|
      entries = new AbstractSet()
 | 
						|
      {
 | 
						|
        public int size()
 | 
						|
        {
 | 
						|
          return size;
 | 
						|
        }
 | 
						|
 | 
						|
        public Iterator iterator()
 | 
						|
        {
 | 
						|
          return new IdentityIterator(ENTRIES);
 | 
						|
        }
 | 
						|
 | 
						|
        public void clear()
 | 
						|
        {
 | 
						|
          IdentityHashMap.this.clear();
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean contains(Object o)
 | 
						|
        {
 | 
						|
          if (! (o instanceof Map.Entry))
 | 
						|
            return false;
 | 
						|
          Map.Entry m = (Map.Entry) o;
 | 
						|
          return m.getValue() == table[hash(m.getKey()) + 1];
 | 
						|
        }
 | 
						|
 | 
						|
        public int hashCode()
 | 
						|
        {
 | 
						|
          return IdentityHashMap.this.hashCode();
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean remove(Object o)
 | 
						|
        {
 | 
						|
          if (! (o instanceof Map.Entry))
 | 
						|
            return false;
 | 
						|
          Object key = ((Map.Entry) o).getKey();
 | 
						|
          int h = hash(key);
 | 
						|
          if (table[h] == key)
 | 
						|
            {
 | 
						|
              size--;
 | 
						|
              modCount++;
 | 
						|
              table[h] = tombstone;
 | 
						|
              table[h + 1] = tombstone;
 | 
						|
              return true;
 | 
						|
            }
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      };
 | 
						|
    return entries;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Compares two maps for equality. This returns true only if both maps
 | 
						|
   * have the same reference-identity comparisons. While this returns
 | 
						|
   * <code>this.entrySet().equals(m.entrySet())</code> as specified by Map,
 | 
						|
   * this will not work with normal maps, since the entry set compares
 | 
						|
   * with == instead of .equals.
 | 
						|
   *
 | 
						|
   * @param o the object to compare to
 | 
						|
   * @return true if it is equal
 | 
						|
   */
 | 
						|
  public boolean equals(Object o)
 | 
						|
  {
 | 
						|
    // Why did Sun specify this one? The superclass does the right thing.
 | 
						|
    return super.equals(o);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return the value in this Map associated with the supplied key,
 | 
						|
   * or <pre>null</pre> if the key maps to nothing.  NOTE: Since the value
 | 
						|
   * could also be null, you must use containsKey to see if this key
 | 
						|
   * actually maps to something.  Unlike normal maps, this tests for the key
 | 
						|
   * with <code>entry == key</code> instead of
 | 
						|
   * <code>entry == null ? key == null : entry.equals(key)</code>.
 | 
						|
   *
 | 
						|
   * @param key the key for which to fetch an associated value
 | 
						|
   * @return what the key maps to, if present
 | 
						|
   * @see #put(Object, Object)
 | 
						|
   * @see #containsKey(Object)
 | 
						|
   */
 | 
						|
  public Object get(Object key)
 | 
						|
  {
 | 
						|
    int h = hash(key);
 | 
						|
    return table[h] == key ? table[h + 1] : null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the hashcode of this map. This guarantees that two
 | 
						|
   * IdentityHashMaps that compare with equals() will have the same hash code,
 | 
						|
   * but may break with comparison to normal maps since it uses
 | 
						|
   * System.identityHashCode() instead of hashCode().
 | 
						|
   *
 | 
						|
   * @return the hash code
 | 
						|
   */
 | 
						|
  public int hashCode()
 | 
						|
  {
 | 
						|
    int hash = 0;
 | 
						|
    for (int i = table.length - 2; i >= 0; i -= 2)
 | 
						|
      {
 | 
						|
        Object key = table[i];
 | 
						|
        if (key == emptyslot || key == tombstone)
 | 
						|
          continue;
 | 
						|
        hash += (System.identityHashCode(key)
 | 
						|
                 ^ System.identityHashCode(table[i + 1]));
 | 
						|
      }
 | 
						|
    return hash;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns true if there are no key-value mappings currently in this Map
 | 
						|
   * @return <code>size() == 0</code>
 | 
						|
   */
 | 
						|
  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.  The set supports
 | 
						|
   * element removal, but not element addition.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * <em>The semantics of this set are different from the contract of Set
 | 
						|
   * in order to make IdentityHashMap work.  This means that while you can
 | 
						|
   * compare these objects between IdentityHashMaps, comparing them with
 | 
						|
   * regular sets is likely to have undefined behavior.</em>  The hashCode
 | 
						|
   * of the set is the sum of the identity hash codes, instead of the
 | 
						|
   * regular hashCodes, and equality is determined by reference instead
 | 
						|
   * of by the equals method.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * @return a set view of the keys
 | 
						|
   * @see #values()
 | 
						|
   * @see #entrySet()
 | 
						|
   */
 | 
						|
  public Set keySet()
 | 
						|
  {
 | 
						|
    if (keys == null)
 | 
						|
      keys = new AbstractSet()
 | 
						|
      {
 | 
						|
        public int size()
 | 
						|
        {
 | 
						|
          return size;
 | 
						|
        }
 | 
						|
 | 
						|
        public Iterator iterator()
 | 
						|
        {
 | 
						|
          return new IdentityIterator(KEYS);
 | 
						|
        }
 | 
						|
 | 
						|
        public void clear()
 | 
						|
        {
 | 
						|
          IdentityHashMap.this.clear();
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean contains(Object o)
 | 
						|
        {
 | 
						|
          return containsKey(o);
 | 
						|
        }
 | 
						|
 | 
						|
        public int hashCode()
 | 
						|
        {
 | 
						|
          int hash = 0;
 | 
						|
          for (int i = table.length - 2; i >= 0; i -= 2)
 | 
						|
            {
 | 
						|
              Object key = table[i];
 | 
						|
              if (key == emptyslot || key == tombstone)
 | 
						|
                continue;
 | 
						|
              hash += System.identityHashCode(key);
 | 
						|
            }
 | 
						|
          return hash;
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean remove(Object o)
 | 
						|
        {
 | 
						|
          int h = hash(o);
 | 
						|
          if (table[h] == o)
 | 
						|
            {
 | 
						|
              size--;
 | 
						|
              modCount++;
 | 
						|
              table[h] = tombstone;
 | 
						|
              table[h + 1] = tombstone;
 | 
						|
              return true;
 | 
						|
            }
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      };
 | 
						|
    return keys;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Puts the supplied value into the Map, mapped by the supplied key.
 | 
						|
   * The value may be retrieved by any object which <code>equals()</code>
 | 
						|
   * this key. NOTE: Since the prior value could also be null, you must
 | 
						|
   * first use containsKey if you want to see if you are replacing the
 | 
						|
   * key's mapping.  Unlike normal maps, this tests for the key
 | 
						|
   * with <code>entry == key</code> instead of
 | 
						|
   * <code>entry == null ? key == null : entry.equals(key)</code>.
 | 
						|
   *
 | 
						|
   * @param key the key used to locate the value
 | 
						|
   * @param value the value to be stored in the HashMap
 | 
						|
   * @return the prior mapping of the key, or null if there was none
 | 
						|
   * @see #get(Object)
 | 
						|
   */
 | 
						|
  public Object put(Object key, Object value)
 | 
						|
  {
 | 
						|
    // Rehash if the load factor is too high.
 | 
						|
    if (size > threshold)
 | 
						|
      {
 | 
						|
        Object[] old = table;
 | 
						|
        // This isn't necessarily prime, but it is an odd number of key/value
 | 
						|
        // slots, which has a higher probability of fewer collisions.
 | 
						|
        table = new Object[old.length * 2 + 2];
 | 
						|
        Arrays.fill(table, emptyslot);
 | 
						|
        size = 0;
 | 
						|
        threshold = table.length / 4 * 3;
 | 
						|
 | 
						|
        for (int i = old.length - 2; i >= 0; i -= 2)
 | 
						|
          {
 | 
						|
            Object oldkey = old[i];
 | 
						|
            if (oldkey != tombstone && oldkey != emptyslot)
 | 
						|
              // Just use put.  This isn't very efficient, but it is ok.
 | 
						|
              put(oldkey, old[i + 1]);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    int h = hash(key);
 | 
						|
    if (table[h] == key)
 | 
						|
      {
 | 
						|
        Object r = table[h + 1];
 | 
						|
        table[h + 1] = value;
 | 
						|
        return r;
 | 
						|
      }
 | 
						|
 | 
						|
    // At this point, we add a new mapping.
 | 
						|
    modCount++;
 | 
						|
    size++;
 | 
						|
    table[h] = key;
 | 
						|
    table[h + 1] = value;
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Copies all of the mappings from the specified map to this. If a key
 | 
						|
   * is already in this map, its value is replaced.
 | 
						|
   *
 | 
						|
   * @param m the map to copy
 | 
						|
   * @throws NullPointerException if m is null
 | 
						|
   */
 | 
						|
  public void putAll(Map m)
 | 
						|
  {
 | 
						|
    // Why did Sun specify this one? The superclass does the right thing.
 | 
						|
    super.putAll(m);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Removes from the HashMap and returns the value which is mapped by the
 | 
						|
   * supplied key. If the key maps to nothing, then the HashMap remains
 | 
						|
   * unchanged, and <pre>null</pre> is returned. NOTE: Since the value
 | 
						|
   * could also be null, you must use containsKey to see if you are
 | 
						|
   * actually removing a mapping.  Unlike normal maps, this tests for the
 | 
						|
   * key with <code>entry == key</code> instead of
 | 
						|
   * <code>entry == null ? key == null : entry.equals(key)</code>.
 | 
						|
   *
 | 
						|
   * @param key the key used to locate the value to remove
 | 
						|
   * @return whatever the key mapped to, if present
 | 
						|
   */
 | 
						|
  public Object remove(Object key)
 | 
						|
  {
 | 
						|
    int h = hash(key);
 | 
						|
    if (table[h] == key)
 | 
						|
      {
 | 
						|
        modCount++;
 | 
						|
        size--;
 | 
						|
        Object r = table[h + 1];
 | 
						|
        table[h] = tombstone;
 | 
						|
        table[h + 1] = tombstone;
 | 
						|
        return r;
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the number of kay-value mappings currently in this Map
 | 
						|
   * @return the size
 | 
						|
   */
 | 
						|
  public int size()
 | 
						|
  {
 | 
						|
    return size;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a "collection view" (or "bag view") of this Map's values.
 | 
						|
   * The collection is backed by the Map, so changes in one show up
 | 
						|
   * in the other.  The collection supports element removal, but not element
 | 
						|
   * addition.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * <em>The semantics of this set are different from the contract of
 | 
						|
   * Collection in order to make IdentityHashMap work.  This means that
 | 
						|
   * while you can compare these objects between IdentityHashMaps, comparing
 | 
						|
   * them with regular sets is likely to have undefined behavior.</em>
 | 
						|
   * Likewise, contains and remove go by == instead of equals().
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * @return a bag view of the values
 | 
						|
   * @see #keySet()
 | 
						|
   * @see #entrySet()
 | 
						|
   */
 | 
						|
  public Collection values()
 | 
						|
  {
 | 
						|
    if (values == null)
 | 
						|
      values = new AbstractCollection()
 | 
						|
      {
 | 
						|
        public int size()
 | 
						|
        {
 | 
						|
          return size;
 | 
						|
        }
 | 
						|
 | 
						|
        public Iterator iterator()
 | 
						|
        {
 | 
						|
          return new IdentityIterator(VALUES);
 | 
						|
        }
 | 
						|
 | 
						|
        public void clear()
 | 
						|
        {
 | 
						|
          IdentityHashMap.this.clear();
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean remove(Object o)
 | 
						|
        {
 | 
						|
          for (int i = table.length - 1; i > 0; i -= 2)
 | 
						|
            if (table[i] == o)
 | 
						|
              {
 | 
						|
                modCount++;
 | 
						|
                table[i - 1] = tombstone;
 | 
						|
                table[i] = tombstone;
 | 
						|
                size--;
 | 
						|
                return true;
 | 
						|
              }
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      };
 | 
						|
    return values;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Helper method which computes the hash code, then traverses the table
 | 
						|
   * until it finds the key, or the spot where the key would go.
 | 
						|
   *
 | 
						|
   * @param key the key to check
 | 
						|
   * @return the index where the key belongs
 | 
						|
   * @see #IdentityHashMap(int)
 | 
						|
   * @see #put(Object, Object)
 | 
						|
   */
 | 
						|
  // Package visible for use by nested classes.
 | 
						|
  int hash(Object key)
 | 
						|
  {
 | 
						|
    // Implementation note: it is feasible for the table to have no
 | 
						|
    // emptyslots, if it is full with entries and tombstones, so we must
 | 
						|
    // remember where we started. If we encounter the key or an emptyslot,
 | 
						|
    // we are done.  If we encounter a tombstone, the key may still be in
 | 
						|
    // the array.  If we don't encounter the key, we use the first emptyslot
 | 
						|
    // or tombstone we encountered as the location where the key would go.
 | 
						|
    // By requiring at least 2 key/value slots, and rehashing at 75%
 | 
						|
    // capacity, we guarantee that there will always be either an emptyslot
 | 
						|
    // or a tombstone somewhere in the table.
 | 
						|
    int h = 2 * Math.abs(System.identityHashCode(key) % (table.length / 2));
 | 
						|
    int del = -1;
 | 
						|
    int save = h;
 | 
						|
 | 
						|
    do
 | 
						|
      {
 | 
						|
        if (table[h] == key)
 | 
						|
          return h;
 | 
						|
        if (table[h] == emptyslot)
 | 
						|
          break;
 | 
						|
        if (table[h] == tombstone && del < 0)
 | 
						|
          del = h;
 | 
						|
        h -= 2;
 | 
						|
        if (h < 0)
 | 
						|
          h = table.length - 2;
 | 
						|
      }
 | 
						|
    while (h != save);
 | 
						|
 | 
						|
    return del < 0 ? h : del;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class allows parameterized iteration over IdentityHashMaps.  Based
 | 
						|
   * on its construction, it returns the key or value of a mapping, or
 | 
						|
   * creates the appropriate Map.Entry object with the correct fail-fast
 | 
						|
   * semantics and identity comparisons.
 | 
						|
   *
 | 
						|
   * @author Tom Tromey <tromey@redhat.com>
 | 
						|
   * @author Eric Blake <ebb9@email.byu.edu>
 | 
						|
   */
 | 
						|
  private final class IdentityIterator implements Iterator
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
 | 
						|
     * or {@link #ENTRIES}.
 | 
						|
     */
 | 
						|
    final int type;
 | 
						|
    /** The number of modifications to the backing Map that we know about. */
 | 
						|
    int knownMod = modCount;
 | 
						|
    /** The number of elements remaining to be returned by next(). */
 | 
						|
    int count = size;
 | 
						|
    /** Location in the table. */
 | 
						|
    int loc = table.length;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Construct a new Iterator with the supplied type.
 | 
						|
     * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
 | 
						|
     */
 | 
						|
    IdentityIterator(int type)
 | 
						|
    {
 | 
						|
      this.type = type;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns true if the Iterator has more elements.
 | 
						|
     * @return true if there are more elements
 | 
						|
     * @throws ConcurrentModificationException if the Map was modified
 | 
						|
     */
 | 
						|
    public boolean hasNext()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      return count > 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the next element in the Iterator's sequential view.
 | 
						|
     * @return the next element
 | 
						|
     * @throws ConcurrentModificationException if the Map was modified
 | 
						|
     * @throws NoSuchElementException if there is none
 | 
						|
     */
 | 
						|
    public Object next()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      if (count == 0)
 | 
						|
        throw new NoSuchElementException();
 | 
						|
      count--;
 | 
						|
 | 
						|
      Object key;
 | 
						|
      do
 | 
						|
        {
 | 
						|
          loc -= 2;
 | 
						|
          key = table[loc];
 | 
						|
        }
 | 
						|
      while (key == emptyslot || key == tombstone);
 | 
						|
 | 
						|
      return type == KEYS ? key : (type == VALUES ? table[loc + 1]
 | 
						|
                                   : new IdentityEntry(loc));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Removes from the backing Map the last element which was fetched
 | 
						|
     * with the <pre>next()</pre> method.
 | 
						|
     * @throws ConcurrentModificationException if the Map was modified
 | 
						|
     * @throws IllegalStateException if called when there is no last element
 | 
						|
     */
 | 
						|
    public void remove()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      if (loc == table.length || table[loc] == tombstone)
 | 
						|
        throw new IllegalStateException();
 | 
						|
      modCount++;
 | 
						|
      size--;
 | 
						|
      table[loc] = tombstone;
 | 
						|
      table[loc + 1] = tombstone;
 | 
						|
      knownMod++;
 | 
						|
    }
 | 
						|
  } // class IdentityIterator
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class provides Map.Entry objects for IdentityHashMaps.  The entry
 | 
						|
   * is fail-fast, and will throw a ConcurrentModificationException if
 | 
						|
   * the underlying map is modified, or if remove is called on the iterator
 | 
						|
   * that generated this object.  It is identity based, so it violates
 | 
						|
   * the general contract of Map.Entry, and is probably unsuitable for
 | 
						|
   * comparison to normal maps; but it works among other IdentityHashMaps.
 | 
						|
   *
 | 
						|
   * @author Eric Blake <ebb9@email.byu.edu>
 | 
						|
   */
 | 
						|
  private final class IdentityEntry implements Map.Entry
 | 
						|
  {
 | 
						|
    /** The location of this entry. */
 | 
						|
    final int loc;
 | 
						|
    /** The number of modifications to the backing Map that we know about. */
 | 
						|
    final int knownMod = modCount;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructs the Entry.
 | 
						|
     *
 | 
						|
     * @param loc the location of this entry in table
 | 
						|
     */
 | 
						|
    IdentityEntry(int loc)
 | 
						|
    {
 | 
						|
      this.loc = loc;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Compares the specified object with this entry, using identity
 | 
						|
     * semantics. Note that this can lead to undefined results with
 | 
						|
     * Entry objects created by normal maps.
 | 
						|
     *
 | 
						|
     * @param o the object to compare
 | 
						|
     * @return true if it is equal
 | 
						|
     * @throws ConcurrentModificationException if the entry was invalidated
 | 
						|
     *         by modifying the Map or calling Iterator.remove()
 | 
						|
     */
 | 
						|
    public boolean equals(Object o)
 | 
						|
    {
 | 
						|
      if (knownMod != modCount || table[loc] == tombstone)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      if (! (o instanceof Map.Entry))
 | 
						|
        return false;
 | 
						|
      Map.Entry e = (Map.Entry) o;
 | 
						|
      return table[loc] == e.getKey() && table[loc + 1] == e.getValue();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the key of this entry.
 | 
						|
     *
 | 
						|
     * @return the key
 | 
						|
     * @throws ConcurrentModificationException if the entry was invalidated
 | 
						|
     *         by modifying the Map or calling Iterator.remove()
 | 
						|
     */
 | 
						|
    public Object getKey()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount || table[loc] == tombstone)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      return table[loc];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the value of this entry.
 | 
						|
     *
 | 
						|
     * @return the value
 | 
						|
     * @throws ConcurrentModificationException if the entry was invalidated
 | 
						|
     *         by modifying the Map or calling Iterator.remove()
 | 
						|
     */
 | 
						|
    public Object getValue()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount || table[loc] == tombstone)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      return table[loc + 1];
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the hashcode of the entry, using identity semantics.
 | 
						|
     * Note that this can lead to undefined results with Entry objects
 | 
						|
     * created by normal maps.
 | 
						|
     *
 | 
						|
     * @return the hash code
 | 
						|
     * @throws ConcurrentModificationException if the entry was invalidated
 | 
						|
     *         by modifying the Map or calling Iterator.remove()
 | 
						|
     */
 | 
						|
    public int hashCode()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount || table[loc] == tombstone)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      return (System.identityHashCode(table[loc])
 | 
						|
              ^ System.identityHashCode(table[loc + 1]));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Replaces the value of this mapping, and returns the old value.
 | 
						|
     *
 | 
						|
     * @param value the new value
 | 
						|
     * @return the old value
 | 
						|
     * @throws ConcurrentModificationException if the entry was invalidated
 | 
						|
     *         by modifying the Map or calling Iterator.remove()
 | 
						|
     */
 | 
						|
    public Object setValue(Object value)
 | 
						|
    {
 | 
						|
      if (knownMod != modCount || table[loc] == tombstone)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      Object r = table[loc + 1];
 | 
						|
      table[loc + 1] = value;
 | 
						|
      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
 | 
						|
     * @throws ConcurrentModificationException if the entry was invalidated
 | 
						|
     *         by modifying the Map or calling Iterator.remove()
 | 
						|
     */
 | 
						|
    public final String toString()
 | 
						|
    {
 | 
						|
      if (knownMod != modCount || table[loc] == tombstone)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
      return table[loc] + "=" + table[loc + 1];
 | 
						|
    }
 | 
						|
  } // class IdentityEntry
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads the object from a serial stream.
 | 
						|
   *
 | 
						|
   * @param s the stream to read from
 | 
						|
   * @throws ClassNotFoundException if the underlying stream fails
 | 
						|
   * @throws IOException if the underlying stream fails
 | 
						|
   * @serialData expects the size (int), followed by that many key (Object)
 | 
						|
   *             and value (Object) pairs, with the pairs in no particular
 | 
						|
   *             order
 | 
						|
   */
 | 
						|
  private void readObject(ObjectInputStream s)
 | 
						|
    throws IOException, ClassNotFoundException
 | 
						|
  {
 | 
						|
    s.defaultReadObject();
 | 
						|
 | 
						|
    int num = s.readInt();
 | 
						|
    table = new Object[2 * Math.max(num * 2, DEFAULT_CAPACITY)];
 | 
						|
    // Read key/value pairs.
 | 
						|
    while (--num >= 0)
 | 
						|
      put(s.readObject(), s.readObject());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Writes the object to a serial stream.
 | 
						|
   *
 | 
						|
   * @param s the stream to write to
 | 
						|
   * @throws IOException if the underlying stream fails
 | 
						|
   * @serialData outputs the size (int), followed by that many key (Object)
 | 
						|
   *             and value (Object) pairs, with the pairs in no particular
 | 
						|
   *             order
 | 
						|
   */
 | 
						|
  private void writeObject(ObjectOutputStream s)
 | 
						|
    throws IOException
 | 
						|
  {
 | 
						|
    s.defaultWriteObject();
 | 
						|
    s.writeInt(size);
 | 
						|
    for (int i = table.length - 2; i >= 0; i -= 2)
 | 
						|
      {
 | 
						|
        Object key = table[i];
 | 
						|
        if (key != tombstone && key != emptyslot)
 | 
						|
          {
 | 
						|
            s.writeObject(key);
 | 
						|
            s.writeObject(table[i + 1]);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 |