Index: working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java =================================================================== --- working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java (revision 647500) +++ working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java (working copy) @@ -47,8 +47,9 @@ * The internal data structure to hold key value pairs This array holds keys * and values in an alternating fashion. */ - transient Object[] elementData; + transient ElementArray keys, values; + /* Actual number of key-value pairs. */ int size; @@ -136,15 +137,8 @@ } public boolean hasNext() { - while (position < associatedMap.elementData.length) { - // if this is an empty spot, go to the next one - if (associatedMap.elementData[position] == null) { - position += 2; - } else { - return true; - } - } - return false; + int p = position; + return (p < associatedMap.keys.getLength() && (associatedMap.keys.get(p) != null)); } void checkConcurrentMod() throws ConcurrentModificationException { @@ -162,9 +156,10 @@ IdentityHashMapEntry result = associatedMap .getEntry(position); lastPosition = position; - position += 2; + position++; canRemove = true; + return type.get(result); } @@ -175,7 +170,7 @@ } canRemove = false; - associatedMap.remove(associatedMap.elementData[lastPosition]); + associatedMap.remove(associatedMap.keys.get(lastPosition)); position = lastPosition; expectedModCount++; } @@ -252,7 +247,9 @@ if (maxSize >= 0) { this.size = 0; threshold = getThreshold(maxSize); - elementData = newElementArray(computeElementArraySize()); + int eaSize = computeElementArraySize(); + keys = new ElementArray(eaSize); + values = new ElementArray(eaSize); } else { throw new IllegalArgumentException(); } @@ -265,20 +262,20 @@ } private int computeElementArraySize() { - return (int) (((long) threshold * 10000) / loadFactor) * 2; - } + int s = (int) (((long) threshold * 10000) / loadFactor); - /** - * 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]; + // rounding to next power of 2 + s |= (s >> 1); + s |= (s >> 2); + s |= (s >> 4); + s |= (s >> 8); + s |= (s >> 16); + int proposed = s + 1; + + return proposed; } + /** * Create an IdentityHashMap using the given Map as initial values. * @@ -307,9 +304,8 @@ @Override public void clear() { size = 0; - for (int i = 0; i < elementData.length; i++) { - elementData[i] = null; - } + keys.clear(); + values.clear(); modCount++; } @@ -326,8 +322,8 @@ key = NULL_OBJECT; } - int index = findIndex(key, elementData); - return elementData[index] == key; + int index = keys.findKey(key); + return keys.get(index) == key; } /** @@ -345,12 +341,7 @@ value = NULL_OBJECT; } - for (int i = 1; i < elementData.length; i = i + 2) { - if (elementData[i] == value) { - return true; - } - } - return false; + return values.findValue(value); } /** @@ -366,11 +357,10 @@ key = NULL_OBJECT; } - int index = findIndex(key, elementData); + int index = keys.findKey(key); - if (elementData[index] == key) { - Object result = elementData[index + 1]; - return massageValue(result); + if (keys.get(index) == key) { + return massageValue(values.get(index)); } return null; @@ -381,9 +371,9 @@ key = NULL_OBJECT; } - int index = findIndex(key, elementData); - if (elementData[index] == key) { - return getEntry(index); + int index = keys.findKey(key); + if (keys.get(index) == key) { + return getEntry(key, values.get(index)); } return null; @@ -394,10 +384,7 @@ * NULL_OBJECT elements */ @SuppressWarnings("unchecked") - private IdentityHashMapEntry getEntry(int index) { - Object key = elementData[index]; - Object value = elementData[index + 1]; - + private IdentityHashMapEntry getEntry(Object key, Object value) { if (key == NULL_OBJECT) { key = null; } @@ -409,31 +396,6 @@ } /** - * 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. - */ - 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; - } - return index; - } - - 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 @@ -455,24 +417,23 @@ _value = NULL_OBJECT; } - int index = findIndex(_key, elementData); + int index = keys.findKey(_key); // if the key doesn't exist in the table - if (elementData[index] != _key) { + if (keys.get(index) != _key) { modCount++; if (++size > threshold) { rehash(); - index = findIndex(_key, elementData); + index = keys.findKey(_key); } - // insert the key and assign the value to null initially - elementData[index] = _key; - elementData[index + 1] = null; + // insert the key + keys.put(index, _key); } // insert value to where it needs to go, return the old value - Object result = elementData[index + 1]; - elementData[index + 1] = _value; + Object result = values.get(index); + values.put(index, _value); return massageValue(result); } @@ -493,26 +454,29 @@ } private void rehash() { - int newlength = elementData.length << 1; + int newlength = keys.getLength() << 1; if (newlength == 0) { newlength = 1; } - Object[] newData = newElementArray(newlength); - for (int i = 0; i < elementData.length; i = i + 2) { - Object key = elementData[i]; + ElementArray newKeys = new ElementArray(newlength); + ElementArray newValues = new ElementArray(newlength); + + for (int i = 0; i < keys.getLength(); i++) { + Object key = keys.get(i); if (key != null) { // if not empty - int index = findIndex(key, newData); - newData[index] = key; - newData[index + 1] = elementData[i + 1]; + int index = newKeys.findKey(key); + newKeys.put(index, key); + newValues.put(index, values.get(i)); } } - elementData = newData; + keys = newKeys; + values = newValues; computeMaxSize(); } private void computeMaxSize() { - threshold = (int) ((long) (elementData.length / 2) * loadFactor / 10000); + threshold = (int) ((long) (keys.getLength()) * loadFactor / 10000); } /** @@ -532,26 +496,25 @@ boolean hashedOk; int index, next, hash; Object result, object; - index = next = findIndex(key, elementData); + index = next = keys.findKey(key); - if (elementData[index] != key) { + if (keys.get(index) != key) { return null; } // store the value for this key - result = elementData[index + 1]; + result = values.get(index); // 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]; + next = (next + 1) & keys.getLengthMask(); + object = keys.get(next); if (object == null) { break; } - hash = getModuloHash(object, length); + hash = keys.getModuloHash(object); hashedOk = hash > index; if (next < index) { hashedOk = hashedOk || (hash <= next); @@ -559,8 +522,8 @@ hashedOk = hashedOk && (hash <= next); } if (!hashedOk) { - elementData[index] = object; - elementData[index + 1] = elementData[next + 1]; + keys.put(index, object); + values.put(index, values.get(next)); index = next; } } @@ -569,8 +532,8 @@ modCount++; // clear both the key and the value - elementData[index] = null; - elementData[index + 1] = null; + keys.put(index, null); + values.put(index, null); return massageValue(result); } @@ -782,8 +745,13 @@ ClassNotFoundException { stream.defaultReadObject(); int savedSize = stream.readInt(); + + // useless. threshold = getThreshold(DEFAULT_MAX_SIZE); - elementData = newElementArray(computeElementArraySize()); + + int eaSize = computeElementArraySize(); + values = new ElementArray(eaSize); + keys = new ElementArray(eaSize); for (int i = savedSize; --i >= 0;) { K key = (K) stream.readObject(); put(key, (V) stream.readObject()); @@ -796,4 +764,83 @@ super.putAll(map); } } + + // key/value storage + class ElementArray { + + Object[] storage; + int length, lengthMask; + + public ElementArray(int size) { + storage = new Object[size]; + length = size; + recomputeMask(); + } + + public int getLength() { + return storage.length; + } + + public Object[] getArray() { + return storage; + } + + public Object get(int index) { + return storage[index]; + } + + public void clear() { + for(int c = 0; c < length; c++) { + storage[c] = null; + } + } + + public void put(int index, Object o) { + storage[index] = o; + } + + private void recomputeMask() { + lengthMask = 0; + int wLength = length; + while( wLength > 0 ) { + lengthMask = (lengthMask << 1) + 1; + wLength = wLength >> 1; + } + lengthMask = lengthMask >> 1; + } + + /** + * 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. + */ + public int findKey(Object key) { + + int index = getModuloHash(key); + int last = (index + length - 1) & lengthMask; + while (index != last) { + if (storage[index] == key || (storage[index] == null)) { + break; + } + index = (index + 1) & lengthMask; + } + return index; + } + + public boolean findValue(Object value) { + for (int i = 0; i < length; i++) { + if (storage[i] == value) return true; + } + return false; + } + + public int getModuloHash(Object key) { + return (System.identityHashCode(key) & lengthMask); + } + + public int getLengthMask() { + return lengthMask; + } + + } + }