diff --git a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java index 7d27918e..df38d8c4 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -484,15 +484,21 @@ private static CompletableFuture allTupleOf0(CompletionStage[] css, bo if (fastFail) resultSetter = allOfFastFail(resultSetterCfs); else resultSetter = CompletableFuture.allOf(resultSetterCfs); - final CompletableFuture ret = resultSetter.thenApply(unused -> { - if (length == 2) return Tuple2.of(result[0], result[1]); - if (length == 3) return Tuple3.of(result[0], result[1], result[2]); - if (length == 4) return Tuple4.of(result[0], result[1], result[2], result[3]); - return Tuple5.of(result[0], result[1], result[2], result[3], result[4]); - }); + final CompletableFuture ret = resultSetter.thenApply(unused -> tupleOf0(result)); return f_cast(ret); } + @SuppressWarnings("unchecked") + private static T tupleOf0(Object... elements) { + final int length = elements.length; + final Object ret; + if (length == 2) ret = Tuple2.of(elements[0], elements[1]); + else if (length == 3) ret = Tuple3.of(elements[0], elements[1], elements[2]); + else if (length == 4) ret = Tuple4.of(elements[0], elements[1], elements[2], elements[3]); + else ret = Tuple5.of(elements[0], elements[1], elements[2], elements[3], elements[4]); + return (T) ret; + } + //////////////////////////////////////////////////////////////////////////////// //# `then both(binary input)` methods with fast-fail support: // @@ -1009,7 +1015,7 @@ C peekAsync(C cf, BiConsumer action, Executor exec } //////////////////////////////////////////////////////////////////////////////// - //# Backport CF static methods + //# Backport CF static methods + related enhanced methods // compatibility for low Java versions //////////////////////////////////////////////////////////////////////////////// @@ -1304,6 +1310,7 @@ public static T join(CompletableFuture cf, long timeout, TimeUnit unit) { * * @param valueIfNotSuccess the value to return if not completed successfully * @return the result value, if completed successfully, else the given valueIfNotSuccess + * @see #batchGetSuccessNow(Object, CompletionStage[]) */ @Contract(pure = true) @Nullable @@ -1429,6 +1436,81 @@ public static CffuState state(CompletableFuture cf) { } } + //# New enhanced batch read(explicitly) methods + + /** + * Batch gets the results in the same order of the given cfs, + * use the result value if the given stage is completed successfully, else use the given valueIfNotSuccess + * (aka the result extraction logic is {@link #getSuccessNow(CompletionStage, Object)}). + * + * @param cfs the stages + * @see #getSuccessNow(CompletionStage, Object) + */ + @Contract(pure = true) + @SafeVarargs + public static List batchGetSuccessNow(@Nullable T valueIfNotSuccess, CompletionStage... cfs) { + return arrayList(batchGet0(cf -> getSuccessNow(cf, valueIfNotSuccess), cfs)); + } + + @SafeVarargs + @SuppressWarnings("unchecked") + private static T[] batchGet0(Function, ? extends T> resultGetter, + CompletionStage... cfs) { + final CompletableFuture[] cfArray = f_toCfArray(cfs); + Object[] ret = new Object[cfs.length]; + for (int i = 0; i < cfArray.length; i++) { + CompletableFuture cf = cfArray[i]; + ret[i] = resultGetter.apply(cf); + } + return (T[]) ret; + } + + /** + * Batch gets the result value in the same order of the given cfs, + * use the result value if the cf is completed successfully, else use the value {@code null} + * (aka the result extraction logic is {@code getSuccessNow(cf, null)}). + */ + public static Tuple2 tupleGetSuccessNow( + CompletionStage cf1, CompletionStage cf2) { + return tupleGet0(requireCfsAndEleNonNull(cf1, cf2)); + } + + /** + * Batch gets the result value in the same order of the given cfs, + * use the result value if the cf is completed successfully, else use the value {@code null} + * (aka the result extraction logic is {@code getSuccessNow(cf, null)}). + */ + public static Tuple3 tupleGetSuccessNow( + CompletionStage cf1, CompletionStage cf2, CompletionStage cf3) { + return tupleGet0(requireCfsAndEleNonNull(cf1, cf2, cf3)); + } + + /** + * Batch gets the result value in the same order of the given cfs, + * use the result value if the cf is completed successfully, else use the value {@code null} + * (aka the result extraction logic is {@code getSuccessNow(cf, null)}). + */ + public static Tuple4 tupleGetSuccessNow( + CompletionStage cf1, CompletionStage cf2, + CompletionStage cf3, CompletionStage cf4) { + return tupleGet0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4)); + } + + /** + * Batch gets the result value in the same order of the given cfs, + * use the result value if the cf is completed successfully, else the value {@code null} + * (aka the result extraction logic is {@code getSuccessNow(cf, null)}). + */ + public static Tuple5 tupleGetSuccessNow( + CompletionStage cf1, CompletionStage cf2, CompletionStage cf3, + CompletionStage cf4, CompletionStage cf5) { + return tupleGet0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5)); + } + + private static T tupleGet0(CompletionStage... css) { + return tupleOf0(batchGet0(cf -> getSuccessNow(cf, null), css)); + } + //# Write methods of CompletableFuture /** diff --git a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java index 31b8ae49..c7761d74 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java @@ -967,6 +967,24 @@ void test_read() { assertEquals(n, join(later, 3, TimeUnit.SECONDS)); } + @Test + void test_gets() { + final CompletableFuture completed = completedFuture(n); + final CompletableFuture failed = failedFuture(rte); + final CompletableFuture cancelled = createCancelledFuture(); + final CompletableFuture incomplete = createIncompleteFuture(); + + assertEquals(Arrays.asList(n, anotherN, anotherN, anotherN), + batchGetSuccessNow(anotherN, completed, incomplete, cancelled, failed)); + + assertEquals(Tuple2.of(n, null), tupleGetSuccessNow(completed, failed)); + assertEquals(Tuple3.of(null, n, null), tupleGetSuccessNow(failed, completed, cancelled)); + assertEquals(Tuple4.of(null, n, null, anotherN), + tupleGetSuccessNow(failed, completed, cancelled, completedFuture(anotherN))); + assertEquals(Tuple5.of(null, n, null, anotherN, null), + tupleGetSuccessNow(failed, completed, cancelled, completedFuture(anotherN), failed)); + } + @Test void test_write() throws Exception { assertEquals(n, completeAsync(createIncompleteFuture(), () -> n).get());