Index: working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java =================================================================== --- working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java (revision 646000) +++ working_classlib/modules/luni/src/main/java/java/util/IdentityHashMap.java (working copy) @@ -47,8 +47,11 @@ * The internal data structure to hold key value pairs This array holds keys * and values in an alternating fashion. */ - transient Object[] elementData; + //transient Object[] elementData; + transient ElementArray keys, values; + + /* Actual number of key-value pairs. */ int size; @@ -136,15 +139,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 { @@ -159,12 +155,15 @@ throw new NoSuchElementException(); } +// System.err.println("IdentityHashMapIterator.next(): position=" + position); IdentityHashMapEntry result = associatedMap .getEntry(position); lastPosition = position; - position += 2; + position++; canRemove = true; +// System.err.println("Returning result="+result); + return type.get(result); } @@ -175,7 +174,7 @@ } canRemove = false; - associatedMap.remove(associatedMap.elementData[lastPosition]); + associatedMap.remove(associatedMap.keys.get(lastPosition)); position = lastPosition; expectedModCount++; } @@ -249,10 +248,15 @@ * this map. */ public IdentityHashMap(int maxSize) { + + // stub here, need to round to 2^k + maxSize = 16; + if (maxSize >= 0) { this.size = 0; threshold = getThreshold(maxSize); - elementData = newElementArray(computeElementArraySize()); + keys = new ElementArray(maxSize); + values = new ElementArray(maxSize); } else { throw new IllegalArgumentException(); } @@ -265,19 +269,9 @@ } private int computeElementArraySize() { - return (int) (((long) threshold * 10000) / loadFactor) * 2; + return (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]; - } /** * Create an IdentityHashMap using the given Map as initial values. @@ -307,9 +301,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 +319,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 +338,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 +354,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,11 +368,12 @@ 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)); } +// System.err.println("getEntry(O): return null;"); return null; } @@ -394,10 +382,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 +394,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 +415,24 @@ _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; + keys.put(index, _key); +// values.put(index, null); } // 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 +453,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 +495,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 +521,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 +531,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 +744,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 +763,91 @@ 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; + +// System.err.println("length = " + length + ", lengthMask = " + lengthMask + ", lengthMask2 = " + lengthMask2); + } + + /** + * 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) { +// System.err.println("findKey: length="+length+", index="+index+", lengthMask="+lengthMask); + if (storage[index] == key || (storage[index] == null)) { + /* + * Found the key, or the next empty spot (which means key is not + * in the table) + */ + break; + } + index = (index + 1) & lengthMask; + } +// System.err.println("findKey: length="+length+", index="+index); + 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; + } + + } + }