package peergos.shared.util; import java.util.*; import java.util.concurrent.*; import java.util.function.*; import java.util.stream.*; public class Futures { /** * * @param futures collection of independent futures whose results we want to combine * @param <T> result type of each future * @return */ public static <T> CompletableFuture<Set<T>> combineAll(Collection<CompletableFuture<T>> futures) { CompletableFuture<Set<T>> identity = CompletableFuture.completedFuture(Collections.emptySet()); return futures.stream().reduce(identity, (a, b) -> b.thenCompose(opt -> a.thenApply(set -> Stream.concat(set.stream(), Stream.of(opt)) .collect(Collectors.toSet()))), (a, b) -> b.thenCompose(setb -> a.thenApply(seta -> Stream.concat(seta.stream(), setb.stream()).collect(Collectors.toSet())))); } /** * * @param futures collection of independent futures whose results we want to combine * @param <T> result type of each future * @return */ public static <T> CompletableFuture<List<T>> combineAllInOrder(Collection<CompletableFuture<T>> futures) { CompletableFuture<List<T>> identity = CompletableFuture.completedFuture(Collections.emptyList()); return futures.stream().reduce(identity, (a, b) -> b.thenCompose(opt -> a.thenApply(set -> Stream.concat(set.stream(), Stream.of(opt)) .collect(Collectors.toList()))), (a, b) -> b.thenCompose(setb -> a.thenApply(seta -> Stream.concat(seta.stream(), setb.stream()).collect(Collectors.toList())))); } /*** Reduce a set of input values against an Identity where the composition step is asynchronous * * @param input the values to reduce * @param identity the identity of the target type * @param composer composes an input value with a target type value asynchronously * @param combiner * @param <T> target type * @param <V> input type * @return */ public static <T, V> CompletableFuture<T> reduceAll(Collection<V> input, T identity, BiFunction<T, V, CompletableFuture<T>> composer, BiFunction<T, T, T> combiner) { CompletableFuture<T> identityFut = CompletableFuture.completedFuture(identity); return input.stream().reduce( identityFut, (a, b) -> a.thenCompose(res -> composer.apply(res, b)), (a, b) -> a.thenCompose(x -> b.thenApply(y -> combiner.apply(x, y))) ); } public static <T> T logError(Throwable t) { t.printStackTrace(); throw new RuntimeException(t.getMessage(), t); } }