|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
/* |
|
* This file is available under and governed by the GNU General Public |
|
* License version 2 only, as published by the Free Software Foundation. |
|
* However, the following notice accompanied the original version of this |
|
* file: |
|
* |
|
* Written by Doug Lea with assistance from members of JCP JSR-166 |
|
* Expert Group and released to the public domain, as explained at |
|
* http://creativecommons.org/publicdomain/zero/1.0/ |
|
*/ |
|
|
|
package java.util.concurrent; |
|
import java.util.function.Supplier; |
|
import java.util.function.Consumer; |
|
import java.util.function.BiConsumer; |
|
import java.util.function.Function; |
|
import java.util.function.BiFunction; |
|
import java.util.concurrent.Future; |
|
import java.util.concurrent.TimeUnit; |
|
import java.util.concurrent.ForkJoinPool; |
|
import java.util.concurrent.ForkJoinTask; |
|
import java.util.concurrent.Executor; |
|
import java.util.concurrent.ThreadLocalRandom; |
|
import java.util.concurrent.ExecutionException; |
|
import java.util.concurrent.TimeoutException; |
|
import java.util.concurrent.CancellationException; |
|
import java.util.concurrent.CompletionException; |
|
import java.util.concurrent.CompletionStage; |
|
import java.util.concurrent.locks.LockSupport; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> { |
|
|
|
/* |
|
* Overview: |
|
* |
|
* A CompletableFuture may have dependent completion actions, |
|
* collected in a linked stack. It atomically completes by CASing |
|
* a result field, and then pops off and runs those actions. This |
|
* applies across normal vs exceptional outcomes, sync vs async |
|
* actions, binary triggers, and various forms of completions. |
|
* |
|
* Non-nullness of field result (set via CAS) indicates done. An |
|
* AltResult is used to box null as a result, as well as to hold |
|
* exceptions. Using a single field makes completion simple to |
|
* detect and trigger. Encoding and decoding is straightforward |
|
* but adds to the sprawl of trapping and associating exceptions |
|
* with targets. Minor simplifications rely on (static) NIL (to |
|
* box null results) being the only AltResult with a null |
|
* exception field, so we don't usually need explicit comparisons. |
|
* Even though some of the generics casts are unchecked (see |
|
* SuppressWarnings annotations), they are placed to be |
|
* appropriate even if checked. |
|
* |
|
* Dependent actions are represented by Completion objects linked |
|
* as Treiber stacks headed by field "stack". There are Completion |
|
* classes for each kind of action, grouped into single-input |
|
* (UniCompletion), two-input (BiCompletion), projected |
|
* (BiCompletions using either (not both) of two inputs), shared |
|
* (CoCompletion, used by the second of two sources), zero-input |
|
* source actions, and Signallers that unblock waiters. Class |
|
* Completion extends ForkJoinTask to enable async execution |
|
* (adding no space overhead because we exploit its "tag" methods |
|
* to maintain claims). It is also declared as Runnable to allow |
|
* usage with arbitrary executors. |
|
* |
|
* Support for each kind of CompletionStage relies on a separate |
|
* class, along with two CompletableFuture methods: |
|
* |
|
* * A Completion class with name X corresponding to function, |
|
* prefaced with "Uni", "Bi", or "Or". Each class contains |
|
* fields for source(s), actions, and dependent. They are |
|
* boringly similar, differing from others only with respect to |
|
* underlying functional forms. We do this so that users don't |
|
* encounter layers of adaptors in common usages. We also |
|
* include "Relay" classes/methods that don't correspond to user |
|
* methods; they copy results from one stage to another. |
|
* |
|
* * Boolean CompletableFuture method x(...) (for example |
|
* uniApply) takes all of the arguments needed to check that an |
|
* action is triggerable, and then either runs the action or |
|
* arranges its async execution by executing its Completion |
|
* argument, if present. The method returns true if known to be |
|
* complete. |
|
* |
|
* * Completion method tryFire(int mode) invokes the associated x |
|
* method with its held arguments, and on success cleans up. |
|
* The mode argument allows tryFire to be called twice (SYNC, |
|
* then ASYNC); the first to screen and trap exceptions while |
|
* arranging to execute, and the second when called from a |
|
* task. (A few classes are not used async so take slightly |
|
* different forms.) The claim() callback suppresses function |
|
* invocation if already claimed by another thread. |
|
* |
|
* * CompletableFuture method xStage(...) is called from a public |
|
* stage method of CompletableFuture x. It screens user |
|
* arguments and invokes and/or creates the stage object. If |
|
* not async and x is already complete, the action is run |
|
* immediately. Otherwise a Completion c is created, pushed to |
|
* x's stack (unless done), and started or triggered via |
|
* c.tryFire. This also covers races possible if x completes |
|
* while pushing. Classes with two inputs (for example BiApply) |
|
* deal with races across both while pushing actions. The |
|
* second completion is a CoCompletion pointing to the first, |
|
* shared so that at most one performs the action. The |
|
* multiple-arity methods allOf and anyOf do this pairwise to |
|
* form trees of completions. |
|
* |
|
* Note that the generic type parameters of methods vary according |
|
* to whether "this" is a source, dependent, or completion. |
|
* |
|
* Method postComplete is called upon completion unless the target |
|
* is guaranteed not to be observable (i.e., not yet returned or |
|
* linked). Multiple threads can call postComplete, which |
|
* atomically pops each dependent action, and tries to trigger it |
|
* via method tryFire, in NESTED mode. Triggering can propagate |
|
* recursively, so NESTED mode returns its completed dependent (if |
|
* one exists) for further processing by its caller (see method |
|
* postFire). |
|
* |
|
* Blocking methods get() and join() rely on Signaller Completions |
|
* that wake up waiting threads. The mechanics are similar to |
|
* Treiber stack wait-nodes used in FutureTask, Phaser, and |
|
* SynchronousQueue. See their internal documentation for |
|
* algorithmic details. |
|
* |
|
* Without precautions, CompletableFutures would be prone to |
|
* garbage accumulation as chains of Completions build up, each |
|
* pointing back to its sources. So we null out fields as soon as |
|
* possible (see especially method Completion.detach). The |
|
* screening checks needed anyway harmlessly ignore null arguments |
|
* that may have been obtained during races with threads nulling |
|
* out fields. We also try to unlink fired Completions from |
|
* stacks that might never be popped (see method postFire). |
|
* Completion fields need not be declared as final or volatile |
|
* because they are only visible to other threads upon safe |
|
* publication. |
|
*/ |
|
|
|
volatile Object result; |
|
volatile Completion stack; |
|
|
|
final boolean internalComplete(Object r) { |
|
return UNSAFE.compareAndSwapObject(this, RESULT, null, r); |
|
} |
|
|
|
final boolean casStack(Completion cmp, Completion val) { |
|
return UNSAFE.compareAndSwapObject(this, STACK, cmp, val); |
|
} |
|
|
|
|
|
final boolean tryPushStack(Completion c) { |
|
Completion h = stack; |
|
lazySetNext(c, h); |
|
return UNSAFE.compareAndSwapObject(this, STACK, h, c); |
|
} |
|
|
|
|
|
final void pushStack(Completion c) { |
|
do {} while (!tryPushStack(c)); |
|
} |
|
|
|
/* ------------- Encoding and decoding outcomes -------------- */ |
|
|
|
static final class AltResult { |
|
final Throwable ex; |
|
AltResult(Throwable x) { this.ex = x; } |
|
} |
|
|
|
|
|
static final AltResult NIL = new AltResult(null); |
|
|
|
|
|
final boolean completeNull() { |
|
return UNSAFE.compareAndSwapObject(this, RESULT, null, |
|
NIL); |
|
} |
|
|
|
|
|
final Object encodeValue(T t) { |
|
return (t == null) ? NIL : t; |
|
} |
|
|
|
|
|
final boolean completeValue(T t) { |
|
return UNSAFE.compareAndSwapObject(this, RESULT, null, |
|
(t == null) ? NIL : t); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static AltResult encodeThrowable(Throwable x) { |
|
return new AltResult((x instanceof CompletionException) ? x : |
|
new CompletionException(x)); |
|
} |
|
|
|
|
|
final boolean completeThrowable(Throwable x) { |
|
return UNSAFE.compareAndSwapObject(this, RESULT, null, |
|
encodeThrowable(x)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static Object encodeThrowable(Throwable x, Object r) { |
|
if (!(x instanceof CompletionException)) |
|
x = new CompletionException(x); |
|
else if (r instanceof AltResult && x == ((AltResult)r).ex) |
|
return r; |
|
return new AltResult(x); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final boolean completeThrowable(Throwable x, Object r) { |
|
return UNSAFE.compareAndSwapObject(this, RESULT, null, |
|
encodeThrowable(x, r)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
Object encodeOutcome(T t, Throwable x) { |
|
return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static Object encodeRelay(Object r) { |
|
Throwable x; |
|
return (((r instanceof AltResult) && |
|
(x = ((AltResult)r).ex) != null && |
|
!(x instanceof CompletionException)) ? |
|
new AltResult(new CompletionException(x)) : r); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
final boolean completeRelay(Object r) { |
|
return UNSAFE.compareAndSwapObject(this, RESULT, null, |
|
encodeRelay(r)); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static <T> T reportGet(Object r) |
|
throws InterruptedException, ExecutionException { |
|
if (r == null) |
|
throw new InterruptedException(); |
|
if (r instanceof AltResult) { |
|
Throwable x, cause; |
|
if ((x = ((AltResult)r).ex) == null) |
|
return null; |
|
if (x instanceof CancellationException) |
|
throw (CancellationException)x; |
|
if ((x instanceof CompletionException) && |
|
(cause = x.getCause()) != null) |
|
x = cause; |
|
throw new ExecutionException(x); |
|
} |
|
@SuppressWarnings("unchecked") T t = (T) r; |
|
return t; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static <T> T reportJoin(Object r) { |
|
if (r instanceof AltResult) { |
|
Throwable x; |
|
if ((x = ((AltResult)r).ex) == null) |
|
return null; |
|
if (x instanceof CancellationException) |
|
throw (CancellationException)x; |
|
if (x instanceof CompletionException) |
|
throw (CompletionException)x; |
|
throw new CompletionException(x); |
|
} |
|
@SuppressWarnings("unchecked") T t = (T) r; |
|
return t; |
|
} |
|
|
|
/* ------------- Async task preliminaries -------------- */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static interface AsynchronousCompletionTask { |
|
} |
|
|
|
private static final boolean useCommonPool = |
|
(ForkJoinPool.getCommonPoolParallelism() > 1); |
|
|
|
|
|
|
|
|
|
*/ |
|
private static final Executor asyncPool = useCommonPool ? |
|
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor(); |
|
|
|
|
|
static final class ThreadPerTaskExecutor implements Executor { |
|
public void execute(Runnable r) { new Thread(r).start(); } |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static Executor screenExecutor(Executor e) { |
|
if (!useCommonPool && e == ForkJoinPool.commonPool()) |
|
return asyncPool; |
|
if (e == null) throw new NullPointerException(); |
|
return e; |
|
} |
|
|
|
|
|
static final int SYNC = 0; |
|
static final int ASYNC = 1; |
|
static final int NESTED = -1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ? |
|
1 << 8 : 0); |
|
|
|
/* ------------- Base Completion classes and operations -------------- */ |
|
|
|
@SuppressWarnings("serial") |
|
abstract static class Completion extends ForkJoinTask<Void> |
|
implements Runnable, AsynchronousCompletionTask { |
|
volatile Completion next; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
abstract CompletableFuture<?> tryFire(int mode); |
|
|
|
|
|
abstract boolean isLive(); |
|
|
|
public final void run() { tryFire(ASYNC); } |
|
public final boolean exec() { tryFire(ASYNC); return true; } |
|
public final Void getRawResult() { return null; } |
|
public final void setRawResult(Void v) {} |
|
} |
|
|
|
static void lazySetNext(Completion c, Completion next) { |
|
UNSAFE.putOrderedObject(c, NEXT, next); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
final void postComplete() { |
|
|
|
|
|
|
|
|
|
*/ |
|
CompletableFuture<?> f = this; Completion h; |
|
while ((h = f.stack) != null || |
|
(f != this && (h = (f = this).stack) != null)) { |
|
CompletableFuture<?> d; Completion t; |
|
if (f.casStack(h, t = h.next)) { |
|
if (t != null) { |
|
if (f != this) { |
|
pushStack(h); |
|
continue; |
|
} |
|
h.next = null; |
|
} |
|
f = (d = h.tryFire(NESTED)) == null ? this : d; |
|
} |
|
} |
|
} |
|
|
|
|
|
final void cleanStack() { |
|
for (Completion p = null, q = stack; q != null;) { |
|
Completion s = q.next; |
|
if (q.isLive()) { |
|
p = q; |
|
q = s; |
|
} |
|
else if (p == null) { |
|
casStack(q, s); |
|
q = stack; |
|
} |
|
else { |
|
p.next = s; |
|
if (p.isLive()) |
|
q = s; |
|
else { |
|
p = null; |
|
q = stack; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* ------------- One-input Completions -------------- */ |
|
|
|
|
|
@SuppressWarnings("serial") |
|
abstract static class UniCompletion<T,V> extends Completion { |
|
Executor executor; |
|
CompletableFuture<V> dep; |
|
CompletableFuture<T> src; |
|
|
|
UniCompletion(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src) { |
|
this.executor = executor; this.dep = dep; this.src = src; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final boolean claim() { |
|
Executor e = executor; |
|
if (compareAndSetForkJoinTaskTag((short)0, (short)1)) { |
|
if (e == null) |
|
return true; |
|
executor = null; |
|
e.execute(this); |
|
} |
|
return false; |
|
} |
|
|
|
final boolean isLive() { return dep != null; } |
|
} |
|
|
|
|
|
final void push(UniCompletion<?,?> c) { |
|
if (c != null) { |
|
while (result == null && !tryPushStack(c)) |
|
lazySetNext(c, null); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) { |
|
if (a != null && a.stack != null) { |
|
if (mode < 0 || a.result == null) |
|
a.cleanStack(); |
|
else |
|
a.postComplete(); |
|
} |
|
if (result != null && stack != null) { |
|
if (mode < 0) |
|
return this; |
|
else |
|
postComplete(); |
|
} |
|
return null; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniApply<T,V> extends UniCompletion<T,V> { |
|
Function<? super T,? extends V> fn; |
|
UniApply(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src, |
|
Function<? super T,? extends V> fn) { |
|
super(executor, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<V> tryFire(int mode) { |
|
CompletableFuture<V> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || |
|
!d.uniApply(a = src, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final <S> boolean uniApply(CompletableFuture<S> a, |
|
Function<? super S,? extends T> f, |
|
UniApply<S,T> c) { |
|
Object r; Throwable x; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
@SuppressWarnings("unchecked") S s = (S) r; |
|
completeValue(f.apply(s)); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <V> CompletableFuture<V> uniApplyStage( |
|
Executor e, Function<? super T,? extends V> f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<V> d = new CompletableFuture<V>(); |
|
if (e != null || !d.uniApply(this, f, null)) { |
|
UniApply<T,V> c = new UniApply<T,V>(e, d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniAccept<T> extends UniCompletion<T,Void> { |
|
Consumer<? super T> fn; |
|
UniAccept(Executor executor, CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, Consumer<? super T> fn) { |
|
super(executor, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || |
|
!d.uniAccept(a = src, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final <S> boolean uniAccept(CompletableFuture<S> a, |
|
Consumer<? super S> f, UniAccept<S> c) { |
|
Object r; Throwable x; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
@SuppressWarnings("unchecked") S s = (S) r; |
|
f.accept(s); |
|
completeNull(); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private CompletableFuture<Void> uniAcceptStage(Executor e, |
|
Consumer<? super T> f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (e != null || !d.uniAccept(this, f, null)) { |
|
UniAccept<T> c = new UniAccept<T>(e, d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniRun<T> extends UniCompletion<T,Void> { |
|
Runnable fn; |
|
UniRun(Executor executor, CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, Runnable fn) { |
|
super(executor, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || |
|
!d.uniRun(a = src, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) { |
|
Object r; Throwable x; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
if (result == null) { |
|
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) |
|
completeThrowable(x, r); |
|
else |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
f.run(); |
|
completeNull(); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (e != null || !d.uniRun(this, f, null)) { |
|
UniRun<T> c = new UniRun<T>(e, d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniWhenComplete<T> extends UniCompletion<T,T> { |
|
BiConsumer<? super T, ? super Throwable> fn; |
|
UniWhenComplete(Executor executor, CompletableFuture<T> dep, |
|
CompletableFuture<T> src, |
|
BiConsumer<? super T, ? super Throwable> fn) { |
|
super(executor, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<T> tryFire(int mode) { |
|
CompletableFuture<T> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || |
|
!d.uniWhenComplete(a = src, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final boolean uniWhenComplete(CompletableFuture<T> a, |
|
BiConsumer<? super T,? super Throwable> f, |
|
UniWhenComplete<T> c) { |
|
Object r; T t; Throwable x = null; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
if (result == null) { |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
if (r instanceof AltResult) { |
|
x = ((AltResult)r).ex; |
|
t = null; |
|
} else { |
|
@SuppressWarnings("unchecked") T tr = (T) r; |
|
t = tr; |
|
} |
|
f.accept(t, x); |
|
if (x == null) { |
|
internalComplete(r); |
|
return true; |
|
} |
|
} catch (Throwable ex) { |
|
if (x == null) |
|
x = ex; |
|
} |
|
completeThrowable(x, r); |
|
} |
|
return true; |
|
} |
|
|
|
private CompletableFuture<T> uniWhenCompleteStage( |
|
Executor e, BiConsumer<? super T, ? super Throwable> f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<T> d = new CompletableFuture<T>(); |
|
if (e != null || !d.uniWhenComplete(this, f, null)) { |
|
UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniHandle<T,V> extends UniCompletion<T,V> { |
|
BiFunction<? super T, Throwable, ? extends V> fn; |
|
UniHandle(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src, |
|
BiFunction<? super T, Throwable, ? extends V> fn) { |
|
super(executor, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<V> tryFire(int mode) { |
|
CompletableFuture<V> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || |
|
!d.uniHandle(a = src, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final <S> boolean uniHandle(CompletableFuture<S> a, |
|
BiFunction<? super S, Throwable, ? extends T> f, |
|
UniHandle<S,T> c) { |
|
Object r; S s; Throwable x; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
if (result == null) { |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
if (r instanceof AltResult) { |
|
x = ((AltResult)r).ex; |
|
s = null; |
|
} else { |
|
x = null; |
|
@SuppressWarnings("unchecked") S ss = (S) r; |
|
s = ss; |
|
} |
|
completeValue(f.apply(s, x)); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <V> CompletableFuture<V> uniHandleStage( |
|
Executor e, BiFunction<? super T, Throwable, ? extends V> f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<V> d = new CompletableFuture<V>(); |
|
if (e != null || !d.uniHandle(this, f, null)) { |
|
UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniExceptionally<T> extends UniCompletion<T,T> { |
|
Function<? super Throwable, ? extends T> fn; |
|
UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src, |
|
Function<? super Throwable, ? extends T> fn) { |
|
super(null, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<T> tryFire(int mode) { // never ASYNC |
|
|
|
CompletableFuture<T> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final boolean uniExceptionally(CompletableFuture<T> a, |
|
Function<? super Throwable, ? extends T> f, |
|
UniExceptionally<T> c) { |
|
Object r; Throwable x; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
if (result == null) { |
|
try { |
|
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) { |
|
if (c != null && !c.claim()) |
|
return false; |
|
completeValue(f.apply(x)); |
|
} else |
|
internalComplete(r); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private CompletableFuture<T> uniExceptionallyStage( |
|
Function<Throwable, ? extends T> f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<T> d = new CompletableFuture<T>(); |
|
if (!d.uniExceptionally(this, f, null)) { |
|
UniExceptionally<T> c = new UniExceptionally<T>(d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniRelay<T> extends UniCompletion<T,T> { |
|
UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) { |
|
super(null, dep, src); |
|
} |
|
final CompletableFuture<T> tryFire(int mode) { |
|
CompletableFuture<T> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || !d.uniRelay(a = src)) |
|
return null; |
|
src = null; dep = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final boolean uniRelay(CompletableFuture<T> a) { |
|
Object r; |
|
if (a == null || (r = a.result) == null) |
|
return false; |
|
if (result == null) |
|
completeRelay(r); |
|
return true; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class UniCompose<T,V> extends UniCompletion<T,V> { |
|
Function<? super T, ? extends CompletionStage<V>> fn; |
|
UniCompose(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src, |
|
Function<? super T, ? extends CompletionStage<V>> fn) { |
|
super(executor, dep, src); this.fn = fn; |
|
} |
|
final CompletableFuture<V> tryFire(int mode) { |
|
CompletableFuture<V> d; CompletableFuture<T> a; |
|
if ((d = dep) == null || |
|
!d.uniCompose(a = src, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; fn = null; |
|
return d.postFire(a, mode); |
|
} |
|
} |
|
|
|
final <S> boolean uniCompose( |
|
CompletableFuture<S> a, |
|
Function<? super S, ? extends CompletionStage<T>> f, |
|
UniCompose<S,T> c) { |
|
Object r; Throwable x; |
|
if (a == null || (r = a.result) == null || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
@SuppressWarnings("unchecked") S s = (S) r; |
|
CompletableFuture<T> g = f.apply(s).toCompletableFuture(); |
|
if (g.result == null || !uniRelay(g)) { |
|
UniRelay<T> copy = new UniRelay<T>(this, g); |
|
g.push(copy); |
|
copy.tryFire(SYNC); |
|
if (result == null) |
|
return false; |
|
} |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <V> CompletableFuture<V> uniComposeStage( |
|
Executor e, Function<? super T, ? extends CompletionStage<V>> f) { |
|
if (f == null) throw new NullPointerException(); |
|
Object r; Throwable x; |
|
if (e == null && (r = result) != null) { |
|
|
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
return new CompletableFuture<V>(encodeThrowable(x, r)); |
|
} |
|
r = null; |
|
} |
|
try { |
|
@SuppressWarnings("unchecked") T t = (T) r; |
|
CompletableFuture<V> g = f.apply(t).toCompletableFuture(); |
|
Object s = g.result; |
|
if (s != null) |
|
return new CompletableFuture<V>(encodeRelay(s)); |
|
CompletableFuture<V> d = new CompletableFuture<V>(); |
|
UniRelay<V> copy = new UniRelay<V>(d, g); |
|
g.push(copy); |
|
copy.tryFire(SYNC); |
|
return d; |
|
} catch (Throwable ex) { |
|
return new CompletableFuture<V>(encodeThrowable(ex)); |
|
} |
|
} |
|
CompletableFuture<V> d = new CompletableFuture<V>(); |
|
UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f); |
|
push(c); |
|
c.tryFire(SYNC); |
|
return d; |
|
} |
|
|
|
/* ------------- Two-input Completions -------------- */ |
|
|
|
|
|
@SuppressWarnings("serial") |
|
abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> { |
|
CompletableFuture<U> snd; |
|
BiCompletion(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src, CompletableFuture<U> snd) { |
|
super(executor, dep, src); this.snd = snd; |
|
} |
|
} |
|
|
|
|
|
@SuppressWarnings("serial") |
|
static final class CoCompletion extends Completion { |
|
BiCompletion<?,?,?> base; |
|
CoCompletion(BiCompletion<?,?,?> base) { this.base = base; } |
|
final CompletableFuture<?> tryFire(int mode) { |
|
BiCompletion<?,?,?> c; CompletableFuture<?> d; |
|
if ((c = base) == null || (d = c.tryFire(mode)) == null) |
|
return null; |
|
base = null; |
|
return d; |
|
} |
|
final boolean isLive() { |
|
BiCompletion<?,?,?> c; |
|
return (c = base) != null && c.dep != null; |
|
} |
|
} |
|
|
|
|
|
final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) { |
|
if (c != null) { |
|
Object r; |
|
while ((r = result) == null && !tryPushStack(c)) |
|
lazySetNext(c, null); |
|
if (b != null && b != this && b.result == null) { |
|
Completion q = (r != null) ? c : new CoCompletion(c); |
|
while (b.result == null && !b.tryPushStack(q)) |
|
lazySetNext(q, null); |
|
} |
|
} |
|
} |
|
|
|
|
|
final CompletableFuture<T> postFire(CompletableFuture<?> a, |
|
CompletableFuture<?> b, int mode) { |
|
if (b != null && b.stack != null) { |
|
if (mode < 0 || b.result == null) |
|
b.cleanStack(); |
|
else |
|
b.postComplete(); |
|
} |
|
return postFire(a, mode); |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class BiApply<T,U,V> extends BiCompletion<T,U,V> { |
|
BiFunction<? super T,? super U,? extends V> fn; |
|
BiApply(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src, CompletableFuture<U> snd, |
|
BiFunction<? super T,? super U,? extends V> fn) { |
|
super(executor, dep, src, snd); this.fn = fn; |
|
} |
|
final CompletableFuture<V> tryFire(int mode) { |
|
CompletableFuture<V> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || |
|
!d.biApply(a = src, b = snd, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; snd = null; fn = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final <R,S> boolean biApply(CompletableFuture<R> a, |
|
CompletableFuture<S> b, |
|
BiFunction<? super R,? super S,? extends T> f, |
|
BiApply<R,S,T> c) { |
|
Object r, s; Throwable x; |
|
if (a == null || (r = a.result) == null || |
|
b == null || (s = b.result) == null || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
if (s instanceof AltResult) { |
|
if ((x = ((AltResult)s).ex) != null) { |
|
completeThrowable(x, s); |
|
break tryComplete; |
|
} |
|
s = null; |
|
} |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
@SuppressWarnings("unchecked") R rr = (R) r; |
|
@SuppressWarnings("unchecked") S ss = (S) s; |
|
completeValue(f.apply(rr, ss)); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <U,V> CompletableFuture<V> biApplyStage( |
|
Executor e, CompletionStage<U> o, |
|
BiFunction<? super T,? super U,? extends V> f) { |
|
CompletableFuture<U> b; |
|
if (f == null || (b = o.toCompletableFuture()) == null) |
|
throw new NullPointerException(); |
|
CompletableFuture<V> d = new CompletableFuture<V>(); |
|
if (e != null || !d.biApply(this, b, f, null)) { |
|
BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f); |
|
bipush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class BiAccept<T,U> extends BiCompletion<T,U,Void> { |
|
BiConsumer<? super T,? super U> fn; |
|
BiAccept(Executor executor, CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, CompletableFuture<U> snd, |
|
BiConsumer<? super T,? super U> fn) { |
|
super(executor, dep, src, snd); this.fn = fn; |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || |
|
!d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; snd = null; fn = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final <R,S> boolean biAccept(CompletableFuture<R> a, |
|
CompletableFuture<S> b, |
|
BiConsumer<? super R,? super S> f, |
|
BiAccept<R,S> c) { |
|
Object r, s; Throwable x; |
|
if (a == null || (r = a.result) == null || |
|
b == null || (s = b.result) == null || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
if (s instanceof AltResult) { |
|
if ((x = ((AltResult)s).ex) != null) { |
|
completeThrowable(x, s); |
|
break tryComplete; |
|
} |
|
s = null; |
|
} |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
@SuppressWarnings("unchecked") R rr = (R) r; |
|
@SuppressWarnings("unchecked") S ss = (S) s; |
|
f.accept(rr, ss); |
|
completeNull(); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <U> CompletableFuture<Void> biAcceptStage( |
|
Executor e, CompletionStage<U> o, |
|
BiConsumer<? super T,? super U> f) { |
|
CompletableFuture<U> b; |
|
if (f == null || (b = o.toCompletableFuture()) == null) |
|
throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (e != null || !d.biAccept(this, b, f, null)) { |
|
BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f); |
|
bipush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class BiRun<T,U> extends BiCompletion<T,U,Void> { |
|
Runnable fn; |
|
BiRun(Executor executor, CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, |
|
CompletableFuture<U> snd, |
|
Runnable fn) { |
|
super(executor, dep, src, snd); this.fn = fn; |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || |
|
!d.biRun(a = src, b = snd, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; snd = null; fn = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b, |
|
Runnable f, BiRun<?,?> c) { |
|
Object r, s; Throwable x; |
|
if (a == null || (r = a.result) == null || |
|
b == null || (s = b.result) == null || f == null) |
|
return false; |
|
if (result == null) { |
|
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) |
|
completeThrowable(x, r); |
|
else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null) |
|
completeThrowable(x, s); |
|
else |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
f.run(); |
|
completeNull(); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o, |
|
Runnable f) { |
|
CompletableFuture<?> b; |
|
if (f == null || (b = o.toCompletableFuture()) == null) |
|
throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (e != null || !d.biRun(this, b, f, null)) { |
|
BiRun<T,?> c = new BiRun<>(e, d, this, b, f); |
|
bipush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { |
|
BiRelay(CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, |
|
CompletableFuture<U> snd) { |
|
super(null, dep, src, snd); |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || !d.biRelay(a = src, b = snd)) |
|
return null; |
|
src = null; snd = null; dep = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) { |
|
Object r, s; Throwable x; |
|
if (a == null || (r = a.result) == null || |
|
b == null || (s = b.result) == null) |
|
return false; |
|
if (result == null) { |
|
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) |
|
completeThrowable(x, r); |
|
else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null) |
|
completeThrowable(x, s); |
|
else |
|
completeNull(); |
|
} |
|
return true; |
|
} |
|
|
|
|
|
static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs, |
|
int lo, int hi) { |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (lo > hi) |
|
d.result = NIL; |
|
else { |
|
CompletableFuture<?> a, b; |
|
int mid = (lo + hi) >>> 1; |
|
if ((a = (lo == mid ? cfs[lo] : |
|
andTree(cfs, lo, mid))) == null || |
|
(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] : |
|
andTree(cfs, mid+1, hi))) == null) |
|
throw new NullPointerException(); |
|
if (!d.biRelay(a, b)) { |
|
BiRelay<?,?> c = new BiRelay<>(d, a, b); |
|
a.bipush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
} |
|
return d; |
|
} |
|
|
|
/* ------------- Projected (Ored) BiCompletions -------------- */ |
|
|
|
|
|
final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) { |
|
if (c != null) { |
|
while ((b == null || b.result == null) && result == null) { |
|
if (tryPushStack(c)) { |
|
if (b != null && b != this && b.result == null) { |
|
Completion q = new CoCompletion(c); |
|
while (result == null && b.result == null && |
|
!b.tryPushStack(q)) |
|
lazySetNext(q, null); |
|
} |
|
break; |
|
} |
|
lazySetNext(c, null); |
|
} |
|
} |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> { |
|
Function<? super T,? extends V> fn; |
|
OrApply(Executor executor, CompletableFuture<V> dep, |
|
CompletableFuture<T> src, |
|
CompletableFuture<U> snd, |
|
Function<? super T,? extends V> fn) { |
|
super(executor, dep, src, snd); this.fn = fn; |
|
} |
|
final CompletableFuture<V> tryFire(int mode) { |
|
CompletableFuture<V> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || |
|
!d.orApply(a = src, b = snd, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; snd = null; fn = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final <R,S extends R> boolean orApply(CompletableFuture<R> a, |
|
CompletableFuture<S> b, |
|
Function<? super R, ? extends T> f, |
|
OrApply<R,S,T> c) { |
|
Object r; Throwable x; |
|
if (a == null || b == null || |
|
((r = a.result) == null && (r = b.result) == null) || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
@SuppressWarnings("unchecked") R rr = (R) r; |
|
completeValue(f.apply(rr)); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <U extends T,V> CompletableFuture<V> orApplyStage( |
|
Executor e, CompletionStage<U> o, |
|
Function<? super T, ? extends V> f) { |
|
CompletableFuture<U> b; |
|
if (f == null || (b = o.toCompletableFuture()) == null) |
|
throw new NullPointerException(); |
|
CompletableFuture<V> d = new CompletableFuture<V>(); |
|
if (e != null || !d.orApply(this, b, f, null)) { |
|
OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f); |
|
orpush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> { |
|
Consumer<? super T> fn; |
|
OrAccept(Executor executor, CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, |
|
CompletableFuture<U> snd, |
|
Consumer<? super T> fn) { |
|
super(executor, dep, src, snd); this.fn = fn; |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || |
|
!d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; snd = null; fn = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final <R,S extends R> boolean orAccept(CompletableFuture<R> a, |
|
CompletableFuture<S> b, |
|
Consumer<? super R> f, |
|
OrAccept<R,S> c) { |
|
Object r; Throwable x; |
|
if (a == null || b == null || |
|
((r = a.result) == null && (r = b.result) == null) || f == null) |
|
return false; |
|
tryComplete: if (result == null) { |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
if (r instanceof AltResult) { |
|
if ((x = ((AltResult)r).ex) != null) { |
|
completeThrowable(x, r); |
|
break tryComplete; |
|
} |
|
r = null; |
|
} |
|
@SuppressWarnings("unchecked") R rr = (R) r; |
|
f.accept(rr); |
|
completeNull(); |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private <U extends T> CompletableFuture<Void> orAcceptStage( |
|
Executor e, CompletionStage<U> o, Consumer<? super T> f) { |
|
CompletableFuture<U> b; |
|
if (f == null || (b = o.toCompletableFuture()) == null) |
|
throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (e != null || !d.orAccept(this, b, f, null)) { |
|
OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f); |
|
orpush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class OrRun<T,U> extends BiCompletion<T,U,Void> { |
|
Runnable fn; |
|
OrRun(Executor executor, CompletableFuture<Void> dep, |
|
CompletableFuture<T> src, |
|
CompletableFuture<U> snd, |
|
Runnable fn) { |
|
super(executor, dep, src, snd); this.fn = fn; |
|
} |
|
final CompletableFuture<Void> tryFire(int mode) { |
|
CompletableFuture<Void> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || |
|
!d.orRun(a = src, b = snd, fn, mode > 0 ? null : this)) |
|
return null; |
|
dep = null; src = null; snd = null; fn = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b, |
|
Runnable f, OrRun<?,?> c) { |
|
Object r; Throwable x; |
|
if (a == null || b == null || |
|
((r = a.result) == null && (r = b.result) == null) || f == null) |
|
return false; |
|
if (result == null) { |
|
try { |
|
if (c != null && !c.claim()) |
|
return false; |
|
if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) |
|
completeThrowable(x, r); |
|
else { |
|
f.run(); |
|
completeNull(); |
|
} |
|
} catch (Throwable ex) { |
|
completeThrowable(ex); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o, |
|
Runnable f) { |
|
CompletableFuture<?> b; |
|
if (f == null || (b = o.toCompletableFuture()) == null) |
|
throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
if (e != null || !d.orRun(this, b, f, null)) { |
|
OrRun<T,?> c = new OrRun<>(e, d, this, b, f); |
|
orpush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { |
|
OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src, |
|
CompletableFuture<U> snd) { |
|
super(null, dep, src, snd); |
|
} |
|
final CompletableFuture<Object> tryFire(int mode) { |
|
CompletableFuture<Object> d; |
|
CompletableFuture<T> a; |
|
CompletableFuture<U> b; |
|
if ((d = dep) == null || !d.orRelay(a = src, b = snd)) |
|
return null; |
|
src = null; snd = null; dep = null; |
|
return d.postFire(a, b, mode); |
|
} |
|
} |
|
|
|
final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) { |
|
Object r; |
|
if (a == null || b == null || |
|
((r = a.result) == null && (r = b.result) == null)) |
|
return false; |
|
if (result == null) |
|
completeRelay(r); |
|
return true; |
|
} |
|
|
|
|
|
static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs, |
|
int lo, int hi) { |
|
CompletableFuture<Object> d = new CompletableFuture<Object>(); |
|
if (lo <= hi) { |
|
CompletableFuture<?> a, b; |
|
int mid = (lo + hi) >>> 1; |
|
if ((a = (lo == mid ? cfs[lo] : |
|
orTree(cfs, lo, mid))) == null || |
|
(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] : |
|
orTree(cfs, mid+1, hi))) == null) |
|
throw new NullPointerException(); |
|
if (!d.orRelay(a, b)) { |
|
OrRelay<?,?> c = new OrRelay<>(d, a, b); |
|
a.orpush(b, c); |
|
c.tryFire(SYNC); |
|
} |
|
} |
|
return d; |
|
} |
|
|
|
/* ------------- Zero-input Async forms -------------- */ |
|
|
|
@SuppressWarnings("serial") |
|
static final class AsyncSupply<T> extends ForkJoinTask<Void> |
|
implements Runnable, AsynchronousCompletionTask { |
|
CompletableFuture<T> dep; Supplier<T> fn; |
|
AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) { |
|
this.dep = dep; this.fn = fn; |
|
} |
|
|
|
public final Void getRawResult() { return null; } |
|
public final void setRawResult(Void v) {} |
|
public final boolean exec() { run(); return true; } |
|
|
|
public void run() { |
|
CompletableFuture<T> d; Supplier<T> f; |
|
if ((d = dep) != null && (f = fn) != null) { |
|
dep = null; fn = null; |
|
if (d.result == null) { |
|
try { |
|
d.completeValue(f.get()); |
|
} catch (Throwable ex) { |
|
d.completeThrowable(ex); |
|
} |
|
} |
|
d.postComplete(); |
|
} |
|
} |
|
} |
|
|
|
static <U> CompletableFuture<U> asyncSupplyStage(Executor e, |
|
Supplier<U> f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<U> d = new CompletableFuture<U>(); |
|
e.execute(new AsyncSupply<U>(d, f)); |
|
return d; |
|
} |
|
|
|
@SuppressWarnings("serial") |
|
static final class AsyncRun extends ForkJoinTask<Void> |
|
implements Runnable, AsynchronousCompletionTask { |
|
CompletableFuture<Void> dep; Runnable fn; |
|
AsyncRun(CompletableFuture<Void> dep, Runnable fn) { |
|
this.dep = dep; this.fn = fn; |
|
} |
|
|
|
public final Void getRawResult() { return null; } |
|
public final void setRawResult(Void v) {} |
|
public final boolean exec() { run(); return true; } |
|
|
|
public void run() { |
|
CompletableFuture<Void> d; Runnable f; |
|
if ((d = dep) != null && (f = fn) != null) { |
|
dep = null; fn = null; |
|
if (d.result == null) { |
|
try { |
|
f.run(); |
|
d.completeNull(); |
|
} catch (Throwable ex) { |
|
d.completeThrowable(ex); |
|
} |
|
} |
|
d.postComplete(); |
|
} |
|
} |
|
} |
|
|
|
static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) { |
|
if (f == null) throw new NullPointerException(); |
|
CompletableFuture<Void> d = new CompletableFuture<Void>(); |
|
e.execute(new AsyncRun(d, f)); |
|
return d; |
|
} |
|
|
|
/* ------------- Signallers -------------- */ |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("serial") |
|
static final class Signaller extends Completion |
|
implements ForkJoinPool.ManagedBlocker { |
|
long nanos; |
|
final long deadline; |
|
volatile int interruptControl; |
|
volatile Thread thread; |
|
|
|
Signaller(boolean interruptible, long nanos, long deadline) { |
|
this.thread = Thread.currentThread(); |
|
this.interruptControl = interruptible ? 1 : 0; |
|
this.nanos = nanos; |
|
this.deadline = deadline; |
|
} |
|
final CompletableFuture<?> tryFire(int ignore) { |
|
Thread w; |
|
if ((w = thread) != null) { |
|
thread = null; |
|
LockSupport.unpark(w); |
|
} |
|
return null; |
|
} |
|
public boolean isReleasable() { |
|
if (thread == null) |
|
return true; |
|
if (Thread.interrupted()) { |
|
int i = interruptControl; |
|
interruptControl = -1; |
|
if (i > 0) |
|
return true; |
|
} |
|
if (deadline != 0L && |
|
(nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) { |
|
thread = null; |
|
return true; |
|
} |
|
return false; |
|
} |
|
public boolean block() { |
|
if (isReleasable()) |
|
return true; |
|
else if (deadline == 0L) |
|
LockSupport.park(this); |
|
else if (nanos > 0L) |
|
LockSupport.parkNanos(this, nanos); |
|
return isReleasable(); |
|
} |
|
final boolean isLive() { return thread != null; } |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private Object waitingGet(boolean interruptible) { |
|
Signaller q = null; |
|
boolean queued = false; |
|
int spins = -1; |
|
Object r; |
|
while ((r = result) == null) { |
|
if (spins < 0) |
|
spins = SPINS; |
|
else if (spins > 0) { |
|
if (ThreadLocalRandom.nextSecondarySeed() >= 0) |
|
--spins; |
|
} |
|
else if (q == null) |
|
q = new Signaller(interruptible, 0L, 0L); |
|
else if (!queued) |
|
queued = tryPushStack(q); |
|
else if (interruptible && q.interruptControl < 0) { |
|
q.thread = null; |
|
cleanStack(); |
|
return null; |
|
} |
|
else if (q.thread != null && result == null) { |
|
try { |
|
ForkJoinPool.managedBlock(q); |
|
} catch (InterruptedException ie) { |
|
q.interruptControl = -1; |
|
} |
|
} |
|
} |
|
if (q != null) { |
|
q.thread = null; |
|
if (q.interruptControl < 0) { |
|
if (interruptible) |
|
r = null; |
|
else |
|
Thread.currentThread().interrupt(); |
|
} |
|
} |
|
postComplete(); |
|
return r; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private Object timedGet(long nanos) throws TimeoutException { |
|
if (Thread.interrupted()) |
|
return null; |
|
if (nanos <= 0L) |
|
throw new TimeoutException(); |
|
long d = System.nanoTime() + nanos; |
|
Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); |
|
boolean queued = false; |
|
Object r; |
|
// We intentionally don't spin here (as waitingGet does) because |
|
|
|
while ((r = result) == null) { |
|
if (!queued) |
|
queued = tryPushStack(q); |
|
else if (q.interruptControl < 0 || q.nanos <= 0L) { |
|
q.thread = null; |
|
cleanStack(); |
|
if (q.interruptControl < 0) |
|
return null; |
|
throw new TimeoutException(); |
|
} |
|
else if (q.thread != null && result == null) { |
|
try { |
|
ForkJoinPool.managedBlock(q); |
|
} catch (InterruptedException ie) { |
|
q.interruptControl = -1; |
|
} |
|
} |
|
} |
|
if (q.interruptControl < 0) |
|
r = null; |
|
q.thread = null; |
|
postComplete(); |
|
return r; |
|
} |
|
|
|
/* ------------- public methods -------------- */ |
|
|
|
|
|
|
|
*/ |
|
public CompletableFuture() { |
|
} |
|
|
|
|
|
|
|
*/ |
|
private CompletableFuture(Object r) { |
|
this.result = r; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) { |
|
return asyncSupplyStage(asyncPool, supplier); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, |
|
Executor executor) { |
|
return asyncSupplyStage(screenExecutor(executor), supplier); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static CompletableFuture<Void> runAsync(Runnable runnable) { |
|
return asyncRunStage(asyncPool, runnable); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static CompletableFuture<Void> runAsync(Runnable runnable, |
|
Executor executor) { |
|
return asyncRunStage(screenExecutor(executor), runnable); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static <U> CompletableFuture<U> completedFuture(U value) { |
|
return new CompletableFuture<U>((value == null) ? NIL : value); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isDone() { |
|
return result != null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public T get() throws InterruptedException, ExecutionException { |
|
Object r; |
|
return reportGet((r = result) == null ? waitingGet(true) : r); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public T get(long timeout, TimeUnit unit) |
|
throws InterruptedException, ExecutionException, TimeoutException { |
|
Object r; |
|
long nanos = unit.toNanos(timeout); |
|
return reportGet((r = result) == null ? timedGet(nanos) : r); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public T join() { |
|
Object r; |
|
return reportJoin((r = result) == null ? waitingGet(false) : r); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public T getNow(T valueIfAbsent) { |
|
Object r; |
|
return ((r = result) == null) ? valueIfAbsent : reportJoin(r); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean complete(T value) { |
|
boolean triggered = completeValue(value); |
|
postComplete(); |
|
return triggered; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean completeExceptionally(Throwable ex) { |
|
if (ex == null) throw new NullPointerException(); |
|
boolean triggered = internalComplete(new AltResult(ex)); |
|
postComplete(); |
|
return triggered; |
|
} |
|
|
|
public <U> CompletableFuture<U> thenApply( |
|
Function<? super T,? extends U> fn) { |
|
return uniApplyStage(null, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> thenApplyAsync( |
|
Function<? super T,? extends U> fn) { |
|
return uniApplyStage(asyncPool, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> thenApplyAsync( |
|
Function<? super T,? extends U> fn, Executor executor) { |
|
return uniApplyStage(screenExecutor(executor), fn); |
|
} |
|
|
|
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) { |
|
return uniAcceptStage(null, action); |
|
} |
|
|
|
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) { |
|
return uniAcceptStage(asyncPool, action); |
|
} |
|
|
|
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, |
|
Executor executor) { |
|
return uniAcceptStage(screenExecutor(executor), action); |
|
} |
|
|
|
public CompletableFuture<Void> thenRun(Runnable action) { |
|
return uniRunStage(null, action); |
|
} |
|
|
|
public CompletableFuture<Void> thenRunAsync(Runnable action) { |
|
return uniRunStage(asyncPool, action); |
|
} |
|
|
|
public CompletableFuture<Void> thenRunAsync(Runnable action, |
|
Executor executor) { |
|
return uniRunStage(screenExecutor(executor), action); |
|
} |
|
|
|
public <U,V> CompletableFuture<V> thenCombine( |
|
CompletionStage<? extends U> other, |
|
BiFunction<? super T,? super U,? extends V> fn) { |
|
return biApplyStage(null, other, fn); |
|
} |
|
|
|
public <U,V> CompletableFuture<V> thenCombineAsync( |
|
CompletionStage<? extends U> other, |
|
BiFunction<? super T,? super U,? extends V> fn) { |
|
return biApplyStage(asyncPool, other, fn); |
|
} |
|
|
|
public <U,V> CompletableFuture<V> thenCombineAsync( |
|
CompletionStage<? extends U> other, |
|
BiFunction<? super T,? super U,? extends V> fn, Executor executor) { |
|
return biApplyStage(screenExecutor(executor), other, fn); |
|
} |
|
|
|
public <U> CompletableFuture<Void> thenAcceptBoth( |
|
CompletionStage<? extends U> other, |
|
BiConsumer<? super T, ? super U> action) { |
|
return biAcceptStage(null, other, action); |
|
} |
|
|
|
public <U> CompletableFuture<Void> thenAcceptBothAsync( |
|
CompletionStage<? extends U> other, |
|
BiConsumer<? super T, ? super U> action) { |
|
return biAcceptStage(asyncPool, other, action); |
|
} |
|
|
|
public <U> CompletableFuture<Void> thenAcceptBothAsync( |
|
CompletionStage<? extends U> other, |
|
BiConsumer<? super T, ? super U> action, Executor executor) { |
|
return biAcceptStage(screenExecutor(executor), other, action); |
|
} |
|
|
|
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, |
|
Runnable action) { |
|
return biRunStage(null, other, action); |
|
} |
|
|
|
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, |
|
Runnable action) { |
|
return biRunStage(asyncPool, other, action); |
|
} |
|
|
|
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, |
|
Runnable action, |
|
Executor executor) { |
|
return biRunStage(screenExecutor(executor), other, action); |
|
} |
|
|
|
public <U> CompletableFuture<U> applyToEither( |
|
CompletionStage<? extends T> other, Function<? super T, U> fn) { |
|
return orApplyStage(null, other, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> applyToEitherAsync( |
|
CompletionStage<? extends T> other, Function<? super T, U> fn) { |
|
return orApplyStage(asyncPool, other, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> applyToEitherAsync( |
|
CompletionStage<? extends T> other, Function<? super T, U> fn, |
|
Executor executor) { |
|
return orApplyStage(screenExecutor(executor), other, fn); |
|
} |
|
|
|
public CompletableFuture<Void> acceptEither( |
|
CompletionStage<? extends T> other, Consumer<? super T> action) { |
|
return orAcceptStage(null, other, action); |
|
} |
|
|
|
public CompletableFuture<Void> acceptEitherAsync( |
|
CompletionStage<? extends T> other, Consumer<? super T> action) { |
|
return orAcceptStage(asyncPool, other, action); |
|
} |
|
|
|
public CompletableFuture<Void> acceptEitherAsync( |
|
CompletionStage<? extends T> other, Consumer<? super T> action, |
|
Executor executor) { |
|
return orAcceptStage(screenExecutor(executor), other, action); |
|
} |
|
|
|
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, |
|
Runnable action) { |
|
return orRunStage(null, other, action); |
|
} |
|
|
|
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, |
|
Runnable action) { |
|
return orRunStage(asyncPool, other, action); |
|
} |
|
|
|
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, |
|
Runnable action, |
|
Executor executor) { |
|
return orRunStage(screenExecutor(executor), other, action); |
|
} |
|
|
|
public <U> CompletableFuture<U> thenCompose( |
|
Function<? super T, ? extends CompletionStage<U>> fn) { |
|
return uniComposeStage(null, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> thenComposeAsync( |
|
Function<? super T, ? extends CompletionStage<U>> fn) { |
|
return uniComposeStage(asyncPool, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> thenComposeAsync( |
|
Function<? super T, ? extends CompletionStage<U>> fn, |
|
Executor executor) { |
|
return uniComposeStage(screenExecutor(executor), fn); |
|
} |
|
|
|
public CompletableFuture<T> whenComplete( |
|
BiConsumer<? super T, ? super Throwable> action) { |
|
return uniWhenCompleteStage(null, action); |
|
} |
|
|
|
public CompletableFuture<T> whenCompleteAsync( |
|
BiConsumer<? super T, ? super Throwable> action) { |
|
return uniWhenCompleteStage(asyncPool, action); |
|
} |
|
|
|
public CompletableFuture<T> whenCompleteAsync( |
|
BiConsumer<? super T, ? super Throwable> action, Executor executor) { |
|
return uniWhenCompleteStage(screenExecutor(executor), action); |
|
} |
|
|
|
public <U> CompletableFuture<U> handle( |
|
BiFunction<? super T, Throwable, ? extends U> fn) { |
|
return uniHandleStage(null, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> handleAsync( |
|
BiFunction<? super T, Throwable, ? extends U> fn) { |
|
return uniHandleStage(asyncPool, fn); |
|
} |
|
|
|
public <U> CompletableFuture<U> handleAsync( |
|
BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) { |
|
return uniHandleStage(screenExecutor(executor), fn); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public CompletableFuture<T> toCompletableFuture() { |
|
return this; |
|
} |
|
|
|
// not in interface CompletionStage |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public CompletableFuture<T> exceptionally( |
|
Function<Throwable, ? extends T> fn) { |
|
return uniExceptionallyStage(fn); |
|
} |
|
|
|
/* ------------- Arbitrary-arity constructions -------------- */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) { |
|
return andTree(cfs, 0, cfs.length - 1); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) { |
|
return orTree(cfs, 0, cfs.length - 1); |
|
} |
|
|
|
/* ------------- Control and status methods -------------- */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean cancel(boolean mayInterruptIfRunning) { |
|
boolean cancelled = (result == null) && |
|
internalComplete(new AltResult(new CancellationException())); |
|
postComplete(); |
|
return cancelled || isCancelled(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isCancelled() { |
|
Object r; |
|
return ((r = result) instanceof AltResult) && |
|
(((AltResult)r).ex instanceof CancellationException); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isCompletedExceptionally() { |
|
Object r; |
|
return ((r = result) instanceof AltResult) && r != NIL; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void obtrudeValue(T value) { |
|
result = (value == null) ? NIL : value; |
|
postComplete(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void obtrudeException(Throwable ex) { |
|
if (ex == null) throw new NullPointerException(); |
|
result = new AltResult(ex); |
|
postComplete(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int getNumberOfDependents() { |
|
int count = 0; |
|
for (Completion p = stack; p != null; p = p.next) |
|
++count; |
|
return count; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public String toString() { |
|
Object r = result; |
|
int count; |
|
return super.toString() + |
|
((r == null) ? |
|
(((count = getNumberOfDependents()) == 0) ? |
|
"[Not completed]" : |
|
"[Not completed, " + count + " dependents]") : |
|
(((r instanceof AltResult) && ((AltResult)r).ex != null) ? |
|
"[Completed exceptionally]" : |
|
"[Completed normally]")); |
|
} |
|
|
|
|
|
private static final sun.misc.Unsafe UNSAFE; |
|
private static final long RESULT; |
|
private static final long STACK; |
|
private static final long NEXT; |
|
static { |
|
try { |
|
final sun.misc.Unsafe u; |
|
UNSAFE = u = sun.misc.Unsafe.getUnsafe(); |
|
Class<?> k = CompletableFuture.class; |
|
RESULT = u.objectFieldOffset(k.getDeclaredField("result")); |
|
STACK = u.objectFieldOffset(k.getDeclaredField("stack")); |
|
NEXT = u.objectFieldOffset |
|
(Completion.class.getDeclaredField("next")); |
|
} catch (Exception x) { |
|
throw new Error(x); |
|
} |
|
} |
|
} |