java8.util.stream.ReduceOps Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of streamsupport Show documentation
Show all versions of streamsupport Show documentation
streamsupport is a backport of the Java 8 java.util.function (functional interfaces) and
java.util.stream (streams) API for Java 6 / 7 and Android developers
/*
* Copyright (c) 2012, 2015, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 java8.util.stream;
import java8.util.concurrent.CountedCompleter;
import java8.util.Objects;
import java8.util.function.BiConsumer;
import java8.util.function.BiFunction;
import java8.util.function.BinaryOperator;
import java8.util.function.DoubleBinaryOperator;
import java8.util.function.IntBinaryOperator;
import java8.util.function.LongBinaryOperator;
import java8.util.function.ObjDoubleConsumer;
import java8.util.function.ObjIntConsumer;
import java8.util.function.ObjLongConsumer;
import java8.util.function.Supplier;
import java8.util.Optional;
import java8.util.OptionalDouble;
import java8.util.OptionalInt;
import java8.util.OptionalLong;
import java8.util.Spliterator;
/**
* Factory for creating instances of {@code TerminalOp} that implement
* reductions.
*
* @since 1.8
*/
final class ReduceOps {
private ReduceOps() { }
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* reference values.
*
* @param the type of the input elements
* @param the type of the result
* @param seed the identity element for the reduction
* @param reducer the accumulating function that incorporates an additional
* input element into the result
* @param combiner the combining function that combines two intermediate
* results
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeRef(final U seed, final BiFunction reducer, final BinaryOperator combiner) {
Objects.requireNonNull(reducer);
Objects.requireNonNull(combiner);
class ReducingSink extends Box implements AccumulatingSink {
@Override
public void begin(long size) {
state = seed;
}
@Override
public void accept(T t) {
state = reducer.apply(state, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp(StreamShape.REFERENCE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* reference values producing an optional reference result.
*
* @param The type of the input elements, and the type of the result
* @param operator The reducing function
* @return A {@code TerminalOp} implementing the reduction
*/
public static TerminalOp>
makeRef(final BinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, ReducingSink> {
private boolean empty;
private T state;
public void begin(long size) {
empty = true;
state = null;
}
@Override
public void accept(T t) {
if (empty) {
empty = false;
state = t;
} else {
state = operator.apply(state, t);
}
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public Optional get() {
return empty ? Optional.empty() : Optional.of(state);
}
@Override
public void combine(ReducingSink other) {
if (!other.empty)
accept(other.state);
}
}
return new ReduceOp, ReducingSink>(StreamShape.REFERENCE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a mutable reduce on
* reference values.
*
* @param the type of the input elements
* @param the type of the intermediate reduction result
* @param collector a {@code Collector} defining the reduction
* @return a {@code ReduceOp} implementing the reduction
*/
public static TerminalOp
makeRef(final Collector super T, I, ?> collector) {
final Supplier supplier = Objects.requireNonNull(collector).supplier();
final BiConsumer accumulator = collector.accumulator();
final BinaryOperator combiner = collector.combiner();
class ReducingSink extends Box
implements AccumulatingSink {
@Override
public void begin(long size) {
state = supplier.get();
}
@Override
public void accept(T t) {
accumulator.accept(state, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp(StreamShape.REFERENCE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
@Override
public int getOpFlags() {
return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
? StreamOpFlag.NOT_ORDERED
: 0;
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a mutable reduce on
* reference values.
*
* @param the type of the input elements
* @param the type of the result
* @param seedFactory a factory to produce a new base accumulator
* @param accumulator a function to incorporate an element into an
* accumulator
* @param reducer a function to combine an accumulator into another
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeRef(final Supplier seedFactory,
final BiConsumer accumulator,
final BiConsumer reducer) {
Objects.requireNonNull(seedFactory);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(reducer);
class ReducingSink extends Box
implements AccumulatingSink {
@Override
public void begin(long size) {
state = seedFactory.get();
}
@Override
public void accept(T t) {
accumulator.accept(state, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public void combine(ReducingSink other) {
reducer.accept(state, other.state);
}
}
return new ReduceOp(StreamShape.REFERENCE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that counts the number of stream
* elements. If the size of the pipeline is known then count is the size
* and there is no need to evaluate the pipeline. If the size of the
* pipeline is non known then count is produced, via reduction, using a
* {@link CountingSink}.
*
* @param the type of the input elements
* @return a {@code TerminalOp} implementing the counting
*/
public static TerminalOp
makeRefCounting() {
return new ReduceOp>(StreamShape.REFERENCE) {
@Override
public CountingSink makeSink() { return new CountingSink.OfRef<>(); }
@Override
public Long evaluateSequential(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateSequential(helper, spliterator);
}
@Override
public Long evaluateParallel(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateParallel(helper, spliterator);
}
@Override
public int getOpFlags() {
return StreamOpFlag.NOT_ORDERED;
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* {@code int} values.
*
* @param identity the identity for the combining function
* @param operator the combining function
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeInt(final int identity, final IntBinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, Sink.OfInt {
private int state;
@Override
public void begin(long size) {
state = identity;
}
@Override
public void accept(int t) {
state = operator.applyAsInt(state, t);
}
@Override
public void accept(Integer t) {
SinkDefaults.OfInt.accept(this, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public Integer get() {
return state;
}
@Override
public void combine(ReducingSink other) {
accept(other.state);
}
}
return new ReduceOp(StreamShape.INT_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* {@code int} values, producing an optional integer result.
*
* @param operator the combining function
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeInt(final IntBinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, Sink.OfInt {
private boolean empty;
private int state;
public void begin(long size) {
empty = true;
state = 0;
}
@Override
public void accept(int t) {
if (empty) {
empty = false;
state = t;
}
else {
state = operator.applyAsInt(state, t);
}
}
@Override
public void accept(Integer t) {
SinkDefaults.OfInt.accept(this, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public OptionalInt get() {
return empty ? OptionalInt.empty() : OptionalInt.of(state);
}
@Override
public void combine(ReducingSink other) {
if (!other.empty)
accept(other.state);
}
}
return new ReduceOp(StreamShape.INT_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a mutable reduce on
* {@code int} values.
*
* @param The type of the result
* @param supplier a factory to produce a new accumulator of the result type
* @param accumulator a function to incorporate an int into an
* accumulator
* @param combiner a function to combine an accumulator into another
* @return A {@code ReduceOp} implementing the reduction
*/
public static TerminalOp
makeInt(final Supplier supplier,
final ObjIntConsumer accumulator,
final BinaryOperator combiner) {
Objects.requireNonNull(supplier);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(combiner);
class ReducingSink extends Box
implements AccumulatingSink, Sink.OfInt {
@Override
public void begin(long size) {
state = supplier.get();
}
@Override
public void accept(int t) {
accumulator.accept(state, t);
}
@Override
public void accept(Integer t) {
SinkDefaults.OfInt.accept(this, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp(StreamShape.INT_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that counts the number of stream
* elements. If the size of the pipeline is known then count is the size
* and there is no need to evaluate the pipeline. If the size of the
* pipeline is non known then count is produced, via reduction, using a
* {@link CountingSink}.
*
* @return a {@code TerminalOp} implementing the counting
*/
public static TerminalOp
makeIntCounting() {
return new ReduceOp>(StreamShape.INT_VALUE) {
@Override
public CountingSink makeSink() { return new CountingSink.OfInt(); }
@Override
public Long evaluateSequential(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateSequential(helper, spliterator);
}
@Override
public Long evaluateParallel(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateParallel(helper, spliterator);
}
@Override
public int getOpFlags() {
return StreamOpFlag.NOT_ORDERED;
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* {@code long} values.
*
* @param identity the identity for the combining function
* @param operator the combining function
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeLong(final long identity, final LongBinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, Sink.OfLong {
private long state;
@Override
public void begin(long size) {
state = identity;
}
@Override
public void accept(long t) {
state = operator.applyAsLong(state, t);
}
@Override
public void accept(Long t) {
SinkDefaults.OfLong.accept(this, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public Long get() {
return state;
}
@Override
public void combine(ReducingSink other) {
accept(other.state);
}
}
return new ReduceOp(StreamShape.LONG_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* {@code long} values, producing an optional long result.
*
* @param operator the combining function
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeLong(final LongBinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, Sink.OfLong {
private boolean empty;
private long state;
public void begin(long size) {
empty = true;
state = 0;
}
@Override
public void accept(long t) {
if (empty) {
empty = false;
state = t;
}
else {
state = operator.applyAsLong(state, t);
}
}
@Override
public void accept(Long t) {
SinkDefaults.OfLong.accept(this, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public OptionalLong get() {
return empty ? OptionalLong.empty() : OptionalLong.of(state);
}
@Override
public void combine(ReducingSink other) {
if (!other.empty)
accept(other.state);
}
}
return new ReduceOp(StreamShape.LONG_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a mutable reduce on
* {@code long} values.
*
* @param the type of the result
* @param supplier a factory to produce a new accumulator of the result type
* @param accumulator a function to incorporate an int into an
* accumulator
* @param combiner a function to combine an accumulator into another
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeLong(final Supplier supplier,
final ObjLongConsumer accumulator,
final BinaryOperator combiner) {
Objects.requireNonNull(supplier);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(combiner);
class ReducingSink extends Box
implements AccumulatingSink, Sink.OfLong {
@Override
public void begin(long size) {
state = supplier.get();
}
@Override
public void accept(long t) {
accumulator.accept(state, t);
}
@Override
public void accept(Long t) {
SinkDefaults.OfLong.accept(this, t);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp(StreamShape.LONG_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that counts the number of stream
* elements. If the size of the pipeline is known then count is the size
* and there is no need to evaluate the pipeline. If the size of the
* pipeline is non known then count is produced, via reduction, using a
* {@link CountingSink}.
*
* @return a {@code TerminalOp} implementing the counting
*/
public static TerminalOp
makeLongCounting() {
return new ReduceOp>(StreamShape.LONG_VALUE) {
@Override
public CountingSink makeSink() { return new CountingSink.OfLong(); }
@Override
public Long evaluateSequential(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateSequential(helper, spliterator);
}
@Override
public Long evaluateParallel(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateParallel(helper, spliterator);
}
@Override
public int getOpFlags() {
return StreamOpFlag.NOT_ORDERED;
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* {@code double} values.
*
* @param identity the identity for the combining function
* @param operator the combining function
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeDouble(final double identity, final DoubleBinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, Sink.OfDouble {
private double state;
@Override
public void begin(long size) {
state = identity;
}
@Override
public void accept(double t) {
state = operator.applyAsDouble(state, t);
}
@Override
public void accept(Double i) {
SinkDefaults.OfDouble.accept(this, i);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public Double get() {
return state;
}
@Override
public void combine(ReducingSink other) {
accept(other.state);
}
}
return new ReduceOp(StreamShape.DOUBLE_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a functional reduce on
* {@code double} values, producing an optional double result.
*
* @param operator the combining function
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeDouble(final DoubleBinaryOperator operator) {
Objects.requireNonNull(operator);
class ReducingSink
implements AccumulatingSink, Sink.OfDouble {
private boolean empty;
private double state;
public void begin(long size) {
empty = true;
state = 0;
}
@Override
public void accept(double t) {
if (empty) {
empty = false;
state = t;
}
else {
state = operator.applyAsDouble(state, t);
}
}
@Override
public void accept(Double i) {
SinkDefaults.OfDouble.accept(this, i);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public OptionalDouble get() {
return empty ? OptionalDouble.empty() : OptionalDouble.of(state);
}
@Override
public void combine(ReducingSink other) {
if (!other.empty)
accept(other.state);
}
}
return new ReduceOp(StreamShape.DOUBLE_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that implements a mutable reduce on
* {@code double} values.
*
* @param the type of the result
* @param supplier a factory to produce a new accumulator of the result type
* @param accumulator a function to incorporate an int into an
* accumulator
* @param combiner a function to combine an accumulator into another
* @return a {@code TerminalOp} implementing the reduction
*/
public static TerminalOp
makeDouble(final Supplier supplier,
final ObjDoubleConsumer accumulator,
final BinaryOperator combiner) {
Objects.requireNonNull(supplier);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(combiner);
class ReducingSink extends Box
implements AccumulatingSink, Sink.OfDouble {
@Override
public void begin(long size) {
state = supplier.get();
}
@Override
public void accept(double t) {
accumulator.accept(state, t);
}
@Override
public void accept(Double i) {
SinkDefaults.OfDouble.accept(this, i);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
}
return new ReduceOp(StreamShape.DOUBLE_VALUE) {
@Override
public ReducingSink makeSink() {
return new ReducingSink();
}
};
}
/**
* Constructs a {@code TerminalOp} that counts the number of stream
* elements. If the size of the pipeline is known then count is the size
* and there is no need to evaluate the pipeline. If the size of the
* pipeline is non known then count is produced, via reduction, using a
* {@link CountingSink}.
*
* @return a {@code TerminalOp} implementing the counting
*/
public static TerminalOp
makeDoubleCounting() {
return new ReduceOp>(StreamShape.DOUBLE_VALUE) {
@Override
public CountingSink makeSink() { return new CountingSink.OfDouble(); }
@Override
public Long evaluateSequential(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateSequential(helper, spliterator);
}
@Override
public Long evaluateParallel(PipelineHelper helper,
Spliterator spliterator) {
if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
return spliterator.getExactSizeIfKnown();
return super.evaluateParallel(helper, spliterator);
}
@Override
public int getOpFlags() {
return StreamOpFlag.NOT_ORDERED;
}
};
}
/**
* A sink that counts elements
*/
abstract static class CountingSink
extends Box
implements AccumulatingSink> {
long count;
@Override
public void begin(long size) {
count = 0L;
}
@Override
public Long get() {
return count;
}
@Override
public void combine(CountingSink other) {
count += other.count;
}
@Override
public void end() {
}
@Override
public boolean cancellationRequested() {
return false;
}
@Override
public void accept(int value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(long value) {
SinkDefaults.accept(this, value);
}
@Override
public void accept(double value) {
SinkDefaults.accept(this, value);
}
static final class OfRef extends CountingSink {
@Override
public void accept(T t) {
count++;
}
}
static final class OfInt extends CountingSink implements Sink.OfInt {
@Override
public void accept(int t) {
count++;
}
@Override
public void accept(Integer i) {
SinkDefaults.OfInt.accept(this, i);
}
}
static final class OfLong extends CountingSink implements Sink.OfLong {
@Override
public void accept(long t) {
count++;
}
@Override
public void accept(Long l) {
SinkDefaults.OfLong.accept(this, l);
}
}
static final class OfDouble extends CountingSink implements Sink.OfDouble {
@Override
public void accept(double t) {
count++;
}
@Override
public void accept(Double d) {
SinkDefaults.OfDouble.accept(this, d);
}
}
}
/**
* A type of {@code TerminalSink} that implements an associative reducing
* operation on elements of type {@code T} and producing a result of type
* {@code R}.
*
* @param the type of input element to the combining operation
* @param the result type
* @param the type of the {@code AccumulatingSink}.
*/
private interface AccumulatingSink>
extends TerminalSink {
void combine(K other);
}
/**
* State box for a single state element, used as a base class for
* {@code AccumulatingSink} instances
*
* @param The type of the state element
*/
private abstract static class Box {
U state;
Box() {} // Avoid creation of special accessor
public U get() {
return state;
}
}
/**
* A {@code TerminalOp} that evaluates a stream pipeline and sends the
* output into an {@code AccumulatingSink}, which performs a reduce
* operation. The {@code AccumulatingSink} must represent an associative
* reducing operation.
*
* @param the output type of the stream pipeline
* @param the result type of the reducing operation
* @param the type of the {@code AccumulatingSink}
*/
private abstract static class ReduceOp>
implements TerminalOp {
private final StreamShape inputShape;
/**
* Create a {@code ReduceOp} of the specified stream shape which uses
* the specified {@code Supplier} to create accumulating sinks.
*
* @param shape The shape of the stream pipeline
*/
ReduceOp(StreamShape shape) {
inputShape = shape;
}
public abstract S makeSink();
@Override
public StreamShape inputShape() {
return inputShape;
}
@Override
public int getOpFlags() {
return 0;
}
@Override
public R evaluateSequential(PipelineHelper helper,
Spliterator spliterator) {
return helper.wrapAndCopyInto(makeSink(), spliterator).get();
}
@Override
public R evaluateParallel(PipelineHelper helper,
Spliterator spliterator) {
return new ReduceTask<>(this, helper, spliterator).invoke().get();
}
}
/**
* A {@code ForkJoinTask} for performing a parallel reduce operation.
*/
@SuppressWarnings("serial")
private static final class ReduceTask>
extends AbstractTask> {
private final ReduceOp op;
ReduceTask(ReduceOp op,
PipelineHelper helper,
Spliterator spliterator) {
super(helper, spliterator);
this.op = op;
}
ReduceTask(ReduceTask parent,
Spliterator spliterator) {
super(parent, spliterator);
this.op = parent.op;
}
@Override
protected ReduceTask makeChild(Spliterator spliterator) {
return new ReduceTask<>(this, spliterator);
}
@Override
protected S doLeaf() {
return helper.wrapAndCopyInto(op.makeSink(), spliterator);
}
@Override
public void onCompletion(CountedCompleter> caller) {
if (!isLeaf()) {
S leftResult = leftChild.getLocalResult();
leftResult.combine(rightChild.getLocalResult());
setLocalResult(leftResult);
}
// GC spliterator, left and right child
super.onCompletion(caller);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy