diff --git a/source/exceptions.tex b/source/exceptions.tex index 79684e4c51..c036557223 100644 --- a/source/exceptions.tex +++ b/source/exceptions.tex @@ -1126,7 +1126,10 @@ when \tcode{unhandled_stopped} is called on a \tcode{with_awaitable_senders} object\iref{exec.with.awaitable.senders} whose continuation is not a handle to a coroutine -whose promise type has an \tcode{unhandled_stopped} member function. +whose promise type has an \tcode{unhandled_stopped} member function, or + +\item% +when an exception is thrown from a coroutine \tcode{std::execution::task}\iref{exec.task} which doesn't support a \tcode{std::execution::set_error_t(std::execption_ptr)} completion. \end{itemize} diff --git a/source/exec.tex b/source/exec.tex index 8fa3c30a24..d05a6ca414 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -708,6 +708,24 @@ // \ref{exec.with.awaitable.senders} template<@\exposconcept{class-type}@ Promise> struct with_awaitable_senders; + + // \ref{exec.affine.on} + struct @\libglobal{affine_on_t}@ { @\unspec@ }; + inline constexpr affine_on_t @\libglobal{affine_on}@{}; + + // \ref{exec.inline.scheduler} + class @\libglobal{inline_scheduler}@; + + // \ref{exec.task.scheduler} + class @\libglobal{task_scheduler}@; + + // \ref{exec.task} + template + struct @\libglobal{with_error}@; + template<@\libconcept{scheduler}@ Sch> + struct @\libglobal{change_coroutine_scheduler}@; + template + class @\libglobal{task}@; } \end{codeblock} @@ -5672,3 +5690,845 @@ return as_awaitable(std::forward(value), static_cast(*this)); \end{codeblock} \end{itemdescr} + +\rSec2[exec.affine.on]{\tcode{execution::affine_on}} + +\pnum +\tcode{affine_on} adapts a sender into one that completes on +the specified scheduler. If the algorithm determines that the adapted +sender already completes on the correct scheduler it can avoid any +scheduling operation. + +\pnum +The name \tcode{affine_on} denotes a pipeable sender adaptor +object. For subexpressions \tcode{sch} and \tcode{sndr}, if +\tcode{decltype((sch))} does not satisfy \libconcept{scheduler}, or +\tcode{decltype((sndr))} does not satisfy \libconcept{sender}, +\tcode{affine_on(sndr, sch)} is ill-formed. + +\pnum +Otherwise, the expression \tcode{affine_on(sndr, sch)} is +expression-equivalent to: +\begin{codeblock} +transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(affine_on, sch, sndr)) +\end{codeblock} +except that \tcode{sndr} is evalutated only once. + +\pnum +The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} +is specialized for \tcode{affine_on_t} as follows: + +\begin{codeblock} +namespace std::execution { + template<> + struct @\exposid{impls-for}@: @\exposid{default-impls}@ { + static constexpr auto @\exposid{get-attrs}@ = + [](const auto& data, const auto& child) noexcept -> decltype(auto) { + return @\exposid{JOIN-ENV}@(@\exposid{SCHED-ATTRS}@(data), @\exposid{FWD-ENV}@(get_env(child))); + }; + }; +} +\end{codeblock} + +\pnum +Let \tcode{out_sndr} be a subexpression denoting a sender +returned from \tcode{affine_on(sndr, sch)} or one equal to such, +and let \tcode{OutSndr} be the type \tcode{decltype((out_sndr))}. +Let \tcode{out_rcvr} be a subexpression denoting a receiver that +has an environment of type \tcode{Env} such that \tcode{sender_in} +is \tcode{true}. Let \tcode{op} be an lvalue referring to +the operation state that results from connecting \tcode{out_sndr} +to \tcode{out_rcvr}. Calling \tcode{start(op)} will start \tcode{sndr} +on the current execution agent and execute completion operations +on \tcode{out_rcvr} on an execution agent of the execution resource +associated with \tcode{sch}. If the current execution resource is +the same as the execution resource associated with \tcode{sch}, the +completion operation on \tcode{out_rcvr} may be called before +\tcode{start(op)} completes. If scheduling onto \tcode{sch} fails, +an error completion on \tcode{out_rcvr} shall be executed on an +unspecified execution agent. + +\rSec2[exec.inline.scheduler]{\tcode{execution::inline_scheduler}} + +\begin{codeblock} +namespace std::execution { + class @\libglobal{inline_scheduler}@ { + class @\exposidnc{inline-sender}@; // \expos + template<@\libconcept{receiver}@ R> + class @\exposidnc{inline-state}@; // \expos + + public: + using scheduler_concept = scheduler_t; + + constexpr @\exposid{inline-sender}@ schedule() noexcept { return {}; } + constexpr bool operator== (const inline_scheduler&) const noexcept = default; + }; +} +\end{codeblock} + +\pnum +\tcode{inline_scheduler} is a class that models +\libconcept{scheduler}\iref{exec.sched}. All objects of type +\tcode{inline_scheduler} are equal. + +\pnum +\exposid{inline-sender} is an exposition-only type that satisfies +\libconcept{sender}. The type +\tcode{completion_signatures_of_t<\exposid{inline-sender}>} +is \tcode{completion_signatures}. + +\pnum +Let \tcode{sndr} be an expression of type \exposid{inline-sender}, +let \tcode{rcvr} be an expression such that +\tcode{\libconcept{receiver_of}} is {true} +where \tcode{CS} is \tcode{completion_signatures}, +then: + +\begin{itemize} +\item the expression \tcode{connect(sndr, rcvr)} has +type \tcode{\exposid{inline-state}>} +and is potentially-throwing if and only if +\tcode{((void)sndr, auto(rcvr))} is potentially-throwing, and +\item the expression +\tcode{get_completion_scheduler(get_env(sndr))} has +type\linebreak\tcode{inline_scheduler} and is potentially-throwing % avoid Overfull +if and only if \tcode{get_env(sndr)} is potentially-throwing. +\end{itemize} + +\pnum +Let \tcode{o} be a non-const lvalue of type +\tcode{\exposid{inline-state}}, and let \tcode{REC(o)} be +a non-const lvalue reference to an object of type \tcode{Rcvr} that +was initialized with the expression \tcode{rcvr} passed to an +invocation of \tcode{connect} that returned \tcode{o}, then: + +\begin{itemize} +\item the object to which \tcode{REC(o)} refers remains valid for +the lifetime of the object to which \tcode{o} refers, and +\item the expression \tcode{start(o)} is equivalent to +\tcode{set_value(std::move(REC(o)))}. +\end{itemize} + +\rSec2[exec.task.scheduler]{\tcode{execution::task_scheduler}} + +\begin{codeblock} +namespace std::execution { + class task_scheduler { + class @\exposidnc{ts-sender}@; // \expos + template<@\libconcept{receiver}@ R> + class @\exposidnc{state}@; // \expos + + public: + using scheduler_concept = scheduler_t; + + template> + requires (!@\libconcept{same_as}@>) + && @\libconcept{scheduler}@ + explicit task_scheduler(Sch&& sch, Allocator alloc = {}); + + @\exposid{ts-sender}@ schedule(); + + friend bool operator== (const task_scheduler& lhs, const task_scheduler& rhs) + noexcept; + template + requires (!@\libconcept{same_as}@) + && @\libconcept{scheduler}@ + friend bool operator== (const task_scheduler& lhs, const Sch& rhs) noexcept; + + private: + shared_ptr @\exposidnc{sch_}@; // \expos + }; +} +\end{codeblock} + +\pnum +\tcode{task_scheduler} is a class that models +\libconcept{scheduler}\iref{exec.sched}. Given on object \tcode{s} +of type \tcode{task_scheduler}, let \tcode{SCHED(s)} be the object +owned by \tcode{s.\exposid{sch_}}. + +\begin{itemdecl} +template> + requires(!@\libconcept{same_as}@>) && @\libconcept{scheduler}@ +explicit task_scheduler(Sch&& sch, Allocator alloc = {}); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initialize \exposid{sch_} with +\tcode{allocate_shared>(alloc, \linebreak % avoid Overfull +std::forward(sch))}. + +\pnum +\recommended Implementations should avoid the use of dynamically +allocated memory for small scheduler objects. + +\pnum +\remarks +Any allocations performed by construction of \exposid{ts-sender} or +\exposid{state} objects resulting from calls on \tcode{*this} are +performed using a copy of \tcode{alloc}. +\end{itemdescr} + +\begin{itemdecl} +@\exposid{ts-sender}@ schedule(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Returns an object of type \exposid{ts-sender} containing a sender +initialized with\linebreak \tcode{schedule(SCHED(*this))}. % avoid Overfull +\end{itemdescr} + +\begin{itemdecl} +bool operator== (const task_scheduler& lhs, const task_scheduler& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{return lhs == SCHED(rhs);} +\end{itemdescr} + +\begin{itemdecl} +template + requires (!@\libconcept{same_as}@) + && @\libconcept{scheduler}@ +bool operator== (const task_scheduler& lhs, const Sch& rhs) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{false} if type of \tcode{SCHED(lhs)} is not \tcode{Sch}, +otherwise \tcode{SCHED(lhs) == rhs;} +\end{itemdescr} + +\begin{codeblock} +class task_scheduler::@\exposid{ts-sender}@ { // \expos +public: + using sender_concept = sender_t; + + template<@\libconcept{receiver}@ Rcvr> + @\exposid{state}@ connect(Rcvr&& rcvr); +}; +\end{codeblock} + +\pnum +\exposid{ts-sender} is an exposition-only class that models +\libconcept{sender}\iref{exec.snd} and for which +\tcode{completion_signatures_of_t<\exposid{ts-sender}>} denotes: + +\begin{codeblock} +completion_signatures< + set_value_t(), + set_error_t(error_code), + set_error_t(exception_ptr), + set_stopped_t()> +\end{codeblock} + +\pnum +Let \tcode{sch} be an object of type \tcode{task_scheduler} +and let \tcode{sndr} be an object of type \exposid{ts-sender} obtained +from \tcode{schedule(sch)}. Then +\tcode{get_completion_scheduler(get_env(sndr)) == sch} +is \tcode{true}. The object \tcode{SENDER(sndr)} is the sender +object contained by \tcode{sndr} or an object move constructed from +it. + +\begin{itemdecl} +template<@\libconcept{receiver}@ Rcvr> +@\exposid{state}@ connect(Rcvr&& rcvr); +\end{itemdecl} + +\pnum +\effects +Let \tcode{r} be an object of a type that models \libconcept{receiver} +and whose completion handlers result in invoking the corresponding +completion handlers of \tcode{rcvr} or copy thereof. Returns an +object of type \tcode{\exposid{state}} containing an operation +state object initialized with \tcode{connect(SENDER(*this), +std::move(r))}. + +\begin{codeblock} +template<@\libconcept{receiver}@ R> +class task_scheduler::@\exposid{state}@ { // \expos +public: + using operation_state_concept = operation_state_t; + + void start() & noexcept; +}; +\end{codeblock} + +\pnum +\exposid{state} is an exposition-only class template whose +specializations model \libconcept{operation_state}\iref{exec.opstate}. + +\begin{itemdecl} +void start() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to \tcode{start(st)} where \tcode{st} is the operation +state object contained by \tcode{*this}. +\end{itemdescr} + +\rSec2[exec.task]{\tcode{execution::task}} + +\rSec3[task.overview]{\tcode{task} Overview} + +\pnum +The \tcode{task} class template represents a sender that can +be used as the return type of coroutines. The first template parameter +\tcode{T} defines the type of the value completion datum +\iref{exec.async.ops} if \tcode{T} is not \tcode{void}. Otherwise, +there are no value completion datums. Inside coroutines returning +\tcode{task} the operand of \tcode{co_return} (if any) becomes +the argument of \tcode{set_value}. The second template parameter +\tcode{Environment} is used to customize the behavior of \tcode{task}. + +\rSec3[task.class]{Class template \tcode{task}} + +\begin{codeblock} +namespace std::execution { + template + class task { + // \ref{task.state} + template<@\libconcept{receiver}@ Rcvr> + class @\exposidnc{state}@; // \expos + + public: + using sender_concept = sender_t; + using completion_signatures = @\seebelow@; + using allocator_type = @\seebelow@; + using scheduler_type = @\seebelow@; + using stop_source_type = @\seebelow@; + using stop_token_type = decltype(declval().get_token()); + using error_types = @\seebelow@; + + // \ref{task.promise} + class promise_type; + + task(task&&) noexcept; + ~task(); + + template<@\libconcept{receiver}@ Rcvr> + @\exposid{state}@ connect(Rcvr&& rcvr); + + private: + coroutine_handle @\exposidnc{handle}@; // \expos + }; +} +\end{codeblock} + +\pnum +\tcode{task} models \libconcept{sender}\iref{exec.snd} +if \tcode{T} is \tcode{void}, a reference type, or an \cv{}-unqualified +non-array object type and \tcode{E} is a class type. Otherwise a program +that instantiates the definition of \tcode{task} is ill-formed. + +\pnum +The nested types of \tcode{task} template specializations +are determined based on the \tcode{Environment} parameter: + +\begin{itemize} +\item \tcode{allocator_type} is \tcode{Environment::allocator_type} +if that qualified-id is valid and denotes a type, \tcode{allocator} +otherwise. +\item \tcode{scheduler_type} is \tcode{Environment::scheduler_type} +if that qualified-id is valid and denotes a type, \tcode{task_scheduler} +otherwise. +\item \tcode{stop_source_type} is \tcode{Environment::stop_source_type} +if that qualified-id is valid and denotes a type, +\tcode{inplace_stop_source} otherwise. +\item \tcode{error_types} is \tcode{Environment::error_types} if +that qualified-id is valid and denotes a type, \linebreak % avoid Overfull +\tcode{completion_signatures} otherwise. +\end{itemize} + +\pnum + A program is ill-formed if \tcode{error_types} is not a +specialization of \tcode{completion_signatures} or +\tcode{ErrorSigs} contains an element which is not of the form +\tcode{set_error_t(E)} for some type \tcode{E}. + +\pnum +The type alias \tcode{completion_signatures} is a specialization +of \tcode{execution::completion_signatures} with the template +arguments (in unspecified order): + +\begin{itemize} +\item \tcode{set_value_t()} if \tcode{T} is \tcode{void}, and +\tcode{set_value_t(T)} otherwise; +\item template arguments of the specialization of +\tcode{execution::completion_signatures} denoted by \tcode{error_types}; +and +\item \tcode{set_stopped_t()}. +\end{itemize} + +\pnum +\tcode{allocator_type} shall meet the \oldconcept{Allocator} +requirements\iref{allocator.requirements.general}. + +\rSec3[task.members]{\tcode{task} Members} + +\begin{itemdecl} +task(task&& other) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{handle} with \tcode{exchange(other.\exposid{handle}, +\{\})}. +\end{itemdescr} + +\begin{itemdecl} +~task(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: + +\begin{codeblock} +if (@\exposid{handle}@) + @\exposid{handle}@.destroy(); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template<@\libconcept{receiver}@ R> +@\exposid{state}@ connect(R&& recv); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{bool(\exposid{handle})} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return \exposid{state}(exchange(\exposid{handle}, +\{\}), std::forward(recv));} +\end{itemdescr} + +\rSec3[task.state]{\tcode{Class template \tcode{task::state}}} + +\begin{codeblock} +namespace std::execution { + template + template<@\libconcept{receiver}@ Rcvr> + class task::@\exposid{state}@ { // \expos + public: + using operation_state_concept = operation_state_t; + + template + @\exposid{state}@(coroutine_handle h, R&& rr); + ~@\exposid{state}@(); + void start() & noexcept; + +private: + using @\exposidnc{own-env-t}@ = @\seebelow@; // \expos + coroutine_handle @\exposidnc{handle}@; // \expos + remove_cvref_t @\exposidnc{rcvr}@; // \expos + @\exposid{own-env-t}@ @\exposidnc{own-env}@; // \expos + Environment @\exposidnc{environment}@; // \expos + }; +} +\end{codeblock} + +\begin{itemdescr} +\pnum +The type \exposid{own-env-t} is \tcode{Environment::template +env_type()))>} if that % avoid Overfull +qualified-id is valid and denotes a type, \tcode{env<>} otherwise. +\end{itemdescr} + +\begin{itemdecl} +template +@\exposid{state}@(coroutine_handle h, R&& rr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes + +\item \exposid{handle} with \tcode{std::move(h)}; +\item \exposid{rcvr} with \tcode{std::forward(rr)}; +\item \exposid{own-env} + with \tcode{\exposid{own-env-t}(get_env(\exposid{rcvr}))} if that expression + is valid and \tcode{\exposid{own-env-t}()} otherwise. + If neither of these expressions is valid, the program is ill-formed. +\item \exposid{environment} with \tcode{Environment(\exposid{own-env})} if that expression is + valid, otherwise \tcode{Environment(get_env(\exposid{rcvr}))} + if this expression is valid, otherwise \tcode{Environment()}. + If neither of these expressions is valid, the program is ill-formed. +\end{itemdescr} + +\begin{itemdecl} +~@\exposid{state}@(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: + +\begin{codeblock} +if (@\exposid{handle}@) + @\exposid{handle}@.destroy(); +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +void start() & noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Let \tcode{prom} be the object \tcode{\exposid{handle}.promise()}. +Associates \tcode{STATE(prom)}, \tcode{RCVR(prom)}, and \tcode{SCHED(prom)} +with \tcode{*this} as follows: + +\begin{itemize} +\item \tcode{STATE(prom)} is \tcode{*this}. +\item \tcode{RCVR(prom)} is \exposid{rcvr}. +\item \tcode{SCHED(prom)} is the object initialized +with \tcode{scheduler_type(get_scheduler(get_env(\exposid{rcvr})))} +if that expression is valid and \tcode{scheduler_type()} otherwise. +If neither of these expressions is valid, the program is ill-formed. +\end{itemize} + +Let \tcode{st} be \tcode{get_stop_token(get_env(\exposid{rcvr}))}. +Initializes \tcode{prom.\exposid{token}} and +\tcode{prom.\exposid{source}} such that + +\begin{itemize} +\item +\tcode{prom.\exposid{token}.stop_requested()} returns +\tcode{st.stop_requested()}; +\item +\tcode{prom.\exposid{token}.stop_possible()} returns +\tcode{st.stop_possible()}; and +\item +for types \tcode{Fn} and \tcode{Init} such that both +\tcode{\libconcept{invocable}} and +\tcode{\libconcept{constructible_from}} are modeled, +\tcode{stop_token_type::callback_type} models +\tcode{\exposid{stoppable-callback-for}}. +\end{itemize} + +After that invokes \tcode{\exposid{handle}.resume()}. +\end{itemdescr} + +\rSec3[task.promise]{Class \tcode{task::promise_type}} + +\begin{codeblock} +namespace std::execution { + template + struct with_error { + using type = remove_cvref_t; + type error; + }; + template + with_error(E) -> with_error; + + template<@\libconcept{scheduler}@ Sch> + struct change_coroutine_scheduler { + using type = remove_cvref_t; + type scheduler; + }; + template<@\libconcept{scheduler}@ Sch> + change_coroutine_scheduler(Sch) -> change_coroutine_scheduler; + + template + class task::promise_type { + public: + template + promise_type(const Args&... args); + + task get_return_object() noexcept; + + auto initial_suspend() noexcept; + auto final_suspend() noexcept; + + void uncaught_exception(); + coroutine_handle<> unhandled_stopped(); + + void return_void(); // present only if is_void_v is true; + template + void return_value(V&& value); // present only if is_void_v is false; + + template + @\unspec@ yield_value(with_error error); + + template + auto await_transform(A&& a); + template + auto await_transform(change_coroutine_scheduler sch); + + @\unspec@ get_env() const noexcept; + + template + void* operator new(size_t size, Args&&... args); + + void operator delete(void* pointer, size_t size) noexcept; + + private: + using @\exposidnc{error-variant}@ = @\seebelow@; // \expos + + allocator_type @\exposidnc{alloc}@; // \expos + stop_source_type @\exposidnc{source}@; // \expos + stop_token_type @\exposidnc{token}@; // \expos + optional @\exposidnc{result}@; // \expos; present only if is_void_v is false; + @\exposid{error-variant}@ @\exposidnc{errors}@; // \expos + }; +} +\end{codeblock} + +\pnum +Let \tcode{prom} be an object of \tcode{promise_type} and let \tcode{tsk} be +the \tcode{task} object created by \tcode{prom.get_return_object()}. The +description below refers to objects \tcode{STATE(prom)}, +\tcode{RCVR(prom)}, and \tcode{SCHED(prom)} associated +with \tcode{tsk} during evalutation of \tcode{task::\exposid{state}::start} +for some receiver \tcode{Rcvr}. + +\pnum +\exposid{error-variant} is a \tcode{variant...>}, with duplicate types removed, where \tcode{E...} +are template arguments of the specialization of +\tcode{execution::completion_signatures} denoted by +\tcode{error_types}. + +\begin{itemdecl} +template +promise_type(const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +The first parameter of type \tcode{allocator_arg_t} (if any) is not +the last parameter. + +\pnum +\effects +If \tcode{Args} contains an element of type \tcode{allocator_arg_t} +then \exposid{alloc} is initialized with the corresponding next +element of \tcode{args}. Otherwise, \exposid{alloc} is initialized +with \tcode{allocator_type()}. +\end{itemdescr} + +\begin{itemdecl} +task get_return_object() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A \tcode{task} object whose member \exposid{handle} is +\tcode{coroutine_handle::\linebreak from_promise(*this)}. % avoid Overfull +\end{itemdescr} + +\begin{itemdecl} +auto initial_suspend() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An awaitable object of unspecified type \iref{expr.await} whose +member functions arrange for + +\begin{itemize} +\item the calling coroutine to be suspended, +\item the coroutine to be resumed on an execution agent of the +execution resource associated with \tcode{SCHED(*this)}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +auto final_suspend() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An awaitable object of unspecified type \iref{expr.await} whose +member functions arrange for the completion of the asynchronous +operation associated with \tcode{STATE(*this)} by invoking: + +\begin{itemize} +\item + \tcode{set_error(std::move(RCVR(*this)), std::move(e))} + if \tcode{\exposid{errors}.index()} is greater than zero and + \tcode{e} is the value held by \exposid{errors}, otherwise +\item + \tcode{set_value(std::move(RCVR(*this)))} if \tcode{is_void} is \tcode{true}, + and otherwise +\item + \tcode{set_value(std::move(RCVR(*this)), *\exposid{result})}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template +auto yield_value(with_error err); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{std::move(err.error)} is convertible to exactly one of the +\tcode{set_error_t} argument types of \tcode{error_types}. Let +\tcode{Cerr} be that type. + +\pnum +\returns +An awaitable object of unspecified type \iref{expr.await} whose +member functions arrange for the calling coroutine to be suspended +and then completes the asynchronous operation associated with +\tcode{STATE(*this)} by invoking \tcode{set_error(std::move(RCVR(*this)), +Cerr(std::move(err.error)))}. +\end{itemdescr} + +\begin{itemdecl} +template<@\libconcept{sender}@ Sender> +auto await_transform(Sender&& sndr) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{same_as} is \tcode{true} +returns \tcode{as_awaitable(\linebreak std::forward (sndr), % avoid Overfull +*this)}; otherwise returns +\tcode{as_awaitable(affine_on(\linebreak std::forward(sndr), % avoid Overfull +SCHED(*this)), *this)}. +\end{itemdescr} + +\begin{itemdecl} +template +auto await_transform(change_coroutine_scheduler sch) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: \tcode{returns await_transform(just(exchange(SCHED(*this), +\linebreak scheduler_type(sch.scheduler))), *this);} % avoid Overfull +\end{itemdescr} + +\begin{itemdecl} +void uncaught_exception(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +If the signature \tcode{set_error_t(exception_ptr)} is not an element +of \tcode{error_types}, calls \tcode{terminate()} \iref{except.terminate}. +Otherwise, stores \tcode{current_exception()} into \exposid{errors}. +\end{itemdescr} + +\begin{itemdecl} +coroutine_handle<> unhandled_stopped(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Completes the asynchronous operation associated with \tcode{STATE(*this)} +by invoking \tcode{set_stopped(std::move(RCVR(*this)))}. +\end{itemdescr} + +\begin{itemdescr} +\pnum +\returns +\tcode{noop_coroutine()}. +\end{itemdescr} + +\begin{itemdecl} +@\unspec@ get_env() const noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An object \tcode{env} such that queries are forwarded as follows: + +\begin{itemize} +\item \tcode{env.query(get_scheduler)} returns \tcode{scheduler_type(SCHED(*this))}. +\item \tcode{env.query(get_allocator)} returns \exposid{alloc}. +\item \tcode{env.query(get_stop_token)} returns \exposid{token}. +\item For any other query \tcode{q} and arguments \tcode{a...} a + call to \tcode{env.query(q, a...)} returns + \tcode{STATE(*this).} \tcode{environment.query(q, a...)} if this expression + is well-formed and \tcode{forwarding_query(q)} is well-formed and is \tcode{true}. Otherwise + \tcode{env.query(q, a...)} is ill-formed. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template +void* operator new(size_t size, const Args&... args); +\end{itemdecl} + +\begin{itemdescr} +\pnum +If there is no parameter with type \tcode{allocator_arg_t} then let +\tcode{alloc} be \tcode{Allocator()}. Let \tcode{arg_next} be the +parameter following the first \tcode{allocator_arg_t} parameter (if +any) and let \tcode{alloc} be \tcode{Allocator(arg_next)}. Then +\tcode{PAlloc} is \tcode{allocator_traits::template +rebind_alloc\linebreak} where \tcode{U} is an unspecified type % avoid Overfull +whose size and alignment are both \tcode{__STDCPP_DEFAULT_NEW_ALIGNMENT__}. + +\pnum +\mandates + +\begin{itemize} +\item The first parameter of type \tcode{allocator_arg_t} (if any) is not the last parameter. +\item \tcode{Allocator(arg_next)} is a valid expression if there is a parameter + of type \tcode{allocator_arg_t}. +\item \tcode{allocator_traits::pointer} is a pointer type. +\end{itemize} + +\pnum +\effects +Initializes an allocator \tcode{palloc} of type \tcode{PAlloc} with +\tcode{alloc}. Uses \tcode{palloc} to allocate storage for the +smallest array of \tcode{U} sufficient to provide storage for a +coroutine state of size \tcode{size}, and unspecified additional +state necessary to ensure that \tcode{operator delete} can later +deallocate this memory block with an allocator equal to \tcode{palloc}. +\pnum +\returns +A pointer to the allocated storage. +\end{itemdescr} + +\begin{itemdecl} +void operator delete(void* pointer, size_t size) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\expects +\tcode{pointer} was returned from an invocation of the above overload +of \tcode{operator new} with a size argument equal to \tcode{size}. + +\pnum +\effects +Deallocates the storage pointed to by \tcode{pointer} using an +allocator equal to that used to allocate it. +\end{itemdescr} diff --git a/source/support.tex b/source/support.tex index 95d674aafb..6baa7f58fb 100644 --- a/source/support.tex +++ b/source/support.tex @@ -825,6 +825,7 @@ #define @\defnlibxname{cpp_lib_string_view}@ 202403L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_submdspan}@ 202411L // freestanding, also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_syncbuf}@ 201803L // also in \libheader{syncstream} +#define @\defnlibxname{cpp_lib_task}@ 202506L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_text_encoding}@ 202306L // also in \libheader{text_encoding} #define @\defnlibxname{cpp_lib_three_way_comparison}@ 201907L // freestanding, also in \libheader{compare} #define @\defnlibxname{cpp_lib_to_address}@ 201711L // freestanding, also in \libheader{memory}