mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8186171: HashMap: Entry.setValue may not work after Iterator.remove() called for previous entries
Reviewed-by: martin, psandoz
This commit is contained in:
parent
76db7c6b61
commit
d9d91c1cc4
7 changed files with 350 additions and 29 deletions
|
@ -490,7 +490,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements Map.putAll and Map constructor
|
||||
* Implements Map.putAll and Map constructor.
|
||||
*
|
||||
* @param m the map
|
||||
* @param evict false when initially constructing this map, else
|
||||
|
@ -557,7 +557,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements Map.get and related methods
|
||||
* Implements Map.get and related methods.
|
||||
*
|
||||
* @param hash hash for key
|
||||
* @param key the key
|
||||
|
@ -612,7 +612,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements Map.put and related methods
|
||||
* Implements Map.put and related methods.
|
||||
*
|
||||
* @param hash hash for key
|
||||
* @param key the key
|
||||
|
@ -700,7 +700,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
threshold = newThr;
|
||||
@SuppressWarnings({"rawtypes","unchecked"})
|
||||
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
|
||||
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
|
||||
table = newTab;
|
||||
if (oldTab != null) {
|
||||
for (int j = 0; j < oldCap; ++j) {
|
||||
|
@ -800,7 +800,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements Map.remove and related methods
|
||||
* Implements Map.remove and related methods.
|
||||
*
|
||||
* @param hash hash for key
|
||||
* @param key the key
|
||||
|
@ -875,7 +875,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
public boolean containsValue(Object value) {
|
||||
Node<K,V>[] tab; V v;
|
||||
if ((tab = table) != null && size > 0) {
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next) {
|
||||
if ((v = e.value) == value ||
|
||||
(value != null && value.equals(v)))
|
||||
|
@ -927,7 +927,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e.key);
|
||||
}
|
||||
|
@ -975,7 +975,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e.value);
|
||||
}
|
||||
|
@ -1038,7 +1038,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e);
|
||||
}
|
||||
|
@ -1335,7 +1335,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next)
|
||||
action.accept(e.key, e.value);
|
||||
}
|
||||
|
@ -1351,7 +1351,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
throw new NullPointerException();
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
int mc = modCount;
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next) {
|
||||
e.value = function.apply(e.key, e.value);
|
||||
}
|
||||
|
@ -1394,9 +1394,10 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
/**
|
||||
* Save the state of the {@code HashMap} instance to a stream (i.e.,
|
||||
* serialize it).
|
||||
* Saves this map to a stream (that is, serializes it).
|
||||
*
|
||||
* @param s the stream
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @serialData The <i>capacity</i> of the HashMap (the length of the
|
||||
* bucket array) is emitted (int), followed by the
|
||||
* <i>size</i> (an int, the number of key-value
|
||||
|
@ -1415,8 +1416,11 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
/**
|
||||
* Reconstitute the {@code HashMap} instance from a stream (i.e.,
|
||||
* deserialize it).
|
||||
* Reconstitutes this map from a stream (that is, deserializes it).
|
||||
* @param s the stream
|
||||
* @throws ClassNotFoundException if the class of a serialized object
|
||||
* could not be found
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
@ -1445,7 +1449,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
|
||||
(int)ft : Integer.MAX_VALUE);
|
||||
@SuppressWarnings({"rawtypes","unchecked"})
|
||||
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
|
||||
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
|
||||
table = tab;
|
||||
|
||||
// Read the keys and values, and put the mappings in the HashMap
|
||||
|
@ -1830,7 +1834,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
|
||||
Node<K,V>[] tab;
|
||||
if (size > 0 && (tab = table) != null) {
|
||||
for (Node<K, V> e : tab) {
|
||||
for (Node<K,V> e : tab) {
|
||||
for (; e != null; e = e.next) {
|
||||
s.writeObject(e.key);
|
||||
s.writeObject(e.value);
|
||||
|
@ -1951,7 +1955,6 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
|
||||
/**
|
||||
* Forms tree of the nodes linked from this node.
|
||||
* @return root of tree
|
||||
*/
|
||||
final void treeify(Node<K,V>[] tab) {
|
||||
TreeNode<K,V> root = null;
|
||||
|
@ -2089,8 +2092,11 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
return;
|
||||
if (root.parent != null)
|
||||
root = root.root();
|
||||
if (root == null || root.right == null ||
|
||||
(rl = root.left) == null || rl.left == null) {
|
||||
if (root == null
|
||||
|| (movable
|
||||
&& (root.right == null
|
||||
|| (rl = root.left) == null
|
||||
|| rl.left == null))) {
|
||||
tab[index] = first.untreeify(map); // too small
|
||||
return;
|
||||
}
|
||||
|
@ -2319,7 +2325,7 @@ public class HashMap<K,V> extends AbstractMap<K,V>
|
|||
|
||||
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
|
||||
TreeNode<K,V> x) {
|
||||
for (TreeNode<K,V> xp, xpl, xpr;;) {
|
||||
for (TreeNode<K,V> xp, xpl, xpr;;) {
|
||||
if (x == null || x == root)
|
||||
return root;
|
||||
else if ((xp = x.parent) == null) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue