Skip to content

Commit ac36b7d

Browse files
committed
8267452: Delegate forEachRemaining in Spliterators.iterator()
Reviewed-by: psandoz
1 parent d0d2ddc commit ac36b7d

File tree

2 files changed

+198
-5
lines changed

2 files changed

+198
-5
lines changed

src/java.base/share/classes/java/util/Spliterators.java

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -688,8 +688,22 @@ public T next() {
688688
throw new NoSuchElementException();
689689
else {
690690
valueReady = false;
691-
return nextElement;
691+
T t = nextElement;
692+
nextElement = null;
693+
return t;
694+
}
695+
}
696+
697+
@Override
698+
public void forEachRemaining(Consumer<? super T> action) {
699+
Objects.requireNonNull(action);
700+
if (valueReady) {
701+
valueReady = false;
702+
T t = nextElement;
703+
nextElement = null;
704+
action.accept(t);
692705
}
706+
spliterator.forEachRemaining(action);
693707
}
694708
}
695709

@@ -736,6 +750,16 @@ public int nextInt() {
736750
return nextElement;
737751
}
738752
}
753+
754+
@Override
755+
public void forEachRemaining(IntConsumer action) {
756+
Objects.requireNonNull(action);
757+
if (valueReady) {
758+
valueReady = false;
759+
action.accept(nextElement);
760+
}
761+
spliterator.forEachRemaining(action);
762+
}
739763
}
740764

741765
return new Adapter();
@@ -781,6 +805,16 @@ public long nextLong() {
781805
return nextElement;
782806
}
783807
}
808+
809+
@Override
810+
public void forEachRemaining(LongConsumer action) {
811+
Objects.requireNonNull(action);
812+
if (valueReady) {
813+
valueReady = false;
814+
action.accept(nextElement);
815+
}
816+
spliterator.forEachRemaining(action);
817+
}
784818
}
785819

786820
return new Adapter();
@@ -826,6 +860,16 @@ public double nextDouble() {
826860
return nextElement;
827861
}
828862
}
863+
864+
@Override
865+
public void forEachRemaining(DoubleConsumer action) {
866+
Objects.requireNonNull(action);
867+
if (valueReady) {
868+
valueReady = false;
869+
action.accept(nextElement);
870+
}
871+
spliterator.forEachRemaining(action);
872+
}
829873
}
830874

831875
return new Adapter();
@@ -1843,7 +1887,7 @@ public Comparator<? super T> getComparator() {
18431887
static final class IntIteratorSpliterator implements Spliterator.OfInt {
18441888
static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
18451889
static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
1846-
private PrimitiveIterator.OfInt it;
1890+
private final PrimitiveIterator.OfInt it;
18471891
private final int characteristics;
18481892
private long est; // size estimate
18491893
private int batch; // batch size for splits
@@ -1937,7 +1981,7 @@ public Comparator<? super Integer> getComparator() {
19371981
static final class LongIteratorSpliterator implements Spliterator.OfLong {
19381982
static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
19391983
static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
1940-
private PrimitiveIterator.OfLong it;
1984+
private final PrimitiveIterator.OfLong it;
19411985
private final int characteristics;
19421986
private long est; // size estimate
19431987
private int batch; // batch size for splits
@@ -2031,7 +2075,7 @@ public Comparator<? super Long> getComparator() {
20312075
static final class DoubleIteratorSpliterator implements Spliterator.OfDouble {
20322076
static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
20332077
static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
2034-
private PrimitiveIterator.OfDouble it;
2078+
private final PrimitiveIterator.OfDouble it;
20352079
private final int characteristics;
20362080
private long est; // size estimate
20372081
private int batch; // batch size for splits
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import org.testng.annotations.Test;
25+
26+
import java.util.ArrayList;
27+
import java.util.Arrays;
28+
import java.util.Iterator;
29+
import java.util.List;
30+
import java.util.NoSuchElementException;
31+
import java.util.PrimitiveIterator;
32+
import java.util.Spliterators;
33+
import java.util.function.DoubleConsumer;
34+
import java.util.function.IntConsumer;
35+
import java.util.function.LongConsumer;
36+
37+
import static org.testng.Assert.assertEquals;
38+
import static org.testng.Assert.assertFalse;
39+
import static org.testng.Assert.assertThrows;
40+
import static org.testng.Assert.fail;
41+
42+
/**
43+
* @test
44+
* @summary Spliterator.iterator traversing tests
45+
* @library /lib/testlibrary/bootlib
46+
* @run testng IteratorFromSpliteratorTest
47+
* @bug 8267452
48+
*/
49+
public class IteratorFromSpliteratorTest {
50+
@Test
51+
public void testIteratorFromSpliterator() {
52+
List<Integer> input = List.of(1, 2, 3, 4, 5);
53+
for (int i = 0; i < input.size(); i++) {
54+
Iterator<Integer> iterator = Spliterators.iterator(input.spliterator());
55+
List<Integer> result = new ArrayList<>();
56+
int j = i;
57+
while (j++ < input.size() && iterator.hasNext()) {
58+
result.add(iterator.next());
59+
}
60+
// While SpliteratorTraversingAndSplittingTest tests some scenarios with Spliterators.iterator
61+
// it always wraps the resulting iterator into spliterator again, and this limits the use patterns.
62+
// In particular, calling hasNext() right before forEachRemaining() is not tested.
63+
// Here we cover such a scenario.
64+
assertEquals(iterator.hasNext(), result.size() < input.size());
65+
iterator.forEachRemaining(result::add);
66+
iterator.forEachRemaining(x -> fail("Should not be called"));
67+
assertFalse(iterator.hasNext());
68+
assertThrows(NoSuchElementException.class, iterator::next);
69+
iterator.forEachRemaining(x -> fail("Should not be called"));
70+
assertEquals(result, input);
71+
}
72+
}
73+
74+
@Test
75+
public void testIteratorFromSpliteratorInt() {
76+
int[] input = {1, 2, 3, 4, 5};
77+
for (int i = 0; i < input.length; i++) {
78+
PrimitiveIterator.OfInt iterator = Spliterators.iterator(Arrays.spliterator(input));
79+
List<Integer> result = new ArrayList<>();
80+
int j = i;
81+
while (j++ < input.length && iterator.hasNext()) {
82+
result.add(iterator.nextInt());
83+
}
84+
assertEquals(iterator.hasNext(), result.size() < input.length);
85+
iterator.forEachRemaining((IntConsumer) result::add);
86+
iterator.forEachRemaining((IntConsumer) (x -> fail("Should not be called")));
87+
assertFalse(iterator.hasNext());
88+
assertThrows(NoSuchElementException.class, iterator::next);
89+
iterator.forEachRemaining((IntConsumer) (x -> fail("Should not be called")));
90+
assertEquals(result.stream().mapToInt(x -> x).toArray(), input);
91+
}
92+
}
93+
94+
@Test
95+
public void testIteratorFromSpliteratorLong() {
96+
long[] input = {1, 2, 3, 4, 5};
97+
for (int i = 0; i < input.length; i++) {
98+
PrimitiveIterator.OfLong iterator = Spliterators.iterator(Arrays.spliterator(input));
99+
List<Long> result = new ArrayList<>();
100+
int j = i;
101+
while (j++ < input.length && iterator.hasNext()) {
102+
result.add(iterator.nextLong());
103+
}
104+
assertEquals(iterator.hasNext(), result.size() < input.length);
105+
iterator.forEachRemaining((LongConsumer) result::add);
106+
iterator.forEachRemaining((LongConsumer) (x -> fail("Should not be called")));
107+
assertFalse(iterator.hasNext());
108+
assertThrows(NoSuchElementException.class, iterator::next);
109+
iterator.forEachRemaining((LongConsumer) (x -> fail("Should not be called")));
110+
assertEquals(result.stream().mapToLong(x -> x).toArray(), input);
111+
}
112+
}
113+
114+
@Test
115+
public void testIteratorFromSpliteratorDouble() {
116+
double[] input = {1, 2, 3, 4, 5};
117+
for (int i = 0; i < input.length; i++) {
118+
PrimitiveIterator.OfDouble iterator = Spliterators.iterator(Arrays.spliterator(input));
119+
List<Double> result = new ArrayList<>();
120+
int j = i;
121+
while (j++ < input.length && iterator.hasNext()) {
122+
result.add(iterator.nextDouble());
123+
}
124+
assertEquals(iterator.hasNext(), result.size() < input.length);
125+
iterator.forEachRemaining((DoubleConsumer) result::add);
126+
iterator.forEachRemaining((DoubleConsumer) (x -> fail("Should not be called")));
127+
assertFalse(iterator.hasNext());
128+
assertThrows(NoSuchElementException.class, iterator::next);
129+
iterator.forEachRemaining((DoubleConsumer) (x -> fail("Should not be called")));
130+
assertEquals(result.stream().mapToDouble(x -> x).toArray(), input);
131+
}
132+
}
133+
134+
@Test
135+
public void testIteratorFromSpliteratorEmpty() {
136+
Iterator<?>[] iterators = {
137+
Spliterators.iterator(Spliterators.emptySpliterator()),
138+
Spliterators.iterator(Spliterators.emptyIntSpliterator()),
139+
Spliterators.iterator(Spliterators.emptyLongSpliterator()),
140+
Spliterators.iterator(Spliterators.emptyDoubleSpliterator())
141+
};
142+
for (Iterator<?> iterator : iterators) {
143+
iterator.forEachRemaining(x -> fail("Should not be called"));
144+
assertFalse(iterator.hasNext());
145+
iterator.forEachRemaining(x -> fail("Should not be called"));
146+
assertThrows(NoSuchElementException.class, iterator::next);
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)