8343426: ConcurrentSkipListMap.spliterator() can no longer split the stream

Co-authored-by: Doug Lea <dl@openjdk.org>
Reviewed-by: vklang
This commit is contained in:
Dr Heinz M. Kabutz 2024-11-14 09:17:02 +00:00 committed by Viktor Klang
parent a8152bdb9a
commit 2b57f402c4
2 changed files with 40 additions and 9 deletions

View file

@ -3221,14 +3221,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
}
// factory method for KeySpliterator
final KeySpliterator<K,V> keySpliterator() {
Index<K,V> h; Node<K,V> n; long est;
Index<K,V> h; Node<K,V> hn, n; long est;
VarHandle.acquireFence();
if ((h = head) == null) {
if ((h = head) == null || (hn = h.node) == null) {
n = null;
est = 0L;
}
else {
n = h.node;
n = hn.next;
est = getAdderCount();
}
return new KeySpliterator<K,V>(comparator, h, n, null, est);
@ -3307,14 +3307,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
// Almost the same as keySpliterator()
final ValueSpliterator<K,V> valueSpliterator() {
Index<K,V> h; Node<K,V> n; long est;
Index<K,V> h; Node<K,V> hn, n; long est;
VarHandle.acquireFence();
if ((h = head) == null) {
if ((h = head) == null || (hn = h.node) == null) {
n = null;
est = 0L;
}
else {
n = h.node;
n = hn.next;
est = getAdderCount();
}
return new ValueSpliterator<K,V>(comparator, h, n, null, est);
@ -3411,14 +3411,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
// Almost the same as keySpliterator()
final EntrySpliterator<K,V> entrySpliterator() {
Index<K,V> h; Node<K,V> n; long est;
Index<K,V> h; Node<K,V> hn, n; long est;
VarHandle.acquireFence();
if ((h = head) == null) {
if ((h = head) == null || (hn = h.node) == null) {
n = null;
est = 0L;
}
else {
n = h.node;
n = hn.next;
est = getAdderCount();
}
return new EntrySpliterator<K,V>(comparator, h, n, null, est);

View file

@ -1323,6 +1323,37 @@ public class ConcurrentSkipListMapTest extends JSR166TestCase {
}
}
/**
* Spliterators.trySplit() returns null with an empty map and non-null when
* it is not empty.
*/
public void testSpliterators() {
// To test JDK-8343426
ConcurrentSkipListMap<Integer, Integer> map = new ConcurrentSkipListMap<>();
for (int i = 1; i <= 1000; i++) map.put(i, i);
// ensure that the splits do happen
assertNotNull(map.keySet().spliterator().trySplit());
assertNotNull(map.entrySet().spliterator().trySplit());
assertNotNull(map.values().spliterator().trySplit());
// ensure that the splits return *all* the items in the set
assertEquals(500_500, map.keySet()
.parallelStream()
.mapToInt(Integer::valueOf)
.sum());
assertEquals(500_500, map.values()
.parallelStream()
.mapToInt(Integer::valueOf)
.sum());
assertEquals(500_500 * 2, map.entrySet()
.parallelStream()
.mapToInt(entry -> entry.getKey() + entry.getValue())
.sum());
map.clear();
assertNull(map.keySet().spliterator().trySplit());
assertNull(map.entrySet().spliterator().trySplit());
assertNull(map.values().spliterator().trySplit());
}
static void assertEq(Item i, int j) {
if (i == null)
mustEqual(j, -1);