cuda::experimental::stf::sump::sink#
-
template<class _Reaction>
auto cuda::experimental::stf::sump::sink( - _Reaction &&__reaction,
- const ::cuda::std::source_location __loc = ::cuda::std::source_location::current()
Applies a reaction that is not a sink, or reports a location other than the call site.
A sink is its own carrier: every named policy and every composite accepts the two operators directly, and records the location of the expression that applies it.
sink(reaction, loc)is for the rest: a user-defined policy, a raw hook or value (see below), an explicit location, and a carrier that outlives a statement. Two operators apply a sink:policy ->* xevaluates and yields, for when you want the value. An action runs under the policy, so its throws are handled, and its return comes back verbatim, whatever its type: it is never checked and no trait is consulted, even for a registered status type. The right operand must be a callable; a status value goes to the right of<<.->*never chains.policy << xfeeds, possibly several operands:store(&err) << a() << b(). A status value is offered to the policy as with->*. An action runs under the policy, and what it returns is an error code: a status is fed in turn (a successful one only fixes the chain’s status type),voidfeeds nothing, and a type withoutstatus_traitsis a compile error. The expression is a carrier, which records the chain. A sink applied by name is copied into each expression; the library’s stateful sinks keep their state behind a pointer, so the copies share it. A named non-constdynamicis viewed instead of copied, so one model serves every expression that names it; a custom model with mutable state synchronizes its own concurrent use. To keep one chain across statements, name the carrier:auto s = sink(p); s << a; s << b;. C++17 sequences the left side of<<, its handling included, before the right, so each operand runs after the previous one was handled. The carrier records the first status that was forwarded, read withstatus<S>()(the success value if none was), andforwarded()says whether one was. The first<<fixes the chain’s status type, and a later operand of another status type, orstatus<S>()with anotherS, is a programming error checked with_CCCL_VERIFY. The carrier converts to nothing implicitly, and a<<statement whosestatus<S>()nobody reads drops a forwarded status: write->*to keep it.
Both operators bind tighter than
&and|, so a composite on their left is parenthesized:(notify & abort) << cudaFree(p).->*binds tighter than<<, sos << a ->* bparses ass << (a ->* b)and does not compile; write(s << a).status<S>(), or split the statement.A policy is an object exposing any of two optional capabilities, discovered by compile-time introspection: the exception hook
(const std::exception*, source_location, Fn&)whose return value is its answer on the throw path (the callable may be re-invoked by policies likeretry; most policies ignore it), and a success hookon_success(...)that observes the result while preserving its type. The named policies include notify, subst, defer, fwd, unwind, retry, as_expected, noop, sump::if_isa, sump::if_monomorphic, sump::if_equal, sump::thrown, sump::returned, when, translate / sump::nest, delay, sump::backoff, remember, circuit_breaker, and sump::always. Guards forward what they do not claim; translators forward with a different exception; delay/backoff/retry re-run; remember serves the last success. Policies compose with&(sequence; the last element answers; non-final answers are discarded) and|(alternation; the left may forward: a guard, translator or predicate on the left forwards by a returned claim, at no cost beyond its own test; any other policy forwards by throwing, at one unwind), and with*(n-fold|).sinkalso accepts reactions that are not policies:std::ignoreresumes with a default-constructed result; and anything else is taken as a substitution value, exactly assubst(value)(including a user’s nullarynullval-returning ending, which dies silently – pair withnotify &to opt the report back in). A substitution passed as an lvalue can serve a reference result, which the policy refers to rather than copies:int fallback = 42; int& x = sink(fallback) ->* [] { return returns_a_reference(); }; // x is fallback on a throw
The callable itself must not be
noexcept: an exception raised inside one ends the program where it stands, leaving the policy unreachable, so such a pairing is rejected instead of standing there looking like protection. Call such a callable directly.The location defaults to the call site, for a sink applied directly and for
sink(reaction)alike;sink(reaction, loc)reports a different site.Vocabulary visibility: the named policies live in the non-inline namespace
sump. Blessed patterns are a block-scopeusing namespace cuda::experimental::stf::sump;at the function that configures sinks, or a namespace alias (namespace pol = cuda::experimental::stf::sump;):using namespace cuda::experimental::stf::sump; (notify & retry * 3 | subst(-1)) ->* flaky; namespace pol = cuda::experimental::stf::sump; pol::subst(0) ->* flaky;
The right operand may also be a status, a value for which status_traits is specialized (
cudaError_t,CUresult, … oncecuda_safe_call.cuhis included):policy << cudaFree(p). A status is a past result handled on the code channel, and<<is the only way to feed one. The carrier then yields it:status<S>()is the first failing status the chain yielded, one an arm forwarded or left unchanged, andforwarded()says whether any arm forwarded. A value an arm substitutes stands in for the status, andunwindturns the status into an exception. Policies that only handle exceptions see the status’s exception,status_traits<S>::to_exception(status, loc). With exceptions disabled, such a policy that may forward (if_isa, a typedstore,translate, a user policy without a code-channel hook) reports and aborts on the first failing status, since reaching its hook means throwing; policies with a code-channel hook are unaffected.Note
When querying
noexcept(p ->* f)in a constant expression, writesink(p, loc) ->* fwith a location: nvcc’s front-end with a gcc host reports the defaultedsource_location::current()argument as potentially throwing, tainting the query (the call itself isnoexcepteither way).- Parameters:
__reaction – [in] The policy (or a reaction normalized into one). A policy is copied or moved in; a raw value or hook passed as an lvalue is referred to.
__loc – [in] The location passed to the policy’s hooks.
- Returns:
A carrier: it accepts
->*and<<like a sink, and a<<chain on it recordsstatus<S>()andforwarded().