diff --git a/jdk/src/share/classes/java/util/stream/DoubleStream.java b/jdk/src/share/classes/java/util/stream/DoubleStream.java index 55d244fc4c3..1b058abdf8b 100644 --- a/jdk/src/share/classes/java/util/stream/DoubleStream.java +++ b/jdk/src/share/classes/java/util/stream/DoubleStream.java @@ -746,4 +746,26 @@ public interface DoubleStream extends BaseStream { return StreamSupport.doubleStream( new StreamSpliterators.InfiniteSupplyingSpliterator.OfDouble(Long.MAX_VALUE, s)); } + + /** + * Creates a lazy concatenated {@code DoubleStream} whose elements are all the + * elements of a first {@code DoubleStream} succeeded by all the elements of the + * second {@code DoubleStream}. The resulting stream is ordered if both + * of the input streams are ordered, and parallel if either of the input + * streams is parallel. + * + * @param a the first stream + * @param b the second stream to concatenate on to end of the first stream + * @return the concatenation of the two streams + */ + public static DoubleStream concat(DoubleStream a, DoubleStream b) { + Objects.requireNonNull(a); + Objects.requireNonNull(b); + + Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble( + a.spliterator(), b.spliterator()); + return (a.isParallel() || b.isParallel()) + ? StreamSupport.doubleParallelStream(split) + : StreamSupport.doubleStream(split); + } } diff --git a/jdk/src/share/classes/java/util/stream/IntStream.java b/jdk/src/share/classes/java/util/stream/IntStream.java index 3eb4409c4e5..39e0713f1cf 100644 --- a/jdk/src/share/classes/java/util/stream/IntStream.java +++ b/jdk/src/share/classes/java/util/stream/IntStream.java @@ -800,4 +800,26 @@ public interface IntStream extends BaseStream { new Streams.RangeIntSpliterator(startInclusive, endInclusive, true)); } } + + /** + * Creates a lazy concatenated {@code IntStream} whose elements are all the + * elements of a first {@code IntStream} succeeded by all the elements of the + * second {@code IntStream}. The resulting stream is ordered if both + * of the input streams are ordered, and parallel if either of the input + * streams is parallel. + * + * @param a the first stream + * @param b the second stream to concatenate on to end of the first stream + * @return the concatenation of the two streams + */ + public static IntStream concat(IntStream a, IntStream b) { + Objects.requireNonNull(a); + Objects.requireNonNull(b); + + Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt( + a.spliterator(), b.spliterator()); + return (a.isParallel() || b.isParallel()) + ? StreamSupport.intParallelStream(split) + : StreamSupport.intStream(split); + } } diff --git a/jdk/src/share/classes/java/util/stream/LongStream.java b/jdk/src/share/classes/java/util/stream/LongStream.java index 3bc0f76a494..6e3bc688923 100644 --- a/jdk/src/share/classes/java/util/stream/LongStream.java +++ b/jdk/src/share/classes/java/util/stream/LongStream.java @@ -765,10 +765,8 @@ public interface LongStream extends BaseStream { // Split the range in two and concatenate // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE) then // the lower range, [Long.MIN_VALUE, 0) will be further split in two -// long m = startInclusive + Long.divideUnsigned(endExclusive - startInclusive, 2) + 1; -// return Streams.concat(range(startInclusive, m), range(m, endExclusive)); - // This is temporary until Streams.concat is supported - throw new UnsupportedOperationException(); + long m = startInclusive + Long.divideUnsigned(endExclusive - startInclusive, 2) + 1; + return concat(range(startInclusive, m), range(m, endExclusive)); } else { return StreamSupport.longStream( new Streams.RangeLongSpliterator(startInclusive, endExclusive, false)); @@ -801,13 +799,33 @@ public interface LongStream extends BaseStream { // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then // the lower range, [Long.MIN_VALUE, 0), and upper range, // [0, Long.MAX_VALUE], will both be further split in two -// long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1; -// return Streams.concat(range(startInclusive, m), rangeClosed(m, endInclusive)); - // This is temporary until Streams.concat is supported - throw new UnsupportedOperationException(); + long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1; + return concat(range(startInclusive, m), rangeClosed(m, endInclusive)); } else { return StreamSupport.longStream( new Streams.RangeLongSpliterator(startInclusive, endInclusive, true)); } } + + /** + * Creates a lazy concatenated {@code LongStream} whose elements are all the + * elements of a first {@code LongStream} succeeded by all the elements of the + * second {@code LongStream}. The resulting stream is ordered if both + * of the input streams are ordered, and parallel if either of the input + * streams is parallel. + * + * @param a the first stream + * @param b the second stream to concatenate on to end of the first stream + * @return the concatenation of the two streams + */ + public static LongStream concat(LongStream a, LongStream b) { + Objects.requireNonNull(a); + Objects.requireNonNull(b); + + Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong( + a.spliterator(), b.spliterator()); + return (a.isParallel() || b.isParallel()) + ? StreamSupport.longParallelStream(split) + : StreamSupport.longStream(split); + } } diff --git a/jdk/src/share/classes/java/util/stream/Stream.java b/jdk/src/share/classes/java/util/stream/Stream.java index 32b3585fdbf..78264e407ec 100644 --- a/jdk/src/share/classes/java/util/stream/Stream.java +++ b/jdk/src/share/classes/java/util/stream/Stream.java @@ -883,4 +883,29 @@ public interface Stream extends BaseStream> { return StreamSupport.stream( new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s)); } + + /** + * Creates a lazy concatenated {@code Stream} whose elements are all the + * elements of a first {@code Stream} succeeded by all the elements of the + * second {@code Stream}. The resulting stream is ordered if both + * of the input streams are ordered, and parallel if either of the input + * streams is parallel. + * + * @param The type of stream elements + * @param a the first stream + * @param b the second stream to concatenate on to end of the first + * stream + * @return the concatenation of the two input streams + */ + public static Stream concat(Stream a, Stream b) { + Objects.requireNonNull(a); + Objects.requireNonNull(b); + + @SuppressWarnings("unchecked") + Spliterator split = new Streams.ConcatSpliterator.OfRef<>( + (Spliterator) a.spliterator(), (Spliterator) b.spliterator()); + return (a.isParallel() || b.isParallel()) + ? StreamSupport.parallelStream(split) + : StreamSupport.stream(split); + } } diff --git a/jdk/src/share/classes/java/util/stream/Streams.java b/jdk/src/share/classes/java/util/stream/Streams.java index 11dbbe3d7ca..1d49997fe22 100644 --- a/jdk/src/share/classes/java/util/stream/Streams.java +++ b/jdk/src/share/classes/java/util/stream/Streams.java @@ -43,7 +43,7 @@ import java.util.function.LongConsumer; * * @since 1.8 */ -class Streams { +final class Streams { private Streams() { throw new Error("no instances"); @@ -670,4 +670,147 @@ class Streams { } } } + + abstract static class ConcatSpliterator> + implements Spliterator { + protected final T_SPLITR aSpliterator; + protected final T_SPLITR bSpliterator; + // True when no split has occurred, otherwise false + boolean beforeSplit; + // Never read after splitting + final boolean unsized; + + public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) { + this.aSpliterator = aSpliterator; + this.bSpliterator = bSpliterator; + beforeSplit = true; + // The spliterator is unsized before splitting if a and b are + // sized and the sum of the estimates overflows + unsized = aSpliterator.hasCharacteristics(SIZED) + && aSpliterator.hasCharacteristics(SIZED) + && aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0; + } + + @Override + public T_SPLITR trySplit() { + T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit(); + beforeSplit = false; + return ret; + } + + @Override + public boolean tryAdvance(Consumer consumer) { + boolean hasNext; + if (beforeSplit) { + hasNext = aSpliterator.tryAdvance(consumer); + if (!hasNext) { + beforeSplit = false; + hasNext = bSpliterator.tryAdvance(consumer); + } + } + else + hasNext = bSpliterator.tryAdvance(consumer); + return hasNext; + } + + @Override + public void forEachRemaining(Consumer consumer) { + if (beforeSplit) + aSpliterator.forEachRemaining(consumer); + bSpliterator.forEachRemaining(consumer); + } + + @Override + public long estimateSize() { + if (beforeSplit) { + // If one or both estimates are Long.MAX_VALUE then the sum + // will either be Long.MAX_VALUE or overflow to a negative value + long size = aSpliterator.estimateSize() + bSpliterator.estimateSize(); + return (size >= 0) ? size : Long.MAX_VALUE; + } + else { + return bSpliterator.estimateSize(); + } + } + + @Override + public int characteristics() { + if (beforeSplit) { + // Concatenation loses DISTINCT and SORTED characteristics + return aSpliterator.characteristics() & bSpliterator.characteristics() + & ~(Spliterator.DISTINCT | Spliterator.SORTED + | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0)); + } + else { + return bSpliterator.characteristics(); + } + } + + @Override + public Comparator getComparator() { + if (beforeSplit) + throw new IllegalStateException(); + return bSpliterator.getComparator(); + } + + static class OfRef extends ConcatSpliterator> { + OfRef(Spliterator aSpliterator, Spliterator bSpliterator) { + super(aSpliterator, bSpliterator); + } + } + + private static abstract class OfPrimitive> + extends ConcatSpliterator + implements Spliterator.OfPrimitive { + private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) { + super(aSpliterator, bSpliterator); + } + + @Override + public boolean tryAdvance(T_CONS action) { + boolean hasNext; + if (beforeSplit) { + hasNext = aSpliterator.tryAdvance(action); + if (!hasNext) { + beforeSplit = false; + hasNext = bSpliterator.tryAdvance(action); + } + } + else + hasNext = bSpliterator.tryAdvance(action); + return hasNext; + } + + @Override + public void forEachRemaining(T_CONS action) { + if (beforeSplit) + aSpliterator.forEachRemaining(action); + bSpliterator.forEachRemaining(action); + } + } + + static class OfInt + extends ConcatSpliterator.OfPrimitive + implements Spliterator.OfInt { + OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) { + super(aSpliterator, bSpliterator); + } + } + + static class OfLong + extends ConcatSpliterator.OfPrimitive + implements Spliterator.OfLong { + OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) { + super(aSpliterator, bSpliterator); + } + } + + static class OfDouble + extends ConcatSpliterator.OfPrimitive + implements Spliterator.OfDouble { + OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) { + super(aSpliterator, bSpliterator); + } + } + } } diff --git a/jdk/test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java b/jdk/test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java index 225cbf147f6..cec872aa484 100644 --- a/jdk/test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java +++ b/jdk/test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java @@ -360,35 +360,26 @@ public class LambdaTestHelpers { private static Map toBoxedMultiset(Iterator it) { Map result = new HashMap<>(); - it.forEachRemaining(new OmnivorousConsumer() { - @Override - public void accept(T t) { - add(t); - } - - @Override - public void accept(int value) { - add(value); - } - - @Override - public void accept(long value) { - add(value); - } - - @Override - public void accept(double value) { - add(value); - } - - void add(Object o) { + it.forEachRemaining(toBoxingConsumer(o -> { if (result.containsKey(o)) result.put(o, result.get(o) + 1); else result.put(o, 1); - } + })); - }); + return (Map) result; + } + + @SuppressWarnings("unchecked") + public static Map toBoxedMultiset(Spliterator it) { + Map result = new HashMap<>(); + + it.forEachRemaining(toBoxingConsumer(o -> { + if (result.containsKey(o)) + result.put(o, result.get(o) + 1); + else + result.put(o, 1); + })); return (Map) result; } diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java new file mode 100644 index 00000000000..1b3c4b65bf2 --- /dev/null +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.tests.java.util.stream; + +import java.util.stream.OpTestCase; +import java.util.stream.StreamTestDataProvider; + +import org.testng.annotations.Test; + +import java.util.stream.Stream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.DoubleStream; +import java.util.stream.TestData; + +import static java.util.stream.LambdaTestHelpers.*; + +public class ConcatOpTest extends OpTestCase { + + // Sanity to make sure all type of stream source works + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + public void testOpsSequential(String name, TestData.OfRef data) { + exerciseOpsInt(data, + s -> Stream.concat(s, data.stream()), + s -> IntStream.concat(s, data.stream().mapToInt(Integer::intValue)), + s -> LongStream.concat(s, data.stream().mapToLong(Integer::longValue)), + s -> DoubleStream.concat(s, data.stream().mapToDouble(Integer::doubleValue))); + } +} diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatTest.java new file mode 100644 index 00000000000..4ce9c9645b6 --- /dev/null +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatTest.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.tests.java.util.stream; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Spliterator; +import java.util.TreeSet; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import static java.util.stream.LambdaTestHelpers.*; +import static org.testng.Assert.*; + +@Test +public class ConcatTest { + private static Object[][] cases; + + static { + List part1 = Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4); + List part2 = Arrays.asList(8, 8, 6, 6, 9, 7, 10, 9); + List p1p2 = Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4, 8, 8, 6, 6, 9, 7, 10, 9); + List p2p1 = Arrays.asList(8, 8, 6, 6, 9, 7, 10, 9, 5, 3, 4, 1, 2, 6, 2, 4); + List empty = new LinkedList<>(); // To be ordered + assertTrue(empty.isEmpty()); + LinkedHashSet distinctP1 = new LinkedHashSet<>(part1); + LinkedHashSet distinctP2 = new LinkedHashSet<>(part2); + TreeSet sortedP1 = new TreeSet<>(part1); + TreeSet sortedP2 = new TreeSet<>(part2); + + cases = new Object[][] { + { "regular", part1, part2, p1p2 }, + { "reverse regular", part2, part1, p2p1 }, + { "front distinct", distinctP1, part2, Arrays.asList(5, 3, 4, 1, 2, 6, 8, 8, 6, 6, 9, 7, 10, 9) }, + { "back distinct", part1, distinctP2, Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4, 8, 6, 9, 7, 10) }, + { "both distinct", distinctP1, distinctP2, Arrays.asList(5, 3, 4, 1, 2, 6, 8, 6, 9, 7, 10) }, + { "front sorted", sortedP1, part2, Arrays.asList(1, 2, 3, 4, 5, 6, 8, 8, 6, 6, 9, 7, 10, 9) }, + { "back sorted", part1, sortedP2, Arrays.asList(5, 3, 4, 1, 2, 6, 2, 4, 6, 7, 8, 9, 10) }, + { "both sorted", sortedP1, sortedP2, Arrays.asList(1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10) }, + { "reverse both sorted", sortedP2, sortedP1, Arrays.asList(6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6) }, + { "empty something", empty, part1, part1 }, + { "something empty", part1, empty, part1 }, + { "empty empty", empty, empty, empty } + }; + } + + @DataProvider(name = "cases") + private static Object[][] getCases() { + return cases; + } + + @Factory(dataProvider = "cases") + public static Object[] createTests(String scenario, Collection c1, Collection c2, Collection expected) { + return new Object[] { + new ConcatTest(scenario, c1, c2, expected) + }; + } + + protected final String scenario; + protected final Collection c1; + protected final Collection c2; + protected final Collection expected; + + public ConcatTest(String scenario, Collection c1, Collection c2, Collection expected) { + this.scenario = scenario; + this.c1 = c1; + this.c2 = c2; + this.expected = expected; + + // verify prerequisite + Stream s1s = c1.stream(); + Stream s2s = c2.stream(); + Stream s1p = c1.parallelStream(); + Stream s2p = c2.parallelStream(); + assertTrue(s1p.isParallel()); + assertTrue(s2p.isParallel()); + assertFalse(s1s.isParallel()); + assertFalse(s2s.isParallel()); + + assertTrue(s1s.spliterator().hasCharacteristics(Spliterator.ORDERED)); + assertTrue(s1p.spliterator().hasCharacteristics(Spliterator.ORDERED)); + assertTrue(s2s.spliterator().hasCharacteristics(Spliterator.ORDERED)); + assertTrue(s2p.spliterator().hasCharacteristics(Spliterator.ORDERED)); + } + + private void assertConcatContent(Spliterator sp, boolean ordered, Spliterator expected) { + // concat stream cannot guarantee uniqueness + assertFalse(sp.hasCharacteristics(Spliterator.DISTINCT), scenario); + // concat stream cannot guarantee sorted + assertFalse(sp.hasCharacteristics(Spliterator.SORTED), scenario); + // concat stream is ordered if both are ordered + assertEquals(sp.hasCharacteristics(Spliterator.ORDERED), ordered, scenario); + + // Verify elements + if (ordered) { + assertEquals(toBoxedList(sp), + toBoxedList(expected), + scenario); + } else { + assertEquals(toBoxedMultiset(sp), + toBoxedMultiset(expected), + scenario); + } + } + + private void assertRefConcat(Stream s1, Stream s2, boolean parallel, boolean ordered) { + Stream result = Stream.concat(s1, s2); + assertEquals(result.isParallel(), parallel); + assertConcatContent(result.spliterator(), ordered, expected.spliterator()); + } + + private void assertIntConcat(Stream s1, Stream s2, boolean parallel, boolean ordered) { + IntStream result = IntStream.concat(s1.mapToInt(Integer::intValue), + s2.mapToInt(Integer::intValue)); + assertEquals(result.isParallel(), parallel); + assertConcatContent(result.spliterator(), ordered, + expected.stream().mapToInt(Integer::intValue).spliterator()); + } + + private void assertLongConcat(Stream s1, Stream s2, boolean parallel, boolean ordered) { + LongStream result = LongStream.concat(s1.mapToLong(Integer::longValue), + s2.mapToLong(Integer::longValue)); + assertEquals(result.isParallel(), parallel); + assertConcatContent(result.spliterator(), ordered, + expected.stream().mapToLong(Integer::longValue).spliterator()); + } + + private void assertDoubleConcat(Stream s1, Stream s2, boolean parallel, boolean ordered) { + DoubleStream result = DoubleStream.concat(s1.mapToDouble(Integer::doubleValue), + s2.mapToDouble(Integer::doubleValue)); + assertEquals(result.isParallel(), parallel); + assertConcatContent(result.spliterator(), ordered, + expected.stream().mapToDouble(Integer::doubleValue).spliterator()); + } + + public void testRefConcat() { + // sequential + sequential -> sequential + assertRefConcat(c1.stream(), c2.stream(), false, true); + // parallel + parallel -> parallel + assertRefConcat(c1.parallelStream(), c2.parallelStream(), true, true); + // sequential + parallel -> parallel + assertRefConcat(c1.stream(), c2.parallelStream(), true, true); + // parallel + sequential -> parallel + assertRefConcat(c1.parallelStream(), c2.stream(), true, true); + + // not ordered + assertRefConcat(c1.stream().unordered(), c2.stream(), false, false); + assertRefConcat(c1.stream(), c2.stream().unordered(), false, false); + assertRefConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false); + } + + public void testIntConcat() { + // sequential + sequential -> sequential + assertIntConcat(c1.stream(), c2.stream(), false, true); + // parallel + parallel -> parallel + assertIntConcat(c1.parallelStream(), c2.parallelStream(), true, true); + // sequential + parallel -> parallel + assertIntConcat(c1.stream(), c2.parallelStream(), true, true); + // parallel + sequential -> parallel + assertIntConcat(c1.parallelStream(), c2.stream(), true, true); + + // not ordered + assertIntConcat(c1.stream().unordered(), c2.stream(), false, false); + assertIntConcat(c1.stream(), c2.stream().unordered(), false, false); + assertIntConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false); + } + + public void testLongConcat() { + // sequential + sequential -> sequential + assertLongConcat(c1.stream(), c2.stream(), false, true); + // parallel + parallel -> parallel + assertLongConcat(c1.parallelStream(), c2.parallelStream(), true, true); + // sequential + parallel -> parallel + assertLongConcat(c1.stream(), c2.parallelStream(), true, true); + // parallel + sequential -> parallel + assertLongConcat(c1.parallelStream(), c2.stream(), true, true); + + // not ordered + assertLongConcat(c1.stream().unordered(), c2.stream(), false, false); + assertLongConcat(c1.stream(), c2.stream().unordered(), false, false); + assertLongConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false); + } + + public void testDoubleConcat() { + // sequential + sequential -> sequential + assertDoubleConcat(c1.stream(), c2.stream(), false, true); + // parallel + parallel -> parallel + assertDoubleConcat(c1.parallelStream(), c2.parallelStream(), true, true); + // sequential + parallel -> parallel + assertDoubleConcat(c1.stream(), c2.parallelStream(), true, true); + // parallel + sequential -> parallel + assertDoubleConcat(c1.parallelStream(), c2.stream(), true, true); + + // not ordered + assertDoubleConcat(c1.stream().unordered(), c2.stream(), false, false); + assertDoubleConcat(c1.stream(), c2.stream().unordered(), false, false); + assertDoubleConcat(c1.parallelStream().unordered(), c2.stream().unordered(), true, false); + } +} diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/RangeTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/RangeTest.java index 1e6b343fc60..20ae203bb63 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/RangeTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/RangeTest.java @@ -226,116 +226,114 @@ public class RangeTest extends OpTestCase { assertEquals(first, LongStream.iterate(0, i -> i + 1).parallel().filter(i -> i > 10000).findFirst().getAsLong()); } - // Enable when Stream.concat is present and range implementations are - // updated to use that -// private static void assertSizedAndSubSized(Spliterator s) { -// assertTrue(s.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)); -// } -// -// private static void assertNotSizedAndSubSized(Spliterator s) { -// assertFalse(s.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)); -// } -// -// public void testLongLongRange() { -// // Test [Long.MIN_VALUE, Long.MAX_VALUE) -// // This will concatenate streams of three ranges -// // [Long.MIN_VALUE, x) [x, 0) [0, Long.MAX_VALUE) -// // where x = Long.divideUnsigned(0 - Long.MIN_VALUE, 2) + 1 -// { -// Spliterator.OfLong s = LongStream.range(Long.MIN_VALUE, Long.MAX_VALUE).spliterator(); -// -// assertEquals(s.estimateSize(), Long.MAX_VALUE); -// assertNotSizedAndSubSized(s); -// -// Spliterator.OfLong s1 = s.trySplit(); -// assertNotSizedAndSubSized(s1); -// assertSizedAndSubSized(s); -// -// Spliterator.OfLong s2 = s1.trySplit(); -// assertSizedAndSubSized(s1); -// assertSizedAndSubSized(s2); -// -// assertTrue(s.estimateSize() == Long.MAX_VALUE); -// assertTrue(s1.estimateSize() < Long.MAX_VALUE); -// assertTrue(s2.estimateSize() < Long.MAX_VALUE); -// -// assertEquals(s.estimateSize() + s1.estimateSize() + s2.estimateSize(), -// Long.MAX_VALUE - Long.MIN_VALUE); -// } -// -// long[][] ranges = { {Long.MIN_VALUE, 0}, {-1, Long.MAX_VALUE} }; -// for (int i = 0; i < ranges.length; i++) { -// long start = ranges[i][0]; -// long end = ranges[i][1]; -// -// Spliterator.OfLong s = LongStream.range(start, end).spliterator(); -// -// assertEquals(s.estimateSize(), Long.MAX_VALUE); -// assertNotSizedAndSubSized(s); -// -// Spliterator.OfLong s1 = s.trySplit(); -// assertSizedAndSubSized(s1); -// assertSizedAndSubSized(s); -// -// assertTrue(s.estimateSize() < Long.MAX_VALUE); -// assertTrue(s1.estimateSize() < Long.MAX_VALUE); -// -// assertEquals(s.estimateSize() + s1.estimateSize(), end - start); -// } -// } -// -// public void testLongLongRangeClosed() { -// // Test [Long.MIN_VALUE, Long.MAX_VALUE] -// // This will concatenate streams of four ranges -// // [Long.MIN_VALUE, x) [x, 0) [0, y) [y, Long.MAX_VALUE] -// // where x = Long.divideUnsigned(0 - Long.MIN_VALUE, 2) + 1 -// // y = Long.divideUnsigned(Long.MAX_VALUE, 2) + 1 -// -// { -// Spliterator.OfLong s = LongStream.rangeClosed(Long.MIN_VALUE, Long.MAX_VALUE).spliterator(); -// -// assertEquals(s.estimateSize(), Long.MAX_VALUE); -// assertNotSizedAndSubSized(s); -// -// Spliterator.OfLong s1 = s.trySplit(); -// assertNotSizedAndSubSized(s1); -// assertNotSizedAndSubSized(s); -// -// Spliterator.OfLong s2 = s1.trySplit(); -// assertSizedAndSubSized(s1); -// assertSizedAndSubSized(s2); -// -// Spliterator.OfLong s3 = s.trySplit(); -// assertSizedAndSubSized(s3); -// assertSizedAndSubSized(s); -// -// assertTrue(s.estimateSize() < Long.MAX_VALUE); -// assertTrue(s3.estimateSize() < Long.MAX_VALUE); -// assertTrue(s1.estimateSize() < Long.MAX_VALUE); -// assertTrue(s2.estimateSize() < Long.MAX_VALUE); -// -// assertEquals(s.estimateSize() + s3.estimateSize() + s1.estimateSize() + s2.estimateSize(), -// Long.MAX_VALUE - Long.MIN_VALUE + 1); -// } -// -// long[][] ranges = { {Long.MIN_VALUE, 0}, {-1, Long.MAX_VALUE} }; -// for (int i = 0; i < ranges.length; i++) { -// long start = ranges[i][0]; -// long end = ranges[i][1]; -// -// Spliterator.OfLong s = LongStream.rangeClosed(start, end).spliterator(); -// -// assertEquals(s.estimateSize(), Long.MAX_VALUE); -// assertNotSizedAndSubSized(s); -// -// Spliterator.OfLong s1 = s.trySplit(); -// assertSizedAndSubSized(s1); -// assertSizedAndSubSized(s); -// -// assertTrue(s.estimateSize() < Long.MAX_VALUE); -// assertTrue(s1.estimateSize() < Long.MAX_VALUE); -// -// assertEquals(s.estimateSize() + s1.estimateSize(), end - start + 1); -// } -// } + private static void assertSizedAndSubSized(Spliterator s) { + assertTrue(s.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)); + } + + private static void assertNotSizedAndSubSized(Spliterator s) { + assertFalse(s.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)); + } + + public void testLongLongRange() { + // Test [Long.MIN_VALUE, Long.MAX_VALUE) + // This will concatenate streams of three ranges + // [Long.MIN_VALUE, x) [x, 0) [0, Long.MAX_VALUE) + // where x = Long.divideUnsigned(0 - Long.MIN_VALUE, 2) + 1 + { + Spliterator.OfLong s = LongStream.range(Long.MIN_VALUE, Long.MAX_VALUE).spliterator(); + + assertEquals(s.estimateSize(), Long.MAX_VALUE); + assertNotSizedAndSubSized(s); + + Spliterator.OfLong s1 = s.trySplit(); + assertNotSizedAndSubSized(s1); + assertSizedAndSubSized(s); + + Spliterator.OfLong s2 = s1.trySplit(); + assertSizedAndSubSized(s1); + assertSizedAndSubSized(s2); + + assertTrue(s.estimateSize() == Long.MAX_VALUE); + assertTrue(s1.estimateSize() < Long.MAX_VALUE); + assertTrue(s2.estimateSize() < Long.MAX_VALUE); + + assertEquals(s.estimateSize() + s1.estimateSize() + s2.estimateSize(), + Long.MAX_VALUE - Long.MIN_VALUE); + } + + long[][] ranges = { {Long.MIN_VALUE, 0}, {-1, Long.MAX_VALUE} }; + for (int i = 0; i < ranges.length; i++) { + long start = ranges[i][0]; + long end = ranges[i][1]; + + Spliterator.OfLong s = LongStream.range(start, end).spliterator(); + + assertEquals(s.estimateSize(), Long.MAX_VALUE); + assertNotSizedAndSubSized(s); + + Spliterator.OfLong s1 = s.trySplit(); + assertSizedAndSubSized(s1); + assertSizedAndSubSized(s); + + assertTrue(s.estimateSize() < Long.MAX_VALUE); + assertTrue(s1.estimateSize() < Long.MAX_VALUE); + + assertEquals(s.estimateSize() + s1.estimateSize(), end - start); + } + } + + public void testLongLongRangeClosed() { + // Test [Long.MIN_VALUE, Long.MAX_VALUE] + // This will concatenate streams of four ranges + // [Long.MIN_VALUE, x) [x, 0) [0, y) [y, Long.MAX_VALUE] + // where x = Long.divideUnsigned(0 - Long.MIN_VALUE, 2) + 1 + // y = Long.divideUnsigned(Long.MAX_VALUE, 2) + 1 + + { + Spliterator.OfLong s = LongStream.rangeClosed(Long.MIN_VALUE, Long.MAX_VALUE).spliterator(); + + assertEquals(s.estimateSize(), Long.MAX_VALUE); + assertNotSizedAndSubSized(s); + + Spliterator.OfLong s1 = s.trySplit(); + assertNotSizedAndSubSized(s1); + assertNotSizedAndSubSized(s); + + Spliterator.OfLong s2 = s1.trySplit(); + assertSizedAndSubSized(s1); + assertSizedAndSubSized(s2); + + Spliterator.OfLong s3 = s.trySplit(); + assertSizedAndSubSized(s3); + assertSizedAndSubSized(s); + + assertTrue(s.estimateSize() < Long.MAX_VALUE); + assertTrue(s3.estimateSize() < Long.MAX_VALUE); + assertTrue(s1.estimateSize() < Long.MAX_VALUE); + assertTrue(s2.estimateSize() < Long.MAX_VALUE); + + assertEquals(s.estimateSize() + s3.estimateSize() + s1.estimateSize() + s2.estimateSize(), + Long.MAX_VALUE - Long.MIN_VALUE + 1); + } + + long[][] ranges = { {Long.MIN_VALUE, 0}, {-1, Long.MAX_VALUE} }; + for (int i = 0; i < ranges.length; i++) { + long start = ranges[i][0]; + long end = ranges[i][1]; + + Spliterator.OfLong s = LongStream.rangeClosed(start, end).spliterator(); + + assertEquals(s.estimateSize(), Long.MAX_VALUE); + assertNotSizedAndSubSized(s); + + Spliterator.OfLong s1 = s.trySplit(); + assertSizedAndSubSized(s1); + assertSizedAndSubSized(s); + + assertTrue(s.estimateSize() < Long.MAX_VALUE); + assertTrue(s1.estimateSize() < Long.MAX_VALUE); + + assertEquals(s.estimateSize() + s1.estimateSize(), end - start + 1); + } + } }