From d58b6b17aac40665a8d2ffe2ecbbabc7cf25cf83 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Tue, 3 Dec 2024 00:33:23 +0100 Subject: [PATCH] P3325R5 A Utility for Creating Execution Environments --- source/exec.tex | 188 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 168 insertions(+), 20 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 93b641f0de..da2c91f221 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -465,13 +465,20 @@ template constexpr get_completion_scheduler_t @\libglobal{get_completion_scheduler}@{}; - struct @\libglobal{empty_env}@ {}; struct @\libglobal{get_env_t}@ { @\unspec@ }; inline constexpr get_env_t @\libglobal{get_env}@{}; template using @\libglobal{env_of_t}@ = decltype(get_env(declval())); + // \ref{exec.prop}, class template \tcode{prop} + template + struct prop; + + // \ref{exec.env}, class template \tcode{env} + template<@\exposconcept{queryable}@... Envs> + struct env; + // \ref{exec.domain.default}, execution domains struct default_domain; @@ -513,7 +520,7 @@ template concept @\libconcept{sender}@ = @\seebelow@; - template + template> concept @\libconcept{sender_in}@ = @\seebelow@; template @@ -526,7 +533,7 @@ struct get_completion_signatures_t; inline constexpr get_completion_signatures_t get_completion_signatures {}; - template + template> requires @\libconcept{sender_in}@ using completion_signatures_of_t = @\exposid{call-result-t}@; @@ -536,18 +543,18 @@ template using @\exposidnc{variant-or-empty}@ = @\seebelownc@; // \expos - template, template class Tuple = @\exposid{decayed-tuple}@, template class Variant = @\exposid{variant-or-empty}@> requires @\libconcept{sender_in}@ using value_types_of_t = @\seebelow@; - template, template class Variant = @\exposid{variant-or-empty}@> requires @\libconcept{sender_in}@ using error_types_of_t = @\seebelow@; - template + template> requires @\libconcept{sender_in}@ constexpr bool sends_stopped = @\seebelow@; @@ -661,7 +668,7 @@ template< @\libconcept{sender}@ Sndr, - class Env = empty_env, + class Env = env<>, @\exposconcept{valid-completion-signatures}@ AdditionalSignatures = completion_signatures<>, template class SetValue = @\seebelow@, template class SetError = @\seebelow@, @@ -833,7 +840,7 @@ The type of the expression above satisfies \exposconcept{queryable}\iref{exec.queryable}. \item -Otherwise, \tcode{empty_env\{\}}. +Otherwise, \tcode{env<>\{\}}. \end{itemize} \pnum @@ -1785,7 +1792,7 @@ if constexpr (sizeof...(child) == 1) return (@\exposid{FWD-ENV}@(get_env(child)), ...); else - return empty_env(); + return env<>(); } \end{codeblock} @@ -1929,7 +1936,7 @@ template concept @\defexposconcept{enable-sender}@ = // \expos @\exposconcept{is-sender}@ || - @\exposconcept{is-awaitable}@>; // \ref{exec.awaitable} + @\exposconcept{is-awaitable}@>>; // \ref{exec.awaitable} template concept @\deflibconcept{sender}@ = @@ -1940,7 +1947,7 @@ @\libconcept{move_constructible}@> && @\libconcept{constructible_from}@, Sndr>; - template + template> concept @\deflibconcept{sender_in}@ = @\libconcept{sender}@ && @\exposconcept{queryable}@ && @@ -1998,7 +2005,7 @@ value_types_of_t); template - concept @\defexposconcept{sender-of}@ = @\exposconcept{sender-in-of}@; + concept @\defexposconcept{sender-of}@ = @\exposconcept{sender-in-of}@, Values...>; } \end{codeblock} @@ -2680,7 +2687,7 @@ \tcode{\exposid{FWD-ENV}(get_env(sndr))}\iref{exec.fwd.env}. \item A parent sender with more than one child sender has -an associated attributes object equal to \tcode{empty_env\{\}}. +an associated attributes object equal to \tcode{env<>\{\}}. \item When a parent sender is connected to a receiver \tcode{rcvr}, any receiver used to connect a child sender has @@ -3401,7 +3408,7 @@ \item \tcode{\exposid{MAKE-ENV}(get_domain, get_domain(get_env(sndr)))} \item -\tcode{(void(sndr), empty_env\{\})} +\tcode{(void(sndr), env<>\{\})} \end{itemize} \pnum @@ -4114,7 +4121,7 @@ \begin{codeblock} [](auto&&, auto&&... child) noexcept { if constexpr (@\libconcept{same_as}@) { - return empty_env(); + return env<>(); } else { return @\exposid{MAKE-ENV}@(get_domain, CD()); } @@ -4852,23 +4859,21 @@ template<@\exposconcept{completion-signature}@... Fns> struct completion_signatures {}; - template, template class Tuple = @\exposid{decayed-tuple}@, template class Variant = @\exposid{variant-or-empty}@> requires @\libconcept{sender_in}@ using value_types_of_t = @\exposid{gather-signatures}@, Tuple, Variant>; - template, template class Variant = @\exposid{variant-or-empty}@> requires @\libconcept{sender_in}@ using error_types_of_t = @\exposid{gather-signatures}@, type_identity_t, Variant>; - template + template> requires @\libconcept{sender_in}@ constexpr bool sends_stopped = !@\libconcept{same_as}@<@\exposid{type-list}@<>, @@ -4977,6 +4982,149 @@ of all the \tcode{completion_signatures} specializations in the set \tcode{AdditionalSignatures}, \tcode{Vs...}, \tcode{Es...}, \tcode{Ss}. +\rSec1[exec.envs]{Queryable uilities} + +\rSec2[exec.prop]{Class template \tcode{prop}} + +\begin{codeblock} +namespace std::execution { + template + struct @\libglobal{prop}@ { + QueryTag @\exposid{query_}@; // \expos + ValueType @\exposid{value_}@; // \expos + + constexpr const ValueType& query(QueryTag) const noexcept { + return @\exposid{value_}@; + } + }; + + template + prop(QueryTag, ValueType) -> prop>; +} +\end{codeblock} + +\pnum +Class template \tcode{prop} is for building a queryable object +from a query object and a value. + +\pnum +\mandates +\tcode{\exposconcept{callable}>} +is modeled, +where \exposid{prop-like} is the following exposition-only class template: +\begin{codeblock} +template +struct @\exposid{prop-like}@ { // \expos + const ValueType& query(auto) const noexcept; +}; +\end{codeblock} + +\pnum +\begin{example} +\begin{codeblock} +template +sender auto parameterize_work(Sndr sndr) { + // Make an environment such that \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}}. + auto e = prop(get_allocator, my_alloc{}); + + // Parameterize the input sender so that it will use our custom execution environment. + return write_env(sndr, e); +} +\end{codeblock} +\end{example} + +\pnum +Specializations of \tcode{prop} are not assignable. + +\rSec2[exec.env]{Class template \tcode{env}} + +\begin{codeblock} +namespace std::execution { + template<@\exposconcept{queryable}@... Envs> + struct @\libglobal{env}@ { + Envs@$_0$@ @$\exposid{envs}_0$@; // \expos + Envs@$_1$@ @$\exposid{envs}_1$@; // \expos + @\vdots@ + Envs@$_{n-1}$@ @$\exposid{envs}_{n-1}$@; // \expos + + template + constexpr decltype(auto) query(QueryTag q) const noexcept(@\seebelow@); + }; + + template + env(Envs...) -> env...>; +} +\end{codeblock} + +\pnum +The class template \tcode{env} is used to construct a queryable object +from several queryable objects. +Query invocations on the resulting object are resolved +by attempting to query each subobject in lexical order. + +\pnum +Specializations of \tcode{env} are not assignable. + +\pnum +It is unspecified +whether \tcode{env} supports initialization +using a parenthesized \grammarterm{expression-list}\iref{dcl.init}, +unless the \grammarterm{expression-list} consist of +a single element of type (possibly const) \tcode{env}. + +\pnum +\begin{example} +\begin{codeblock} +template +sender auto parameterize_work(Sndr sndr) { + // Make an environment such that: + // \tcode{get_allocator(env)} returns a reference to a copy of \tcode{my_alloc\{\}} + // \tcode{get_scheduler(env)} returns a reference to a copy of \tcode{my_sched\{\}} + auto e = env{prop(get_allocator, my_alloc{}), + prop(get_scheduler, my_sched{})}; + + // Parameterize the input sender so that it will use our custom execution environment. + return write_env(sndr, e); +} +\end{codeblock} +\end{example} + +\indexlibrarymember{query}{env}% +\begin{itemdecl} +template +constexpr decltype(auto) query(QueryTag q) const noexcept(@\seebelow@); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \exposconcept{has-query} be the following exposition-only concept: +\begin{codeblock} +template + concept @\defexposconcept{has-query}@ = // \expos + requires (const Env& env) { + env.query(QueryTag()); + }; +\end{codeblock} + +\pnum +Let \exposid{fe} be the first element of +$\exposid{envs}_0$, $\exposid{envs}_1$, $\dotsc$, $\exposid{envs}_{n-1}$ +such that the expression \tcode{\exposid{fe}.query(q)} is well-formed. + +\pnum +\constraints +\tcode{(\exposconcept{has-query} || ...)} is \tcode{true}. + +\pnum +\effects +Equivalent to: \tcode{return \exposid{fe}.query(q);} + +\pnum +\remarks +The expression in the \tcode{noexcept} clause is equivalent +to \tcode{noexcept(\exposid{fe}.query(q))}. +\end{itemdescr} + \rSec1[exec.ctx]{Execution contexts} \rSec2[exec.run.loop]{\tcode{execution::run_loop}}