Fix iterator remove bug.
See the test case for details of the bug.
To put an end to these bugs I decided to simplify with a small
additional cost on removal.
Simpler is saner...
Change-Id: If64056d90b71c226b9c07ee99ab5c8ff76ded57d
Review-Link: https://gwt-review.googlesource.com/#/c/13489/
diff --git a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
index 19a0011..1d78932 100644
--- a/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
+++ b/user/super/com/google/gwt/emul/java/util/InternalHashCodeMap.java
@@ -75,6 +75,7 @@
Entry<K, V> entry = chain[i];
if (host.equals(key, entry.getKey())) {
if (chain.length == 1) {
+ ArrayHelper.setLength(chain, 0);
// remove the whole array
backingMap.delete(hashCode);
} else {
@@ -112,7 +113,6 @@
final InternalJsIterator<Object> chains = backingMap.entries();
int itemIndex = 0;
Entry<K, V>[] chain = newEntryChain();
- Entry<K, V>[] lastChain = null;
Entry<K, V> lastEntry = null;
@Override
@@ -134,7 +134,6 @@
public Entry<K, V> next() {
checkElement(hasNext());
- lastChain = chain;
lastEntry = chain[itemIndex++];
return lastEntry;
}
@@ -143,14 +142,11 @@
public void remove() {
checkState(lastEntry != null);
- boolean isLastChain = itemIndex == lastChain.length;
InternalHashCodeMap.this.remove(lastEntry.getKey());
-
- // If this was not the last item in the chain, our itemIndex just jumped an item.
- if (!isLastChain) {
+ // Unless we are in a new chain, all items have shifted so our itemIndex should as well...
+ if (itemIndex != 0) {
itemIndex--;
}
-
lastEntry = null;
}
};
diff --git a/user/test/com/google/gwt/emultest/java/util/HashMapTest.java b/user/test/com/google/gwt/emultest/java/util/HashMapTest.java
index 28f232f..81054aa 100644
--- a/user/test/com/google/gwt/emultest/java/util/HashMapTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/HashMapTest.java
@@ -758,7 +758,7 @@
}
// see: https://github.com/gwtproject/gwt/issues/9184
- public void testIterationWithCollidingHashCodes() {
+ public void testIteration_withCollidingHashCodes() {
Object firstKey = createObjectWithHashCode(1);
Object secondKey = createObjectWithHashCode(1);
@@ -793,7 +793,7 @@
}
// see: https://github.com/gwtproject/gwt/issues/9184
- public void testIterationWithCollidingHashCodes_FullIteration() {
+ public void testIteration_withCollidingHashCodesAndFullIteration() {
List<Object> keys = new ArrayList<>();
HashMap<Object, String> testMap = new HashMap<>();
@@ -818,6 +818,22 @@
assertTrue(keys.isEmpty());
}
+ public void testIteration_hasNextThenRemove() {
+ HashMap<Object, String> testMap = new HashMap<>();
+ testMap.put(createObjectWithHashCode(1), "one");
+ testMap.put(createObjectWithHashCode(2), "two");
+
+ Iterator<Object> it = testMap.keySet().iterator();
+ it.next();
+ assertTrue("iterator should have next after first", it.hasNext());
+ it.remove();
+ assertTrue("iterator should have next after removal", it.hasNext());
+
+ it.next();
+ it.remove();
+ assertFalse(it.hasNext());
+ }
+
private Object createObjectWithHashCode(final int hashCode) {
return new Object() {
@Override