package org.codefx.mvn.jdeps.tool; import com.google.common.collect.Sets; import org.codefx.mvn.jdeps.tool.PairCollector.Pair; 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; /** * Uses two collectors on a stream of pairs to create a pair of collection results. * * @param <T> * the type of input elements to the reduction operation * @param <A> * the result type of the first reduction operation * @param <B> * the result type of the second reduction operation * @param <CA> * the mutable accumulation type of the first reduction operation * @param <CB> * the mutable accumulation type of the second reduction operation */ public class PairCollector<T, A, B, CA, CB> implements Collector<T, Pair<CA, CB>, Pair<A, B>> { /* * TODO: This class should be polished, tested and placed somewhere else. */ private final Collector<T, CA, A> firstCollector; private final Collector<T, CB, B> secondCollector; private PairCollector(Collector<T, CA, A> firstCollector, Collector<T, CB, B> secondCollector) { this.firstCollector = firstCollector; this.secondCollector = secondCollector; } public static <T, A, B, CA, CB> Collector<T, ?, Pair<A, B>> pairing( Collector<T, CA, A> firstCollector, Collector<T, CB, B> secondCollector) { return new PairCollector<>(firstCollector, secondCollector); } @Override public Supplier<Pair<CA, CB>> supplier() { return () -> new Pair<>(firstCollector.supplier().get(), secondCollector.supplier().get()); } @Override public BiConsumer<Pair<CA, CB>, T> accumulator() { return (containers, newValue) -> { firstCollector.accumulator().accept(containers.first, newValue); secondCollector.accumulator().accept(containers.second, newValue); }; } @Override public BinaryOperator<Pair<CA, CB>> combiner() { return (containers, otherContainers) -> { CA firstNewContainer = firstCollector.combiner().apply(containers.first, otherContainers.first); CB secondNewContainer = secondCollector.combiner().apply(containers.second, otherContainers.second); return new Pair<>(firstNewContainer, secondNewContainer); }; } @Override public Function<Pair<CA, CB>, Pair<A, B>> finisher() { return containers -> { A firstResult = firstCollector.finisher().apply(containers.first); B secondResult = secondCollector.finisher().apply(containers.second); return new Pair<>(firstResult, secondResult); }; } @Override public Set<Characteristics> characteristics() { return Sets.intersection(firstCollector.characteristics(), secondCollector.characteristics()); } public static class Pair<A, B> { public final A first; public final B second; Pair(A first, B second) { this.first = first; this.second = second; } } }