Index: working_classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java =================================================================== --- working_classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java (revision 650000) +++ working_classlib/modules/luni/src/test/api/common/org/apache/harmony/luni/tests/java/util/IdentityHashMapTest.java (working copy) @@ -252,8 +252,9 @@ map.put(key, value); result = vals.remove(key); - assertTrue("TestB. removed entries incorrectly", map.size() == 11 - && !result); + assertTrue("TestB. removed entries incorrectly, size is not correct: " + map.size(), map.size() == 11); + assertTrue("TestB. removed entries incorrectly, result is not correct", !result); + assertTrue("TestB. removed key incorrectly", map.containsKey(key)); assertTrue("TestB. removed value incorrectly", map.containsValue(value)); Index: working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java =================================================================== --- working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java (revision 650000) +++ working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java (working copy) @@ -23,123 +23,75 @@ import java.io.Serializable; /** - * IdentityHashMap - * - * This is a variant on HashMap which tests equality by reference instead of by - * value. Basically, keys and values are compared for equality by checking if - * their references are equal rather than by calling the "equals" function. - * - * IdentityHashMap uses open addressing (linear probing in particular) for - * collision resolution. This is different from HashMap which uses Chaining. - * - * Like HashMap, IdentityHashMap is not thread safe, so access by multiple - * threads must be synchronized by an external mechanism such as - * Collections.synchronizedMap. - * - * @since 1.4 + * IdentityHashMap is an implementation of Map. All optional operations are supported, + * adding and removing. Keys and values can be any objects. */ -public class IdentityHashMap extends AbstractMap implements - Map, Serializable, Cloneable { +public class IdentityHashMap extends AbstractMap implements Map, + Cloneable, Serializable { private static final long serialVersionUID = 8188218128353913216L; - /* - * The internal data structure to hold key value pairs This array holds keys - * and values in an alternating fashion. - */ - transient Object[] elementData; + transient Entry[] elementData; - /* Actual number of key-value pairs. */ int size; - /* - * maximum number of elements that can be put in this map before having to - * rehash. - */ transient int threshold; - /* - * default threshold value that an IdentityHashMap created using the default - * constructor would have. - */ - private static final int DEFAULT_MAX_SIZE = 21; - - /* Default load factor of 0.75; */ + private static final int DEFAULT_SIZE = 16; + private static final int loadFactor = 7500; - /* - * modification count, to keep track of structural modifications between the - * IdentityHashMap and the iterator - */ transient int modCount = 0; - /* - * Object used to represent null keys and values. This is used to - * differentiate a literal 'null' key value pair from an empty spot in the - * map. - */ - private static final Object NULL_OBJECT = new Object(); //$NON-LOCK-1$ + static class Entry extends MapEntry { + final int origKeyHash; - static class IdentityHashMapEntry extends MapEntry { - IdentityHashMapEntry(K theKey, V theValue) { + Entry next; + + Entry(K theKey, int hash) { + super(theKey, null); + this.origKeyHash = hash; + } + + Entry(K theKey, V theValue) { super(theKey, theValue); + origKeyHash = (theKey == null ? 0 : System.identityHashCode(theKey)); } @Override + @SuppressWarnings("unchecked") public Object clone() { - return super.clone(); - } - - @Override - public boolean equals(Object object) { - if (this == object) { - return true; + Entry entry = (Entry) super.clone(); + if (next != null) { + entry.next = (Entry) next.clone(); } - if (object instanceof Map.Entry) { - Map.Entry entry = (Map.Entry) object; - return (key == entry.getKey()) && (value == entry.getValue()); - } - return false; + return entry; } - - @Override - public int hashCode() { - return System.identityHashCode(key) - ^ System.identityHashCode(value); - } - - @Override - public String toString() { - return key + "=" + value; //$NON-NLS-1$ - } } - static class IdentityHashMapIterator implements Iterator { - private int position = 0; // the current position - - // the position of the entry that was last returned from next() - private int lastPosition = 0; - - final IdentityHashMap associatedMap; - + private static class AbstractMapIterator { + private int position = 0; int expectedModCount; + Entry futureEntry; + Entry currentEntry; + Entry prevEntry; - final MapEntry.Type type; + final IdentityHashMap associatedMap; - boolean canRemove = false; - IdentityHashMapIterator(MapEntry.Type value, - IdentityHashMap hm) { + AbstractMapIterator(IdentityHashMap hm) { associatedMap = hm; - type = value; expectedModCount = hm.modCount; + futureEntry = null; } public boolean hasNext() { + if (futureEntry != null) { + return true; + } while (position < associatedMap.elementData.length) { - // if this is an empty spot, go to the next one if (associatedMap.elementData[position] == null) { - position += 2; + position++; } else { return true; } @@ -147,42 +99,88 @@ return false; } - void checkConcurrentMod() throws ConcurrentModificationException { + final void checkConcurrentMod() throws ConcurrentModificationException { if (expectedModCount != associatedMap.modCount) { throw new ConcurrentModificationException(); } } - public E next() { + final void makeNext() { checkConcurrentMod(); if (!hasNext()) { throw new NoSuchElementException(); } - - IdentityHashMapEntry result = associatedMap - .getEntry(position); - lastPosition = position; - position += 2; - - canRemove = true; - return type.get(result); + if (futureEntry == null) { + currentEntry = associatedMap.elementData[position++]; + futureEntry = currentEntry.next; + prevEntry = null; + } else { + if(currentEntry!=null){ + prevEntry = currentEntry; + } + currentEntry = futureEntry; + futureEntry = futureEntry.next; + } } - public void remove() { + public final void remove() { checkConcurrentMod(); - if (!canRemove) { + if (currentEntry==null) { throw new IllegalStateException(); } + if(prevEntry==null){ + int index = currentEntry.origKeyHash & (associatedMap.elementData.length - 1); + //assert associatedMap.elementData[index] == currentEntry; + associatedMap.elementData[index] = associatedMap.elementData[index].next; + } else { + prevEntry.next = currentEntry.next; + } + currentEntry = null; + expectedModCount++; + associatedMap.modCount++; + associatedMap.size--; - canRemove = false; - associatedMap.remove(associatedMap.elementData[lastPosition]); - position = lastPosition; - expectedModCount++; } } - static class IdentityHashMapEntrySet extends - AbstractSet> { + + private static class EntryIterator extends AbstractMapIterator implements Iterator> { + + EntryIterator (IdentityHashMap map) { + super(map); + } + + public Map.Entry next() { + makeNext(); + return currentEntry; + } + } + + private static class KeyIterator extends AbstractMapIterator implements Iterator { + + KeyIterator (IdentityHashMap map) { + super(map); + } + + public K next() { + makeNext(); + return currentEntry.key; + } + } + + private static class ValueIterator extends AbstractMapIterator implements Iterator { + + ValueIterator (IdentityHashMap map) { + super(map); + } + + public V next() { + makeNext(); + return currentEntry.value; + } + } + + static class IdentityHashMapEntrySet extends AbstractSet> { private final IdentityHashMap associatedMap; public IdentityHashMapEntrySet(IdentityHashMap hm) { @@ -205,9 +203,13 @@ @Override public boolean remove(Object object) { - if (contains(object)) { - associatedMap.remove(((Map.Entry) object).getKey()); - return true; + if (object instanceof Map.Entry) { + Map.Entry oEntry = (Map.Entry) object; + Entry entry = associatedMap.getEntry(oEntry.getKey()); + if(valuesEq(entry, oEntry)) { + associatedMap.removeEntry(entry); + return true; + } } return false; } @@ -215,227 +217,301 @@ @Override public boolean contains(Object object) { if (object instanceof Map.Entry) { - IdentityHashMapEntry entry = associatedMap - .getEntry(((Map.Entry) object).getKey()); - // we must call equals on the entry obtained from "this" - return entry != null && entry.equals(object); + Map.Entry oEntry = (Map.Entry) object; + Entry entry = associatedMap.getEntry(oEntry.getKey()); + return valuesEq(entry, oEntry); } return false; } + private static boolean valuesEq(Entry entry, Map.Entry oEntry) { + return (entry != null) && + ((entry.value == null) ? + (oEntry.getValue() == null) : + (entry.value == oEntry.getValue())); + } + @Override public Iterator> iterator() { - return new IdentityHashMapIterator, KT, VT>( - new MapEntry.Type, KT, VT>() { - public Map.Entry get(MapEntry entry) { - return entry; - } - }, associatedMap); + return new EntryIterator (associatedMap); } } /** - * Create an IdentityHashMap with default maximum size + * Create a new element array + * + * @param s + * @return Reference to the element array */ + @SuppressWarnings("unchecked") + Entry[] newElementArray(int s) { + return new Entry[s]; + } + + /** + * Constructs a new empty instance of IdentityHashMap. + * + */ public IdentityHashMap() { - this(DEFAULT_MAX_SIZE); + this(DEFAULT_SIZE); } /** - * Create an IdentityHashMap with the given maximum size parameter - * - * @param maxSize - * The estimated maximum number of entries that will be put in - * this map. + * Constructs a new instance of IdentityHashMap with the specified capacity. + * + * @param capacity + * the initial capacity of this IdentityHashMap + * + * @exception IllegalArgumentException + * when the capacity is less than zero */ - public IdentityHashMap(int maxSize) { - if (maxSize >= 0) { - this.size = 0; - threshold = getThreshold(maxSize); - elementData = newElementArray(computeElementArraySize()); + public IdentityHashMap(int capacity) { + if (capacity >= 0) { + capacity = calculateCapacity(capacity); + size = 0; + elementData = newElementArray(capacity); + computeMaxSize(); } else { throw new IllegalArgumentException(); } } - private int getThreshold(int maxSize) { - // assign the threshold to maxSize initially, this will change to a - // higher value if rehashing occurs. - return maxSize > 3 ? maxSize : 3; + private static final int calculateCapacity(int x) { + if(x >= 1 << 30){ + return 1 << 30; + } + if(x == 0){ + return 16; + } + x = x -1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; } - private int computeElementArraySize() { - return (int) (((long) threshold * 10000) / loadFactor) * 2; - } - /** - * Create a new element array - * - * @param s - * the number of elements - * @return Reference to the element array - */ - private Object[] newElementArray(int s) { - return new Object[s]; - } - - /** - * Create an IdentityHashMap using the given Map as initial values. - * + * Constructs a new instance of IdentityHashMap containing the mappings from the + * specified Map. + * * @param map - * A map of (key,value) pairs to copy into the IdentityHashMap + * the mappings to add */ public IdentityHashMap(Map map) { this(map.size() < 6 ? 11 : map.size() * 2); putAllImpl(map); } - @SuppressWarnings("unchecked") - private V massageValue(Object value) { - return (V) ((value == NULL_OBJECT) ? null : value); - } - /** - * Removes all elements from this Map, leaving it empty. - * - * @exception UnsupportedOperationException - * when removing from this Map is not supported - * + * Removes all mappings from this IdentityHashMap, leaving it empty. + * * @see #isEmpty * @see #size */ @Override public void clear() { - size = 0; - for (int i = 0; i < elementData.length; i++) { - elementData[i] = null; + if (size > 0) { + size = 0; + Arrays.fill(elementData, null); + modCount++; } - modCount++; } /** - * Searches this Map for the specified key. - * + * Answers a new IdentityHashMap with the same mappings and size as this HashMap. + * + * @return a shallow copy of this IdentityHashMap + * + * @see java.lang.Cloneable + */ + @Override + @SuppressWarnings("unchecked") + public Object clone() { + try { + IdentityHashMap map = (IdentityHashMap) super.clone(); + map.size = 0; + map.elementData = newElementArray(elementData.length); + Entry entry; + for (int i = 0; i < elementData.length; i++) { + if ((entry = elementData[i]) != null){ + map.putImpl(entry.getKey(), entry.getValue()); + while (entry.next != null){ + entry = entry.next; + map.putImpl(entry.getKey(), entry.getValue()); + } + } + } + return map; + } catch (CloneNotSupportedException e) { + return null; + } + } + + private void computeMaxSize() { + threshold = (int) (elementData.length * loadFactor / 10000); + } + + /** + * Searches this IdentityHashMap for the specified key. + * * @param key * the object to search for - * @return true if key is a key of this Map, false otherwise + * @return true if key is a key of this IdentityHashMap, false + * otherwise */ @Override public boolean containsKey(Object key) { - if (key == null) { - key = NULL_OBJECT; - } - - int index = findIndex(key, elementData); - return elementData[index] == key; + Entry m = getEntry(key); + return m != null; } /** - * Searches this Map for the specified value. - * - * + * Searches this IdentityHashMap for the specified value. + * * @param value * the object to search for - * @return true if value is a value of this Map, false + * @return true if value is a value of this IdentityHashMap, false * otherwise */ @Override public boolean containsValue(Object value) { - if (value == null) { - value = NULL_OBJECT; - } - - for (int i = 1; i < elementData.length; i = i + 2) { - if (elementData[i] == value) { - return true; + if (value != null) { + for (int i = elementData.length; --i >= 0;) { + Entry entry = elementData[i]; + while (entry != null) { + if (value == entry.value) { + return true; + } + entry = entry.next; + } } + } else { + for (int i = elementData.length; --i >= 0;) { + Entry entry = elementData[i]; + while (entry != null) { + if (entry.value == null) { + return true; + } + entry = entry.next; + } + } } return false; } /** + * Answers a Set of the mappings contained in this IdentityHashMap. Each element in + * the set is a Map.Entry. The set is backed by this IdentityHashMap so changes to + * one are reflected by the other. The set does not support adding. + * + * @return a Set of the mappings + */ + @Override + public Set> entrySet() { + return new IdentityHashMapEntrySet(this); + } + + /** * Answers the value of the mapping with the specified key. - * + * * @param key * the key * @return the value of the mapping with the specified key */ @Override public V get(Object key) { - if (key == null) { - key = NULL_OBJECT; + Entry m = getEntry(key); + if (m != null) { + return m.value; } - - int index = findIndex(key, elementData); - - if (elementData[index] == key) { - Object result = elementData[index + 1]; - return massageValue(result); - } - return null; } - private IdentityHashMapEntry getEntry(Object key) { + final Entry getEntry(Object key) { + Entry m; if (key == null) { - key = NULL_OBJECT; + m = findNullKeyEntry(); + } else { + int hash = System.identityHashCode(key); + int index = hash & (elementData.length - 1); + m = findNonNullKeyEntry(key, index, hash); } + return m; + } - int index = findIndex(key, elementData); - if (elementData[index] == key) { - return getEntry(index); + final Entry findNonNullKeyEntry(Object key, int index, int keyHash) { + Entry m = elementData[index]; + while (m != null && (m.origKeyHash != keyHash || (key != m.key))) { + m = m.next; } + return m; + } - return null; + final Entry findNullKeyEntry() { + Entry m = elementData[0]; + while (m != null && m.key != null) + m = m.next; + return m; } /** - * Convenience method for getting the IdentityHashMapEntry without the - * NULL_OBJECT elements + * Answers if this IdentityHashMap has no elements, a size of zero. + * + * @return true if this IdentityHashMap has no elements, false otherwise + * + * @see #size */ - @SuppressWarnings("unchecked") - private IdentityHashMapEntry getEntry(int index) { - Object key = elementData[index]; - Object value = elementData[index + 1]; - - if (key == NULL_OBJECT) { - key = null; - } - if (value == NULL_OBJECT) { - value = null; - } - - return new IdentityHashMapEntry((K) key, (V) value); + @Override + public boolean isEmpty() { + return size == 0; } /** - * Returns the index where the key is found at, or the index of the next - * empty spot if the key is not found in this table. + * Answers a Set of the keys contained in this IdentityHashMap. The set is backed by + * this IdentityHashMap so changes to one are reflected by the other. The set does + * not support adding. + * + * @return a Set of the keys */ - private int findIndex(Object key, Object[] array) { - int length = array.length; - int index = getModuloHash(key, length); - int last = (index + length - 2) % length; - while (index != last) { - if (array[index] == key || (array[index] == null)) { - /* - * Found the key, or the next empty spot (which means key is not - * in the table) - */ - break; - } - index = (index + 2) % length; + @Override + public Set keySet() { + if (keySet == null) { + keySet = new AbstractSet() { + @Override + public boolean contains(Object object) { + return containsKey(object); + } + + @Override + public int size() { + return IdentityHashMap.this.size(); + } + + @Override + public void clear() { + IdentityHashMap.this.clear(); + } + + @Override + public boolean remove(Object key) { + Entry entry = IdentityHashMap.this.removeEntry(key); + return entry != null; + } + + @Override + public Iterator iterator() { + return new KeyIterator (IdentityHashMap.this); + } + }; } - return index; + return keySet; } - private int getModuloHash(Object key, int length) { - return ((System.identityHashCode(key) & 0x7FFFFFFF) % (length / 2)) * 2; - } - /** * Maps the specified key to the specified value. - * + * * @param key * the key * @param value @@ -445,43 +521,58 @@ */ @Override public V put(K key, V value) { - Object _key = key; - Object _value = value; - if (_key == null) { - _key = NULL_OBJECT; - } + return putImpl(key, value); + } - if (_value == null) { - _value = NULL_OBJECT; + V putImpl(K key, V value) { + Entry entry; + if(key == null) { + entry = findNullKeyEntry(); + if (entry == null) { + modCount++; + if (++size > threshold) { + rehash(); + } + entry = createHashedEntry(null, 0, 0); + } + } else { + int hash = System.identityHashCode(key); + int index = hash & (elementData.length - 1); + entry = findNonNullKeyEntry(key, index, hash); + if (entry == null) { + modCount++; + if (++size > threshold) { + rehash(); + index = hash & (elementData.length - 1); + } + entry = createHashedEntry(key, index, hash); + } } - int index = findIndex(_key, elementData); + V result = entry.value; + entry.value = value; + return result; + } - // if the key doesn't exist in the table - if (elementData[index] != _key) { - modCount++; - if (++size > threshold) { - rehash(); - index = findIndex(_key, elementData); - } + Entry createEntry(K key, int index, V value) { + Entry entry = new Entry(key, value); + entry.next = elementData[index]; + elementData[index] = entry; + return entry; + } - // insert the key and assign the value to null initially - elementData[index] = _key; - elementData[index + 1] = null; - } + Entry createHashedEntry(K key, int index, int hash) { + Entry entry = new Entry(key,hash); + entry.next = elementData[index]; + elementData[index] = entry; + return entry; + } - // insert value to where it needs to go, return the old value - Object result = elementData[index + 1]; - elementData[index + 1] = _value; - - return massageValue(result); - } - /** * Copies all the mappings in the given map to this map. These mappings will * replace all mappings that this map had for any of the keys currently in * the given map. - * + * * @param map * the Map to copy mappings from * @throws NullPointerException @@ -489,159 +580,125 @@ */ @Override public void putAll(Map map) { - putAllImpl(map); + if (!map.isEmpty()) { + putAllImpl(map); + } } - private void rehash() { - int newlength = elementData.length << 1; - if (newlength == 0) { - newlength = 1; + private void putAllImpl(Map map) { + if (map.size() == 0) return; + + int capacity = size + map.size(); + if (capacity > threshold) { + rehash(capacity); } - Object[] newData = newElementArray(newlength); - for (int i = 0; i < elementData.length; i = i + 2) { - Object key = elementData[i]; - if (key != null) { - // if not empty - int index = findIndex(key, newData); - newData[index] = key; - newData[index + 1] = elementData[i + 1]; + for (Map.Entry entry : map.entrySet()) { + putImpl(entry.getKey(), entry.getValue()); + } + } + + void rehash(int capacity) { + int length = calculateCapacity((capacity == 0 ? 1 : capacity << 1)); + + Entry[] newData = newElementArray(length); + for (int i = 0; i < elementData.length; i++) { + Entry entry = elementData[i]; + while (entry != null) { + int index = entry.origKeyHash & (length - 1); + Entry next = entry.next; + entry.next = newData[index]; + newData[index] = entry; + entry = next; } } elementData = newData; computeMaxSize(); } - private void computeMaxSize() { - threshold = (int) ((long) (elementData.length / 2) * loadFactor / 10000); + void rehash() { + rehash(elementData.length); } /** * Removes a mapping with the specified key from this IdentityHashMap. - * + * * @param key * the key of the mapping to remove - * @return the value of the removed mapping, or null if key is not a key in - * this Map + * @return the value of the removed mapping or null if key is not a key in + * this IdentityHashMap */ @Override public V remove(Object key) { - if (key == null) { - key = NULL_OBJECT; + Entry entry = removeEntry(key); + if (entry != null) { + return entry.value; } + return null; + } - boolean hashedOk; - int index, next, hash; - Object result, object; - index = next = findIndex(key, elementData); + final void removeEntry(Entry entry) { + int index = entry.origKeyHash & (elementData.length - 1); + Entry m = elementData[index]; + if (m == entry) { + elementData[index] = entry.next; + } else { + while (m.next != entry && m.next != null) { + m = m.next; + } + m.next = entry.next; - if (elementData[index] != key) { - return null; } + modCount++; + size--; + } - // store the value for this key - result = elementData[index + 1]; - - // shift the following elements up if needed - // until we reach an empty spot - int length = elementData.length; - while (true) { - next = (next + 2) % length; - object = elementData[next]; - if (object == null) { - break; + final Entry removeEntry(Object key) { + int index = 0; + Entry entry; + Entry last = null; + if (key != null) { + int hash = System.identityHashCode(key); + index = hash & (elementData.length - 1); + entry = elementData[index]; + while (entry != null && !(entry.origKeyHash == hash && key == entry.key)) { + last = entry; + entry = entry.next; } - - hash = getModuloHash(object, length); - hashedOk = hash > index; - if (next < index) { - hashedOk = hashedOk || (hash <= next); - } else { - hashedOk = hashedOk && (hash <= next); + } else { + entry = elementData[0]; + while (entry != null && entry.key != null) { + last = entry; + entry = entry.next; } - if (!hashedOk) { - elementData[index] = object; - elementData[index + 1] = elementData[next + 1]; - index = next; - } } - + if (entry == null) { + return null; + } + if (last == null) { + elementData[index] = entry.next; + } else { + last.next = entry.next; + } + modCount++; size--; - modCount++; - - // clear both the key and the value - elementData[index] = null; - elementData[index + 1] = null; - - return massageValue(result); + return entry; } /** - * Answers a Set of the mappings contained in this IdentityHashMap. Each - * element in the set is a Map.Entry. The set is backed by this Map so - * changes to one are reflected by the other. The set does not support - * adding. - * - * @return a Set of the mappings + * Answers the number of mappings in this IdentityHashMap. + * + * @return the number of mappings in this IdentityHashMap */ @Override - public Set> entrySet() { - return new IdentityHashMapEntrySet(this); + public int size() { + return size; } /** - * Answers a Set of the keys contained in this IdentityHashMap. The set is - * backed by this IdentityHashMap so changes to one are reflected by the - * other. The set does not support adding. - * - * @return a Set of the keys - */ - @Override - public Set keySet() { - if (keySet == null) { - keySet = new AbstractSet() { - @Override - public boolean contains(Object object) { - return containsKey(object); - } - - @Override - public int size() { - return IdentityHashMap.this.size(); - } - - @Override - public void clear() { - IdentityHashMap.this.clear(); - } - - @Override - public boolean remove(Object key) { - if (containsKey(key)) { - IdentityHashMap.this.remove(key); - return true; - } - return false; - } - - @Override - public Iterator iterator() { - return new IdentityHashMapIterator( - new MapEntry.Type() { - public K get(MapEntry entry) { - return entry.key; - } - }, IdentityHashMap.this); - } - }; - } - return keySet; - } - - /** * Answers a Collection of the values contained in this IdentityHashMap. The - * collection is backed by this IdentityHashMap so changes to one are - * reflected by the other. The collection does not support adding. - * + * collection is backed by this IdentityHashMap so changes to one are reflected by + * the other. The collection does not support adding. + * * @return a Collection of the values */ @Override @@ -665,12 +722,7 @@ @Override public Iterator iterator() { - return new IdentityHashMapIterator( - new MapEntry.Type() { - public V get(MapEntry entry) { - return entry.value; - } - }, IdentityHashMap.this); + return new ValueIterator (IdentityHashMap.this); } @Override @@ -684,6 +736,8 @@ } return false; } + + }; } return valuesCollection; @@ -727,53 +781,15 @@ return false; } - /** - * Answers a new IdentityHashMap with the same mappings and size as this - * one. - * - * @return a shallow copy of this IdentityHashMap - * - * @see java.lang.Cloneable - */ - @Override - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - return null; - } - } - - /** - * Answers if this IdentityHashMap has no elements, a size of zero. - * - * @return true if this IdentityHashMap has no elements, false otherwise - * - * @see #size - */ - @Override - public boolean isEmpty() { - return size == 0; - } - - /** - * Answers the number of mappings in this IdentityHashMap. - * - * @return the number of mappings in this IdentityHashMap - */ - @Override - public int size() { - return size; - } - private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeInt(size); Iterator iterator = entrySet().iterator(); while (iterator.hasNext()) { - MapEntry entry = (MapEntry) iterator.next(); + Entry entry = (Entry) iterator.next(); stream.writeObject(entry.key); stream.writeObject(entry.value); + entry = entry.next; } } @@ -782,18 +798,14 @@ ClassNotFoundException { stream.defaultReadObject(); int savedSize = stream.readInt(); - threshold = getThreshold(DEFAULT_MAX_SIZE); - elementData = newElementArray(computeElementArraySize()); - for (int i = savedSize; --i >= 0;) { + int length = calculateCapacity(savedSize); + elementData = newElementArray(length); + for (int i = size; --i >= 0;) { K key = (K) stream.readObject(); - put(key, (V) stream.readObject()); + int index = (null == key) ? 0 : (System.identityHashCode(key) & (length - 1)); + createEntry(key, index, (V) stream.readObject()); } size = savedSize; } - - private void putAllImpl(Map map) { - if (map.entrySet() != null) { - super.putAll(map); - } - } + }