package bjc.utils.funcutils; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; import bjc.data.IHolder; import bjc.data.IPair; import bjc.data.Identity; import bjc.data.Pair; /** * Implementation of a collecter that uses two collectors. * * @author Ben Culkin */ final class CompoundCollector implements Collector>, IPair> { /* Our characteristics. */ private final Set characteristicSet; /* The first collector. */ private final Collector first; /* The second collector. */ private final Collector second; /** * Create a collector that uses two collectors. * * @param first * The first collector. * * @param second * The second collector. */ public CompoundCollector(final Collector first, final Collector second) { this.first = first; this.second = second; /* Accumulate characteristics. */ characteristicSet = first.characteristics(); characteristicSet.addAll(second.characteristics()); } @Override public BiConsumer>, InitialType> accumulator() { final BiConsumer firstAccumulator = first.accumulator(); final BiConsumer secondAccumulator = second.accumulator(); return (state, value) -> { state.doWith(statePair -> { statePair.doWith((left, right) -> { firstAccumulator.accept(left, value); secondAccumulator.accept(right, value); }); }); }; } @Override public Set characteristics() { return characteristicSet; } @Override public BinaryOperator>> combiner() { final BinaryOperator firstCombiner = first.combiner(); final BinaryOperator secondCombiner = second.combiner(); return (leftState, rightState) -> { return leftState.unwrap(leftPair -> { return rightState.transform(rightPair -> { return leftPair.combine(rightPair, firstCombiner, secondCombiner); }); }); }; } @Override public Function>, IPair> finisher() { return state -> { return state.unwrap(pair -> { return pair.bind((left, right) -> { final FinalType1 finalLeft = first.finisher().apply(left); final FinalType2 finalRight = second.finisher().apply(right); return new Pair<>(finalLeft, finalRight); }); }); }; } @Override public Supplier>> supplier() { return () -> { final AuxType1 initialLeft = first.supplier().get(); final AuxType2 initialRight = second.supplier().get(); return new Identity<>(new Pair<>(initialLeft, initialRight)); }; } }