From 6fe6862a51b31e499588b2e21b495ccf949adb77 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Fri, 3 Apr 2026 08:29:50 +0200 Subject: [PATCH 1/2] P3804R2 Iterating on parallel_scheduler Fixes NB RO 4-395 (C++26 CD). --- source/exec.tex | 133 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 45 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 4455a1c991..68dd2e16af 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -8494,24 +8494,6 @@ for operations launched via calls to \tcode{parallel_scheduler_backend}. \end{note} -\pnum -A \defnx{bulk chunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args}}{proxy!bulk chunked} -is a proxy \tcode{r} for \tcode{rcvr} -with base \tcode{system_context_replaceability::bulk_item_receiver_proxy} -such that -\tcode{r.execute(i, j)} for indices \tcode{i} and \tcode{j} -has effects equivalent to \tcode{f(i, j, args...)}. - -\pnum -A \defnx{bulk unchunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args}}{proxy!bulk unchunked} -is a proxy \tcode{r} for \tcode{rcvr} -with base \tcode{system_context_replaceability::bulk_item_receiver_proxy} -such that -\tcode{r.execute(i, i + 1)} for index \tcode{i} -has effects equivalent to \tcode{f(i, args...)}. - \pnum Let \tcode{b} be \tcode{\exposid{BACKEND-OF}(sch)}, let \tcode{sndr} be the object returned by \tcode{schedule(sch)}, and @@ -8534,52 +8516,100 @@ \end{itemize} \pnum -\tcode{parallel_scheduler} provides a customized implementation of -the \tcode{bulk_chunked} algorithm\iref{exec.bulk}. -If a receiver \tcode{rcvr} is connected to the sender -returned by \tcode{bulk_chunked(sndr, pol, shape, f)} and +The expression \tcode{get_domain(sch)} +returns an expression of exposition-only type +\exposid{parallel-scheduler-do\-main}, that is equivalent with: + +\begin{itemdecl} +struct @\exposid{parallel-scheduler-domain}@ { + template<@\exposconcept{sender-for}@ Sndr, @\exposconcept{queryable}@ Env> + static constexpr decltype(auto) + transform_sender(set_value_t, Sndr&& sndr, const Env& env) const noexcept { + return @\seebelow@; + } + template<@\exposconcept{sender-for}@ Sndr, @\exposconcept{queryable}@ Env> + static constexpr decltype(auto) + transform_sender(set_value_t, Sndr&& sndr, const Env& env) const noexcept { + return @\seebelow@; + } +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +For argument \tcode{sndr} of the above \tcode{transform_sender}, +let \tcode{child}, \tcode{pol}, \tcode{shape} and \tcode{f} +be defined by the following declarations: +\begin{codeblock} +auto& [_, data, child] = sndr; +auto& [pol, shape, f] = data; +\end{codeblock} + +\pnum +Let \tcode{p} be: +\begin{itemize} +\item +\tcode{true}, if the type of the expression \tcode{pol} is +\cv{}~\tcode{parallel_policy} or \cv{}~\tcode{parallel_unsequenced_policy}; +\item +implementation-defined, if \tcode{pol} is an implementation-defined execution policy; +\item +\tcode{false}, otherwise. +\end{itemize} + +\pnum +The \tcode{transform_sender} overload +that accepts senders with tag \tcode{bulk_chunked_t} +returns a sender such that if it is connected to a receiver \tcode{rcvr} and the resulting operation state is started, then: \begin{itemize} \item -If \tcode{sndr} completes with values \tcode{vals}, +If \tcode{child} completes with values \tcode{vals}, let \tcode{args} be a pack of lvalue subexpressions designating \tcode{vals}, -then \tcode{b.schedule_bulk_chunked(shape, r, s)} is called, where +then \tcode{b.schedule_bulk_chunked(p ? shape : 1, r, s)} is called, where \begin{itemize} \item -\tcode{r} is a bulk chunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args} and +\tcode{r} is a proxy for \tcode{rcvr} +with base \tcode{system_context_replaceability::bulk_item_receiver_proxy} +such that \tcode{r.execute(i, j)} for indices \tcode{i} and \tcode{j} +has effects equivalent to +\tcode{f(i, j, args...)} if \tcode{p} is true and +\tcode{f(0, shape, args...)} otherwise; and \item \tcode{s} is a preallocated backend storage for \tcode{r}. \end{itemize} \item All other completion operations are forwarded unchanged. \end{itemize} -\begin{note} -Customizing the behavior of \tcode{bulk_chunked} -affects the default implementation of \tcode{bulk}. -\end{note} \pnum -\tcode{parallel_scheduler} provides a customized implementation of -the \tcode{bulk_unchunked} algorithm\iref{exec.bulk}. -If a receiver \tcode{rcvr} is connected to the sender -returned by \tcode{bulk_unchunked(sndr, pol, shape, f)} and +The \tcode{transform_sender} overload +that accepts senders with tag \tcode{bulk_unchunked_t} +returns a sender such that if it is connected to a receiver \tcode{rcvr} and the resulting operation state is started, then: \begin{itemize} \item -If \tcode{sndr} completes with values \tcode{vals}, +If \tcode{child} completes with values \tcode{vals}, let \tcode{args} be a pack of lvalue subexpressions designating \tcode{vals}, -then \tcode{b.schedule_bulk_unchunked(shape, r, s)} is called, where +then \tcode{b.schedule_bulk_unchunked(p ? shape : 1, r, s)} is called, where \begin{itemize} \item -\tcode{r} is a bulk unchunked proxy for \tcode{rcvr} -with callable \tcode{f} and arguments \tcode{args} and +\tcode{r} is a proxy for \tcode{rcvr} +with base \tcode{system_context_replaceability::bulk_item_receiver_proxy} +such that \tcode{r.execute(i, i + 1)} for index \tcode{i} +has effects equivalent to +\tcode{f(i, args...)} if \tcode{p} is true and +\begin{codeblock} +for (decltype(shape) i = 0; i < shape; i++) { f(i, args...); } +\end{codeblock} +otherwise; and \item \tcode{s} is a preallocated backend storage for \tcode{r}. \end{itemize} \item All other completion operations are forwarded unchanged. \end{itemize} +\end{itemdescr} \indexlibraryglobal{get_parallel_scheduler}% \begin{itemdecl} @@ -8609,8 +8639,6 @@ \begin{codeblock} namespace std::execution::system_context_replaceability { struct @\libglobal{receiver_proxy}@ { - virtual ~receiver_proxy() = default; - protected: virtual bool @\exposidnc{query-env}@(@\unspecnc@) noexcept = 0; // \expos @@ -8620,7 +8648,7 @@ virtual void set_stopped() noexcept = 0; template - optional

try_query(Query q) noexcept; + optional

try_query(Query q) const noexcept; }; struct @\libglobal{bulk_item_receiver_proxy}@ : receiver_proxy { @@ -8642,7 +8670,7 @@ \begin{itemdecl} template - optional

@\libglobal{try_query}@(Query q) noexcept; + optional

@\libglobal{try_query}@(Query q) const noexcept; \end{itemdecl} \begin{itemdescr} @@ -8662,11 +8690,13 @@ \tcode{P} is not a member of an implementation-defined set of supported result types for \tcode{Query}; or \item -the expression \tcode{q(env)} is not well-formed or -does not have type \cv{} \tcode{P}, +the expression \tcode{q(env)} is not well-formed, \end{itemize} then returns \tcode{nullopt}. -Otherwise, returns \tcode{q(env)}. +Otherwise, if \tcode{q(env)} has type \cv{}~\tcode{P}, +then returns \tcode{q(env)}. +Otherwise, returns an implementation-defined value +of type \tcode{optional

}. \pnum \remarks @@ -8675,6 +8705,19 @@ \tcode{inplace_stop_token} is a member of the implementation-defined set of supported result types for \tcode{get_stop_token_t}. + +\pnum +\recommended +If \tcode{P} is \tcode{inplace_stop_token} and +\tcode{T} is a type other than \tcode{inplace_stop_token} +that models \libconcept{stoppable_token}, +\tcode{try_query} should return an object of type \tcode{inplace_stop_token} +such that until one of +\tcode{set_value}, +\tcode{set_error} or +\tcode{set_stopped} +is called on \tcode{*this}, +all calls to \tcode{try_query} return equivalent \tcode{inplace_stop_token} objects. \end{itemdescr} \rSec2[exec.sysctxrepl.query]{\tcode{query_parallel_scheduler_backend}} From 1dd037cb91319098c5d626090dce520bfd78eb93 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Fri, 3 Apr 2026 08:30:23 +0200 Subject: [PATCH 2/2] Fixup: grammar --- source/exec.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/exec.tex b/source/exec.tex index 68dd2e16af..7390fd472a 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -8518,7 +8518,7 @@ \pnum The expression \tcode{get_domain(sch)} returns an expression of exposition-only type -\exposid{parallel-scheduler-do\-main}, that is equivalent with: +\exposid{parallel-scheduler-do\-main}, that is equivalent to: \begin{itemdecl} struct @\exposid{parallel-scheduler-domain}@ {