Skip to content

Commit

Permalink
feat: add batchGetSuccessNow and tupleGetSuccessNow methods ☘️
Browse files Browse the repository at this point in the history
  • Loading branch information
oldratlee committed May 18, 2024
1 parent c6449db commit 6595ccf
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -484,15 +484,21 @@ private static <T> CompletableFuture<T> allTupleOf0(CompletionStage<?>[] css, bo
if (fastFail) resultSetter = allOfFastFail(resultSetterCfs);
else resultSetter = CompletableFuture.allOf(resultSetterCfs);

final CompletableFuture<Object> 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<Object> ret = resultSetter.thenApply(unused -> tupleOf0(result));
return f_cast(ret);
}

@SuppressWarnings("unchecked")
private static <T> 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:
//
Expand Down Expand Up @@ -1009,7 +1015,7 @@ C peekAsync(C cf, BiConsumer<? super T, ? super Throwable> action, Executor exec
}

////////////////////////////////////////////////////////////////////////////////
//# Backport CF static methods
//# Backport CF static methods + related enhanced methods
// compatibility for low Java versions
////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -1304,6 +1310,7 @@ public static <T> T join(CompletableFuture<T> 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
Expand Down Expand Up @@ -1429,6 +1436,81 @@ public static CffuState state(CompletableFuture<?> cf) {
}
}

//# New enhanced batch read(explicitly) methods

/**
* Batch gets the results in the <strong>same order</strong> 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 <T> List<T> batchGetSuccessNow(@Nullable T valueIfNotSuccess, CompletionStage<? extends T>... cfs) {
return arrayList(batchGet0(cf -> getSuccessNow(cf, valueIfNotSuccess), cfs));
}

@SafeVarargs
@SuppressWarnings("unchecked")
private static <T> T[] batchGet0(Function<CompletableFuture<T>, ? extends T> resultGetter,
CompletionStage<? extends T>... cfs) {
final CompletableFuture<T>[] cfArray = f_toCfArray(cfs);
Object[] ret = new Object[cfs.length];
for (int i = 0; i < cfArray.length; i++) {
CompletableFuture<T> cf = cfArray[i];
ret[i] = resultGetter.apply(cf);
}
return (T[]) ret;
}

/**
* Batch gets the result value in the <strong>same order</strong> 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 <T1, T2> Tuple2<T1, T2> tupleGetSuccessNow(
CompletionStage<? extends T1> cf1, CompletionStage<? extends T2> cf2) {
return tupleGet0(requireCfsAndEleNonNull(cf1, cf2));
}

/**
* Batch gets the result value in the <strong>same order</strong> 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 <T1, T2, T3> Tuple3<T1, T2, T3> tupleGetSuccessNow(
CompletionStage<? extends T1> cf1, CompletionStage<? extends T2> cf2, CompletionStage<? extends T3> cf3) {
return tupleGet0(requireCfsAndEleNonNull(cf1, cf2, cf3));
}

/**
* Batch gets the result value in the <strong>same order</strong> 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 <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> tupleGetSuccessNow(
CompletionStage<? extends T1> cf1, CompletionStage<? extends T2> cf2,
CompletionStage<? extends T3> cf3, CompletionStage<? extends T4> cf4) {
return tupleGet0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4));
}

/**
* Batch gets the result value in the <strong>same order</strong> 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 <T1, T2, T3, T4, T5> Tuple5<T1, T2, T3, T4, T5> tupleGetSuccessNow(
CompletionStage<? extends T1> cf1, CompletionStage<? extends T2> cf2, CompletionStage<? extends T3> cf3,
CompletionStage<? extends T4> cf4, CompletionStage<? extends T5> cf5) {
return tupleGet0(requireCfsAndEleNonNull(cf1, cf2, cf3, cf4, cf5));
}

private static <T> T tupleGet0(CompletionStage<?>... css) {
return tupleOf0(batchGet0(cf -> getSuccessNow(cf, null), css));
}

//# Write methods of CompletableFuture

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,24 @@ void test_read() {
assertEquals(n, join(later, 3, TimeUnit.SECONDS));
}

@Test
void test_gets() {
final CompletableFuture<Integer> completed = completedFuture(n);
final CompletableFuture<Integer> failed = failedFuture(rte);
final CompletableFuture<Integer> cancelled = createCancelledFuture();
final CompletableFuture<Integer> 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());
Expand Down

0 comments on commit 6595ccf

Please sign in to comment.