--- old/src/java.base/share/classes/java/util/stream/DoubleStream.java 2016-02-21 17:58:20.866799800 +0600 +++ new/src/java.base/share/classes/java/util/stream/DoubleStream.java 2016-02-21 17:58:20.332232000 +0600 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -949,24 +949,100 @@ */ public static DoubleStream iterate(final double seed, final DoubleUnaryOperator f) { Objects.requireNonNull(f); - final PrimitiveIterator.OfDouble iterator = new PrimitiveIterator.OfDouble() { - double t = seed; + Spliterator.OfDouble spliterator = new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + double prev; + boolean started; @Override - public boolean hasNext() { + public boolean tryAdvance(DoubleConsumer action) { + Objects.requireNonNull(action); + double t; + if (started) + t = f.applyAsDouble(prev); + else { + t = seed; + started = true; + } + action.accept(prev = t); + return true; + } + }; + return StreamSupport.doubleStream(spliterator, false); + } + + /** + * Returns a sequential ordered {@code DoubleStream} produced by iterative + * application of a function to an initial element, conditioned on + * satisfying the supplied predicate. The stream terminates as soon as + * the predicate function returns false. + * + *

+ * {@code DoubleStream.iterate} should produce the same sequence of + * elements as produced by the corresponding for-loop: + *

{@code
+     *     for (double index=seed; predicate.test(index); index = f.apply(index)) {
+     *         ... 
+     *     }
+     * }
+ * + *

+ * The resulting sequence may be empty if the predicate does not hold on + * the seed value. Otherwise the first element will be the supplied seed + * value, the next element (if present) will be the result of applying the + * function f to the seed value, and so on iteratively until the predicate + * indicates that the stream should terminate. + * + * @param seed the initial element + * @param predicate a predicate to apply to elements to determine when the + * stream must terminate. + * @param f a function to be applied to the previous element to produce + * a new element + * @return a new sequential {@code DoubleStream} + * @since 9 + */ + public static DoubleStream iterate(double seed, DoublePredicate predicate, DoubleUnaryOperator f) { + Objects.requireNonNull(f); + Objects.requireNonNull(predicate); + Spliterator.OfDouble spliterator = new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + double prev; + boolean started, finished; + + @Override + public boolean tryAdvance(DoubleConsumer action) { + Objects.requireNonNull(action); + if (finished) + return false; + double t; + if (started) + t = f.applyAsDouble(prev); + else { + t = seed; + started = true; + } + if (!predicate.test(t)) { + finished = true; + return false; + } + action.accept(prev = t); return true; } @Override - public double nextDouble() { - double v = t; - t = f.applyAsDouble(t); - return v; + public void forEachRemaining(DoubleConsumer action) { + Objects.requireNonNull(action); + if (finished) + return; + double t = started ? f.applyAsDouble(prev) : seed; + finished = true; + while (predicate.test(t)) { + action.accept(t); + t = f.applyAsDouble(t); + } } }; - return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize( - iterator, - Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false); + return StreamSupport.doubleStream(spliterator, false); } /** --- old/src/java.base/share/classes/java/util/stream/IntStream.java 2016-02-21 17:58:22.533511500 +0600 +++ new/src/java.base/share/classes/java/util/stream/IntStream.java 2016-02-21 17:58:22.268477800 +0600 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -885,28 +885,104 @@ * @param seed the initial element * @param f a function to be applied to the previous element to produce * a new element - * @return A new sequential {@code IntStream} + * @return a new sequential {@code IntStream} */ public static IntStream iterate(final int seed, final IntUnaryOperator f) { Objects.requireNonNull(f); - final PrimitiveIterator.OfInt iterator = new PrimitiveIterator.OfInt() { - int t = seed; + Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + int prev; + boolean started; @Override - public boolean hasNext() { + public boolean tryAdvance(IntConsumer action) { + Objects.requireNonNull(action); + int t; + if (started) + t = f.applyAsInt(prev); + else { + t = seed; + started = true; + } + action.accept(prev = t); + return true; + } + }; + return StreamSupport.intStream(spliterator, false); + } + + /** + * Returns a sequential ordered {@code IntStream} produced by iterative + * application of a function to an initial element, conditioned on + * satisfying the supplied predicate. The stream terminates as soon as + * the predicate function returns false. + * + *

+ * {@code IntStream.iterate} should produce the same sequence of elements + * as produced by the corresponding for-loop: + *

{@code
+     *     for (int index=seed; predicate.test(index); index = f.apply(index)) { 
+     *         ... 
+     *     }
+     * }
+ * + *

+ * The resulting sequence may be empty if the predicate does not hold on + * the seed value. Otherwise the first element will be the supplied seed + * value, the next element (if present) will be the result of applying the + * function f to the seed value, and so on iteratively until the predicate + * indicates that the stream should terminate. + * + * @param seed the initial element + * @param predicate a predicate to apply to elements to determine when the + * stream must terminate. + * @param f a function to be applied to the previous element to produce + * a new element + * @return a new sequential {@code IntStream} + * @since 9 + */ + public static IntStream iterate(int seed, IntPredicate predicate, IntUnaryOperator f) { + Objects.requireNonNull(f); + Objects.requireNonNull(predicate); + Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + int prev; + boolean started, finished; + + @Override + public boolean tryAdvance(IntConsumer action) { + Objects.requireNonNull(action); + if (finished) + return false; + int t; + if (started) + t = f.applyAsInt(prev); + else { + t = seed; + started = true; + } + if (!predicate.test(t)) { + finished = true; + return false; + } + action.accept(prev = t); return true; } @Override - public int nextInt() { - int v = t; - t = f.applyAsInt(t); - return v; + public void forEachRemaining(IntConsumer action) { + Objects.requireNonNull(action); + if (finished) + return; + int t = started ? f.applyAsInt(prev) : seed; + finished = true; + while (predicate.test(t)) { + action.accept(t); + t = f.applyAsInt(t); + } } }; - return StreamSupport.intStream(Spliterators.spliteratorUnknownSize( - iterator, - Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false); + return StreamSupport.intStream(spliterator, false); } /** --- old/src/java.base/share/classes/java/util/stream/LongStream.java 2016-02-21 17:58:23.994197000 +0600 +++ new/src/java.base/share/classes/java/util/stream/LongStream.java 2016-02-21 17:58:23.731163600 +0600 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -879,24 +879,100 @@ */ public static LongStream iterate(final long seed, final LongUnaryOperator f) { Objects.requireNonNull(f); - final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() { - long t = seed; + Spliterator.OfLong spliterator = new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + long prev; + boolean started; @Override - public boolean hasNext() { + public boolean tryAdvance(LongConsumer action) { + Objects.requireNonNull(action); + long t; + if (started) + t = f.applyAsLong(prev); + else { + t = seed; + started = true; + } + action.accept(prev = t); + return true; + } + }; + return StreamSupport.longStream(spliterator, false); + } + + /** + * Returns a sequential ordered {@code LongStream} produced by iterative + * application of a function to an initial element, conditioned on + * satisfying the supplied predicate. The stream terminates as soon as + * the predicate function returns false. + * + *

+ * {@code LongStream.iterate} should produce the same sequence of elements + * as produced by the corresponding for-loop: + *

{@code
+     *     for (long index=seed; predicate.test(index); index = f.apply(index)) { 
+     *         ... 
+     *     }
+     * }
+ * + *

+ * The resulting sequence may be empty if the predicate does not hold on + * the seed value. Otherwise the first element will be the supplied seed + * value, the next element (if present) will be the result of applying the + * function f to the seed value, and so on iteratively until the predicate + * indicates that the stream should terminate. + * + * @param seed the initial element + * @param predicate a predicate to apply to elements to determine when the + * stream must terminate. + * @param f a function to be applied to the previous element to produce + * a new element + * @return a new sequential {@code LongStream} + * @since 9 + */ + public static LongStream iterate(long seed, LongPredicate predicate, LongUnaryOperator f) { + Objects.requireNonNull(f); + Objects.requireNonNull(predicate); + Spliterator.OfLong spliterator = new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + long prev; + boolean started, finished; + + @Override + public boolean tryAdvance(LongConsumer action) { + Objects.requireNonNull(action); + if (finished) + return false; + long t; + if (started) + t = f.applyAsLong(prev); + else { + t = seed; + started = true; + } + if (!predicate.test(t)) { + finished = true; + return false; + } + action.accept(prev = t); return true; } @Override - public long nextLong() { - long v = t; - t = f.applyAsLong(t); - return v; + public void forEachRemaining(LongConsumer action) { + Objects.requireNonNull(action); + if (finished) + return; + long t = started ? f.applyAsLong(prev) : seed; + finished = true; + while (predicate.test(t)) { + action.accept(t); + t = f.applyAsLong(t); + } } }; - return StreamSupport.longStream(Spliterators.spliteratorUnknownSize( - iterator, - Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false); + return StreamSupport.longStream(spliterator, false); } /** --- old/src/java.base/share/classes/java/util/stream/Stream.java 2016-02-21 17:58:25.381873200 +0600 +++ new/src/java.base/share/classes/java/util/stream/Stream.java 2016-02-21 17:58:25.113839100 +0600 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -1185,23 +1185,103 @@ */ public static Stream iterate(final T seed, final UnaryOperator f) { Objects.requireNonNull(f); - final Iterator iterator = new Iterator() { - @SuppressWarnings("unchecked") - T t = (T) Streams.NONE; + Spliterator spliterator = new Spliterators.AbstractSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + T prev; + boolean started; @Override - public boolean hasNext() { + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + T t; + if (started) + t = f.apply(prev); + else { + t = seed; + started = true; + } + action.accept(prev = t); + return true; + } + }; + return StreamSupport.stream(spliterator, false); + } + + /** + * Returns a sequential ordered {@code Stream} produced by iterative + * application of a function to an initial element, conditioned on + * satisfying the supplied predicate. The stream terminates as soon as + * the predicate function returns false. + * + *

+ * {@code Stream.iterate} should produce the same sequence of elements as + * produced by the corresponding for-loop: + *

{@code
+     *     for (T index=seed; predicate.test(index); index = f.apply(index)) { 
+     *         ... 
+     *     }
+     * }
+ * + *

+ * The resulting sequence may be empty if the predicate does not hold on + * the seed value. Otherwise the first element will be the supplied seed + * value, the next element (if present) will be the result of applying the + * function f to the seed value, and so on iteratively until the predicate + * indicates that the stream should terminate. + * + * @param the type of stream elements + * @param seed the initial element + * @param predicate a predicate to apply to elements to determine when the + * stream must terminate. + * @param f a function to be applied to the previous element to produce + * a new element + * @return a new sequential {@code Stream} + * @since 9 + */ + public static Stream iterate(T seed, Predicate predicate, UnaryOperator f) { + Objects.requireNonNull(f); + Objects.requireNonNull(predicate); + Spliterator spliterator = new Spliterators.AbstractSpliterator(Long.MAX_VALUE, + Spliterator.ORDERED | Spliterator.IMMUTABLE) { + T prev; + boolean started, finished; + + @Override + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + if (finished) + return false; + T t; + if (started) + t = f.apply(prev); + else { + t = seed; + started = true; + } + if (!predicate.test(t)) { + prev = null; + finished = true; + return false; + } + action.accept(prev = t); return true; } @Override - public T next() { - return t = (t == Streams.NONE) ? seed : f.apply(t); + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + if (finished) + return; + T t = started ? f.apply(prev) : seed; + finished = true; + prev = null; + while (predicate.test(t)) { + action.accept(t); + t = f.apply(t); + } } }; - return StreamSupport.stream(Spliterators.spliteratorUnknownSize( - iterator, - Spliterator.ORDERED | Spliterator.IMMUTABLE), false); + return StreamSupport.stream(spliterator, false); } /** --- old/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java 2016-02-21 17:58:27.195603500 +0600 +++ new/test/java/util/stream/bootlib/java.base/java/util/stream/DoubleStreamTestDataProvider.java 2016-02-21 17:58:26.704041100 +0600 @@ -126,6 +126,9 @@ () -> Spliterators.spliterator(isl.iterator(), doubles.length, 0))); spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name, () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0))); + spliterators.add(splitDescr("DoubleStream.iterate(0,x->xx+1):" + name, + () -> DoubleStream.iterate(0.0, x -> x < doubles.length, x -> x + 1.0) + .spliterator())); // Need more! } spliteratorTestData = spliterators.toArray(new Object[0][]); --- old/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java 2016-02-21 17:58:28.574278600 +0600 +++ new/test/java/util/stream/bootlib/java.base/java/util/stream/IntStreamTestDataProvider.java 2016-02-21 17:58:28.290242500 +0600 @@ -136,6 +136,8 @@ () -> IntStream.range(0, ints.length).spliterator())); spliterators.add(splitDescr("IntStream.intRangeClosed(0,l):" + name, () -> IntStream.rangeClosed(0, ints.length).spliterator())); + spliterators.add(splitDescr("IntStream.iterate(0,x->xx+1): " + name, + () -> IntStream.iterate(0, x -> x < ints.length, x -> x + 1).spliterator())); // Need more! } spliteratorTestData = spliterators.toArray(new Object[0][]); --- old/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java 2016-02-21 17:58:30.032463700 +0600 +++ new/test/java/util/stream/bootlib/java.base/java/util/stream/LongStreamTestDataProvider.java 2016-02-21 17:58:29.643914400 +0600 @@ -136,6 +136,9 @@ () -> LongStream.range(0, longs.length).spliterator())); spliterators.add(splitDescr("LongStream.longRangeClosed(0,l):" + name, () -> LongStream.rangeClosed(0, longs.length).spliterator())); + spliterators.add(splitDescr("LongStream.iterate(0,x->xx+1):" + name, + () -> LongStream.iterate(0L, x -> x < longs.length, x -> x + 1L) + .spliterator())); // Need more! } spliteratorTestData = spliterators.toArray(new Object[0][]); --- old/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java 2016-02-21 17:58:31.515152000 +0600 +++ new/test/java/util/stream/bootlib/java.base/java/util/stream/StreamTestDataProvider.java 2016-02-21 17:58:31.219114400 +0600 @@ -171,6 +171,8 @@ () -> Spliterators.spliterator(Arrays.asList(ints).iterator(), ints.length, 0))); spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator()):" + name, () -> Spliterators.spliteratorUnknownSize(Arrays.asList(ints).iterator(), 0))); + spliterators.add(splitDescr("Stream.iterate(0,x->xx+1): " + name, + () -> Stream.iterate(0, x -> x < ints.length, x -> x + 1).spliterator())); // @@@ Add map and collection spliterators when spliterator() is exposed on Collection or Iterable } spliteratorTestData = spliterators.toArray(new Object[0][]); --- /dev/null 2016-02-21 17:08:59.203570000 +0600 +++ new/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IterateTest.java 2016-02-21 17:58:32.584287800 +0600 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, 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. + */ + +/** + * @test + * @bug 8072727 + */ + +package org.openjdk.tests.java.util.stream; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.OpTestCase; +import java.util.stream.Stream; +import java.util.stream.TestData; +import java.util.stream.TestData.Factory; + +import static java.util.stream.ThowableHelper.checkNPE; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +@Test +public class IterateTest extends OpTestCase { + + @DataProvider(name = "IterateStreamsData") + public static Object[][] makeIterateStreamsTestData() { + Object[][] data = { + {Arrays.asList(), + Factory.ofSupplier("ref.empty", () -> Stream.iterate(1, x -> x < 0, x -> x * 2))}, + {Arrays.asList(1), + Factory.ofSupplier("ref.one", () -> Stream.iterate(1, x -> x < 2, x -> x * 2))}, + {Arrays.asList(1, 2, 4, 8, 16, 32, 64, 128, 256, 512), + Factory.ofSupplier("ref.ten", () -> Stream.iterate(1, x -> x < 1000, x -> x * 2))}, + {Arrays.asList(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + Factory.ofSupplier("ref.nullCheck", () -> Stream.iterate(10, Objects::nonNull, x -> x > 0 ? x - 1 : null))}, + {Arrays.asList(), + Factory.ofIntSupplier("int.empty", () -> IntStream.iterate(1, x -> x < 0, x -> x + 1))}, + {Arrays.asList(1), + Factory.ofIntSupplier("int.one", () -> IntStream.iterate(1, x -> x < 2, x -> x + 1))}, + {Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), + Factory.ofIntSupplier("int.ten", () -> IntStream.iterate(1, x -> x <= 10, x -> x + 1))}, + {Arrays.asList(5, 4, 3, 2, 1), + Factory.ofIntSupplier("int.divZero", () -> IntStream.iterate(5, x -> x != 0, x -> x - 1/x/2 - 1))}, + {Arrays.asList(), + Factory.ofLongSupplier("long.empty", () -> LongStream.iterate(1L, x -> x < 0, x -> x + 1))}, + {Arrays.asList(1L), + Factory.ofLongSupplier("long.one", () -> LongStream.iterate(1L, x -> x < 2, x -> x + 1))}, + {Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L), + Factory.ofLongSupplier("long.ten", () -> LongStream.iterate(1L, x -> x <= 10, x -> x + 1))}, + {Arrays.asList(), + Factory.ofDoubleSupplier("double.empty", () -> DoubleStream.iterate(1.0, x -> x < 0, x -> x + 1))}, + {Arrays.asList(1.0), + Factory.ofDoubleSupplier("double.one", () -> DoubleStream.iterate(1.0, x -> x < 2, x -> x + 1))}, + {Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0), + Factory.ofDoubleSupplier("double.ten", () -> DoubleStream.iterate(1.0, x -> x <= 10, x -> x + 1))} + }; + return data; + } + + @Test(dataProvider = "IterateStreamsData") + public void testIterate(List expected, TestData data) { + withData(data).stream(s -> s).expectedResult(expected).exercise(); + } + + @Test + public void testNPE() { + checkNPE(() -> Stream.iterate("", null, x -> x + "a")); + checkNPE(() -> Stream.iterate("", String::isEmpty, null)); + checkNPE(() -> IntStream.iterate(0, null, x -> x + 1)); + checkNPE(() -> IntStream.iterate(0, x -> x < 10, null)); + checkNPE(() -> LongStream.iterate(0, null, x -> x + 1)); + checkNPE(() -> LongStream.iterate(0, x -> x < 10, null)); + checkNPE(() -> DoubleStream.iterate(0, null, x -> x + 1)); + checkNPE(() -> DoubleStream.iterate(0, x -> x < 10, null)); + } +}