--- old/src/java.base/share/classes/java/util/stream/DoubleStream.java 2017-08-13 19:17:27.637546100 +0600 +++ new/src/java.base/share/classes/java/util/stream/DoubleStream.java 2017-08-13 19:17:27.433520200 +0600 @@ -547,6 +547,147 @@ OptionalDouble reduce(DoubleBinaryOperator op); /** + * Folds the elements of this stream using the provided {@code seed} value and + * accumulation function, going left to right. This is equivalent to: + * + *
{@code
+     *     double result = seed;
+     *     for (double element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function + * is associative, and {@code seed} value has identity properties, + * consider using {@link #reduce(double, DoubleBinaryOperator)} method. + * + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #reduce(double, DoubleBinaryOperator) + * @see #foldLeft(DoubleBinaryOperator) + * @since 10 + */ + default double foldLeft(double seed, DoubleBinaryOperator accumulator) { + ReduceOps.DoubleFoldLeftOp op = new ReduceOps.DoubleFoldLeftOp(accumulator); + op.accept(seed); + forEachOrdered(op); + return op.getAsDouble(); + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going left to right. This is equivalent to: + * + *

{@code
+     *     boolean foundAny = false;
+     *     double result = 0;
+     *     for (double element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? OptionalDouble.of(result) : OptionalDouble.empty();
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function is + * associative, consider using {@link #reduce(DoubleBinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(double, DoubleBinaryOperator) + * @see #reduce(DoubleBinaryOperator) + * @since 10 + */ + default OptionalDouble foldLeft(DoubleBinaryOperator accumulator) { + ReduceOps.DoubleFoldLeftOp op = new ReduceOps.DoubleFoldLeftOp(accumulator); + forEachOrdered(op); + return op.get(); + } + + /** + * Folds the elements of this stream using the provided {@code seed} value and + * accumulation function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, and {@code seed} value has identity properties, + * consider using {@link #reduce(double, DoubleBinaryOperator)} method. + * + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(double, DoubleBinaryOperator) + * @see #reduce(double, DoubleBinaryOperator) + * @since 10 + */ + default double foldRight(double seed, DoubleBinaryOperator accumulator) { + double[] array = toArray(); + double result = seed; + for(int idx = array.length - 1; idx >= 0; idx--) { + result = accumulator.applyAsDouble(array[idx], result); + } + return result; + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, consider using {@link #reduce(DoubleBinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(double, DoubleBinaryOperator) + * @see #reduce(double, DoubleBinaryOperator) + * @since 10 + */ + default OptionalDouble foldRight(DoubleBinaryOperator accumulator) { + double[] array = toArray(); + int idx = array.length; + if (idx == 0) return OptionalDouble.empty(); + double result = array[--idx]; + while(idx > 0) { + double t = array[--idx]; + result = accumulator.applyAsDouble(t, result); + } + return OptionalDouble.of(result); + } + + /** * Performs a mutable * reduction operation on the elements of this stream. A mutable * reduction is one in which the reduced value is a mutable result container, --- old/src/java.base/share/classes/java/util/stream/IntStream.java 2017-08-13 19:17:28.670677300 +0600 +++ new/src/java.base/share/classes/java/util/stream/IntStream.java 2017-08-13 19:17:28.465651200 +0600 @@ -543,6 +543,147 @@ OptionalInt reduce(IntBinaryOperator op); /** + * Folds the elements of this stream using the provided {@code seed} value and + * accumulation function, going left to right. This is equivalent to: + * + *

{@code
+     *     int result = seed;
+     *     for (int element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function + * is associative, and {@code seed} value has identity properties, + * consider using {@link #reduce(int, IntBinaryOperator)} method. + * + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #reduce(int, IntBinaryOperator) + * @see #foldLeft(IntBinaryOperator) + * @since 10 + */ + default int foldLeft(int seed, IntBinaryOperator accumulator) { + ReduceOps.IntFoldLeftOp op = new ReduceOps.IntFoldLeftOp(accumulator); + op.accept(seed); + forEachOrdered(op); + return op.getAsInt(); + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going left to right. This is equivalent to: + * + *

{@code
+     *     boolean foundAny = false;
+     *     int result = 0;
+     *     for (int element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? OptionalInt.of(result) : OptionalInt.empty();
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function is + * associative, consider using {@link #reduce(IntBinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(int, IntBinaryOperator) + * @see #reduce(IntBinaryOperator) + * @since 10 + */ + default OptionalInt foldLeft(IntBinaryOperator accumulator) { + ReduceOps.IntFoldLeftOp op = new ReduceOps.IntFoldLeftOp(accumulator); + forEachOrdered(op); + return op.get(); + } + + /** + * Folds the elements of this stream using the provided {@code seed} value and + * accumulation function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, and {@code seed} value has identity properties, + * consider using {@link #reduce(int, IntBinaryOperator)} method. + * + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(int, IntBinaryOperator) + * @see #reduce(int, IntBinaryOperator) + * @since 10 + */ + default int foldRight(int seed, IntBinaryOperator accumulator) { + int[] array = toArray(); + int result = seed; + for(int idx = array.length - 1; idx >= 0; idx--) { + result = accumulator.applyAsInt(array[idx], result); + } + return result; + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, consider using {@link #reduce(IntBinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(int, IntBinaryOperator) + * @see #reduce(int, IntBinaryOperator) + * @since 10 + */ + default OptionalInt foldRight(IntBinaryOperator accumulator) { + int[] array = toArray(); + int idx = array.length; + if (idx == 0) return OptionalInt.empty(); + int result = array[--idx]; + while(idx > 0) { + int t = array[--idx]; + result = accumulator.applyAsInt(t, result); + } + return OptionalInt.of(result); + } + + /** * Performs a mutable * reduction operation on the elements of this stream. A mutable * reduction is one in which the reduced value is a mutable result container, --- old/src/java.base/share/classes/java/util/stream/LongStream.java 2017-08-13 19:17:29.773817300 +0600 +++ new/src/java.base/share/classes/java/util/stream/LongStream.java 2017-08-13 19:17:29.505783300 +0600 @@ -545,6 +545,149 @@ OptionalLong reduce(LongBinaryOperator op); /** + * Folds the elements of this stream using the provided {@code seed} value and + * accumulation function, going left to right. This is equivalent to: + * + *

{@code
+     *     long result = seed;
+     *     for (long element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function + * is associative, and {@code seed} value has identity properties, + * consider using {@link #reduce(long, LongBinaryOperator)} method. + * + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #reduce(long, LongBinaryOperator) + * @see #foldLeft(LongBinaryOperator) + * @since 10 + */ + default long foldLeft(long seed, LongBinaryOperator accumulator) { + ReduceOps.LongFoldLeftOp op = new ReduceOps.LongFoldLeftOp(accumulator); + op.accept(seed); + forEachOrdered(op); + return op.getAsLong(); + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going left to right. This is equivalent to: + * + *

+     * {@code
+     *     boolean foundAny = false;
+     *     long result = 0;
+     *     for (long element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? OptionalLong.of(result) : OptionalLong.empty();
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

+ * This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function is + * associative, consider using {@link #reduce(LongBinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(long, LongBinaryOperator) + * @see #reduce(LongBinaryOperator) + * @since 10 + */ + default OptionalLong foldLeft(LongBinaryOperator accumulator) { + ReduceOps.LongFoldLeftOp op = new ReduceOps.LongFoldLeftOp(accumulator); + forEachOrdered(op); + return op.get(); + } + + /** + * Folds the elements of this stream using the provided {@code seed} value and + * accumulation function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, and {@code seed} value has identity properties, + * consider using {@link #reduce(long, LongBinaryOperator)} method. + * + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(long, LongBinaryOperator) + * @see #reduce(long, LongBinaryOperator) + * @since 10 + */ + default long foldRight(long seed, LongBinaryOperator accumulator) { + long[] array = toArray(); + long result = seed; + for(int idx = array.length - 1; idx >= 0; idx--) { + result = accumulator.applyAsLong(array[idx], result); + } + return result; + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, consider using {@link #reduce(LongBinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(long, LongBinaryOperator) + * @see #reduce(long, LongBinaryOperator) + * @since 10 + */ + default OptionalLong foldRight(LongBinaryOperator accumulator) { + long[] array = toArray(); + int idx = array.length; + if (idx == 0) return OptionalLong.empty(); + long result = array[--idx]; + while(idx > 0) { + long t = array[--idx]; + result = accumulator.applyAsLong(t, result); + } + return OptionalLong.of(result); + } + + /** * Performs a mutable * reduction operation on the elements of this stream. A mutable * reduction is one in which the reduced value is a mutable result container, --- old/src/java.base/share/classes/java/util/stream/ReduceOps.java 2017-08-13 19:17:30.802448000 +0600 +++ new/src/java.base/share/classes/java/util/stream/ReduceOps.java 2017-08-13 19:17:30.539414600 +0600 @@ -34,9 +34,13 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BinaryOperator; +import java.util.function.Consumer; import java.util.function.DoubleBinaryOperator; +import java.util.function.DoubleConsumer; import java.util.function.IntBinaryOperator; +import java.util.function.IntConsumer; import java.util.function.LongBinaryOperator; +import java.util.function.LongConsumer; import java.util.function.ObjDoubleConsumer; import java.util.function.ObjIntConsumer; import java.util.function.ObjLongConsumer; @@ -963,4 +967,135 @@ super.onCompletion(caller); } } + + static final class FoldLeftWithSeedOp extends Box implements Consumer { + private final BiFunction op; + + FoldLeftWithSeedOp(U seed, BiFunction op) { + this.state = seed; + this.op = op; + } + + @Override + public void accept(T t) { + state = op.apply(state, t); + } + } + + static final class FoldLeftOp implements Consumer { + private final BinaryOperator op; + private T state; + private boolean empty = true; + + FoldLeftOp(BinaryOperator op) { + this.op = op; + } + + @Override + public void accept(T t) { + if (empty) { + state = t; + empty = false; + } else { + state = op.apply(state, t); + } + } + + Optional get() { + return empty ? Optional.empty() : Optional.of(state); + } + } + + static final class IntFoldLeftOp implements IntConsumer { + private final IntBinaryOperator op; + private int state; + private boolean empty = true; + + IntFoldLeftOp(IntBinaryOperator op) { + this.op = op; + } + + @Override + public void accept(int t) { + if (empty) { + state = t; + empty = false; + } else { + state = op.applyAsInt(state, t); + } + } + + OptionalInt get() { + return empty ? OptionalInt.empty() : OptionalInt.of(state); + } + + int getAsInt() { + if (empty) { + throw new IllegalStateException(); + } + return state; + } + } + + static final class LongFoldLeftOp implements LongConsumer { + private final LongBinaryOperator op; + private long state; + private boolean empty = true; + + LongFoldLeftOp(LongBinaryOperator op) { + this.op = op; + } + + @Override + public void accept(long t) { + if (empty) { + state = t; + empty = false; + } else { + state = op.applyAsLong(state, t); + } + } + + OptionalLong get() { + return empty ? OptionalLong.empty() : OptionalLong.of(state); + } + + long getAsLong() { + if (empty) { + throw new IllegalStateException(); + } + return state; + } + } + + static final class DoubleFoldLeftOp implements DoubleConsumer { + private final DoubleBinaryOperator op; + private double state; + private boolean empty = true; + + DoubleFoldLeftOp(DoubleBinaryOperator op) { + this.op = op; + } + + @Override + public void accept(double t) { + if (empty) { + state = t; + empty = false; + } else { + state = op.applyAsDouble(state, t); + } + } + + OptionalDouble get() { + return empty ? OptionalDouble.empty() : OptionalDouble.of(state); + } + + double getAsDouble() { + if (empty) { + throw new IllegalStateException(); + } + return state; + } + } } --- old/src/java.base/share/classes/java/util/stream/Stream.java 2017-08-13 19:17:31.766570400 +0600 +++ new/src/java.base/share/classes/java/util/stream/Stream.java 2017-08-13 19:17:31.522539400 +0600 @@ -847,6 +847,157 @@ BinaryOperator combiner); /** + * Folds the elements of this stream using the provided seed object and + * accumulation function, going left to right. This is equivalent to: + * + *

{@code
+     *     U result = seed;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function is + * associative and you can provide a combiner function, consider using + * {@link #reduce(Object, BiFunction, BinaryOperator)} method. + * + * @param The type of the result + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldRight(Object, BiFunction) + * @see #reduce(Object, BinaryOperator) + * @see #reduce(Object, BiFunction, BinaryOperator) + * @since 10 + */ + default U foldLeft(U seed, BiFunction accumulator) { + ReduceOps.FoldLeftWithSeedOp consumer = new ReduceOps.FoldLeftWithSeedOp<>(seed, accumulator); + forEachOrdered(consumer); + return consumer.get(); + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going left to right. This is equivalent to: + * + *

{@code
+     *     boolean foundAny = false;
+     *     T result = null;
+     *     for (T element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? Optional.of(result) : Optional.empty();
+     * }
+     * 
+ * + *

This is a terminal + * operation. + * + *

This method cannot take all the advantages of parallel streams as it must + * process elements strictly left to right. If your accumulator function is + * associative, consider using {@link #reduce(BinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(Object, BiFunction) + * @see #foldRight(BinaryOperator) + * @see #reduce(BinaryOperator) + * @since 10 + */ + default Optional foldLeft(BinaryOperator accumulator) { + ReduceOps.FoldLeftOp consumer = new ReduceOps.FoldLeftOp<>(accumulator); + forEachOrdered(consumer); + return consumer.get(); + } + + /** + * Folds the elements of this stream using the provided seed object and + * accumulation function, going right to left. + * + *

This is a terminal + * operation. + * + *

As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative and you can provide a combiner function, consider using + * {@link #reduce(Object, BiFunction, BinaryOperator)} method. + * + * @param The type of the result + * @param seed the starting value + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldLeft(Object, BiFunction) + * @see #reduce(Object, BinaryOperator) + * @see #reduce(Object, BiFunction, BinaryOperator) + * @since 10 + */ + default U foldRight(U seed, BiFunction accumulator) { + Object[] array = toArray(); + U result = seed; + for(int idx = array.length - 1; idx >= 0; idx--) { + @SuppressWarnings("unchecked") + T t = (T) array[idx]; + result = accumulator.apply(t, result); + } + return result; + } + + /** + * Folds the elements of this stream using the provided accumulation + * function, going right to left. + * + *

This is a terminal + * operation. + * + *

+ * As this method must process elements strictly right to left, it cannot + * start processing till all the previous stream stages complete. Also it + * requires intermediate memory to store the whole content of the stream as + * the stream natural order is left to right. If your accumulator function + * is associative, consider using {@link #reduce(BinaryOperator)} method. + * + * @param accumulator a non-interfering, + * stateless + * function for incorporating an additional element into a result + * @return the result of the folding + * @see #foldRight(Object, BiFunction) + * @see #foldLeft(BinaryOperator) + * @see #reduce(BinaryOperator) + * @since 10 + */ + default Optional foldRight(BinaryOperator accumulator) { + Object[] array = toArray(); + int idx = array.length; + if (idx == 0) return Optional.empty(); + @SuppressWarnings("unchecked") + T result = (T) array[--idx]; + while(idx > 0) { + @SuppressWarnings("unchecked") + T t = (T) array[--idx]; + result = accumulator.apply(t, result); + } + return Optional.of(result); + } + + /** * Performs a mutable * reduction operation on the elements of this stream. A mutable * reduction is one in which the reduced value is a mutable result container,