--- old/src/share/classes/java/util/IdentityHashMap.java 2014-07-08 13:13:27.759540024 +0200 +++ new/src/share/classes/java/util/IdentityHashMap.java 2014-07-08 13:13:27.664541727 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ * maximum size and the number of buckets is unspecified. * *
If the size of the map (the number of key-value mappings) sufficiently
- * exceeds the expected maximum size, the number of buckets is increased
+ * exceeds the expected maximum size, the number of buckets is increased.
* Increasing the number of buckets ("rehashing") may be fairly expensive, so
* it pays to create identity hash maps with a sufficiently large expected
* maximum size. On the other hand, iteration over collection views requires
@@ -160,6 +160,10 @@
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<29.
+ *
+ * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
+ * because it has to have at least one slot with the key == null
+ * in order to avoid infinite loops in get(), put(), remove()
*/
private static final int MAXIMUM_CAPACITY = 1 << 29;
@@ -181,11 +185,6 @@
transient int modCount;
/**
- * The next size value at which to resize (capacity * load factor).
- */
- private transient int threshold;
-
- /**
* Value representing null keys inside tables.
*/
static final Object NULL_KEY = new Object();
@@ -229,27 +228,19 @@
}
/**
- * Returns the appropriate capacity for the specified expected maximum
- * size. Returns the smallest power of two between MINIMUM_CAPACITY
- * and MAXIMUM_CAPACITY, inclusive, that is greater than
- * (3 * expectedMaxSize)/2, if such a number exists. Otherwise
- * returns MAXIMUM_CAPACITY. If (3 * expectedMaxSize)/2 is negative, it
- * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned.
- */
- private int capacity(int expectedMaxSize) {
- // Compute min capacity for expectedMaxSize given a load factor of 2/3
- int minCapacity = (3 * expectedMaxSize)/2;
-
- // Compute the appropriate capacity
- int result;
- if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) {
- result = MAXIMUM_CAPACITY;
- } else {
- result = MINIMUM_CAPACITY;
- while (result < minCapacity)
- result <<= 1;
- }
- return result;
+ * Returns the appropriate capacity for the given expected maximum size.
+ * Returns the smallest power of two between MINIMUM_CAPACITY and
+ * MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
+ * expectedMaxSize)/2, if such a number exists. Otherwise returns
+ * MAXIMUM_CAPACITY. If (3 * expectedMaxSize) is negative, it is assumed
+ * that overflow has occurred, and MAXIMUM_CAPACITY is returned.
+ */
+ private static int capacity(int expectedMaxSize) {
+ // assert expectedMaxSize >= 0;
+ return
+ (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
+ (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
+ Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
}
/**
@@ -262,7 +253,6 @@
// assert initCapacity >= MINIMUM_CAPACITY;
// assert initCapacity <= MAXIMUM_CAPACITY;
- threshold = (initCapacity * 2)/3;
table = new Object[2 * initCapacity];
}
@@ -445,11 +435,20 @@
i = nextKeyIndex(i, len);
}
+ if (size == MAXIMUM_CAPACITY - 1)
+ throw new IllegalStateException("Capacity exhausted.");
+
+ if (size >= len / 3 && resize(len)) { // len == 2 * current capacity.
+ tab = table;
+ len = tab.length;
+ i = hash(key, len);
+ while (tab[i] != null)
+ i = nextKeyIndex(i, len);
+ }
modCount++;
tab[i] = k;
tab[i + 1] = value;
- if (++size >= threshold)
- resize(len); // len == 2 * current capacity.
+ size++;
return null;
}
@@ -458,23 +457,19 @@
*
* @param newCapacity the new capacity, must be a power of two.
*/
- private void resize(int newCapacity) {
+ private boolean resize(int newCapacity) {
// assert (newCapacity & -newCapacity) == newCapacity; // power of 2
int newLength = newCapacity * 2;
Object[] oldTable = table;
int oldLength = oldTable.length;
- if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further
- if (threshold == MAXIMUM_CAPACITY-1)
- throw new IllegalStateException("Capacity exhausted.");
- threshold = MAXIMUM_CAPACITY-1; // Gigantic map!
- return;
+ if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
+ return false;
}
if (oldLength >= newLength)
- return;
+ return false;
Object[] newTable = new Object[newLength];
- threshold = newLength / 3;
for (int j = 0; j < oldLength; j += 2) {
Object key = oldTable[j];
@@ -490,6 +485,7 @@
}
}
table = newTable;
+ return true;
}
/**
@@ -504,7 +500,7 @@
int n = m.size();
if (n == 0)
return;
- if (n > threshold) // conservatively pre-expand
+ if (n > table.length / 3) // conservatively pre-expand
resize(capacity(n));
for (Entry extends K, ? extends V> e : m.entrySet())
@@ -542,7 +538,6 @@
return null;
i = nextKeyIndex(i, len);
}
-
}
/**
@@ -1306,8 +1301,7 @@
// Read in size (number of Mappings)
int size = s.readInt();
- // Allow for 33% growth (i.e., capacity is >= 2* size()).
- init(capacity((size*4)/3));
+ init(capacity(size));
// Read the keys and values, and put the mappings in the table
for (int i=0; i