From f67223914c841c2abd6aaa67e2c5d953d919b0f1 Mon Sep 17 00:00:00 2001 From: Jens Maurer Date: Thu, 19 Jun 2025 22:01:58 +0200 Subject: [PATCH] P3682R0 Remove std::execution::split --- source/exec.tex | 373 ------------------------------------------------ 1 file changed, 373 deletions(-) diff --git a/source/exec.tex b/source/exec.tex index 251a81ab38..49e459c9a8 100644 --- a/source/exec.tex +++ b/source/exec.tex @@ -629,7 +629,6 @@ struct @\libglobal{let_error_t}@ { @\unspec@ }; struct @\libglobal{let_stopped_t}@ { @\unspec@ }; struct @\libglobal{bulk_t}@ { @\unspec@ }; - struct @\libglobal{split_t}@ { @\unspec@ }; struct @\libglobal{when_all_t}@ { @\unspec@ }; struct @\libglobal{when_all_with_variant_t}@ { @\unspec@ }; struct @\libglobal{into_variant_t}@ { @\unspec@ }; @@ -647,7 +646,6 @@ inline constexpr let_error_t @\libglobal{let_error}@{}; inline constexpr let_stopped_t @\libglobal{let_stopped}@{}; inline constexpr bulk_t @\libglobal{bulk}@{}; - inline constexpr split_t @\libglobal{split}@{}; inline constexpr when_all_t @\libglobal{when_all}@{}; inline constexpr when_all_with_variant_t @\libglobal{when_all_with_variant}@{}; inline constexpr into_variant_t @\libglobal{into_variant}@{}; @@ -3695,377 +3693,6 @@ propagates all completion operations sent by \tcode{sndr}. \end{itemize} -\rSec3[exec.split]{\tcode{execution::split}} - -\pnum -\tcode{split} adapts an arbitrary sender -into a sender that can be connected multiple times. - -\pnum -Let \exposid{split-env} be the type of an environment -such that, given an instance \tcode{env}, -the expression \tcode{get_stop_token(env)} is well-formed and -has type \tcode{inplace_stop_token.} - -\pnum -The name \tcode{split} denotes a pipeable sender adaptor object. -For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. -If \tcode{\libconcept{sender_in}} is \tcode{false}, -\tcode{split(sndr)} is ill-formed. - -\pnum -Otherwise, the expression \tcode{split(sndr)} is expression-equivalent to: -\begin{codeblock} -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(split, {}, sndr)) -\end{codeblock} -except that \tcode{sndr} is evaluated only once. -\begin{note} -The default implementation of \tcode{transform_sender} -will have the effect of connecting the sender to a receiver. -It will return a sender with a different tag type. -\end{note} - -\pnum -Let \exposid{local-state} denote the following exposition-only class template: - -\begin{codeblock} -namespace std::execution { - struct @\exposid{local-state-base}@ { // \expos - virtual ~@\exposid{local-state-base}@() = default; - virtual void @\exposid{notify}@() noexcept = 0; // \expos - }; - - template - struct @\exposid{local-state}@ : @\exposid{local-state-base}@ { // \expos - using @\exposid{on-stop-callback}@ = // \expos - stop_callback_for_t>, @\exposid{on-stop-request}@>; - - @\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; - ~@\exposid{local-state}@(); - - void @\exposid{notify}@() noexcept override; - - private: - optional<@\exposid{on-stop-callback}@> @\exposid{on_stop}@; // \expos - @\exposid{shared-state}@* @\exposid{sh_state}@; // \expos - Rcvr* @\exposid{rcvr}@; // \expos - }; -} -\end{codeblock} - -\begin{itemdecl} -@\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -auto& [_, data, _] = sndr; -this->@\exposid{sh_state}@ = data.sh_state.get(); -this->@\exposid{sh_state}@->@\exposid{inc-ref}@(); -this->@\exposid{rcvr}@ = addressof(rcvr); -\end{codeblock} -\end{itemdescr} - -\begin{itemdecl} -~@\exposid{local-state}@(); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -sh_state->@\exposid{dec-ref}@(); -\end{codeblock} -\end{itemdescr} - -\begin{itemdecl} -void @\exposid{notify}@() noexcept override; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Equivalent to: -\begin{codeblock} -@\exposid{on_stop}@.reset(); -visit( - [this](const auto& tupl) noexcept -> void { - apply( - [this](auto tag, const auto&... args) noexcept -> void { - tag(std::move(*@\exposid{rcvr}@), args...); - }, - tupl); - }, - @\exposid{sh_state}@->result); -\end{codeblock} -\end{itemdescr} - -\pnum -Let \exposid{split-receiver} denote -the following exposition-only class template: -\begin{codeblock} -namespace std::execution { - template - struct @\exposid{split-receiver}@ { // \expos - using receiver_concept = receiver_t; - - template - void @\exposid{complete}@(Tag, Args&&... args) noexcept { // \expos - using tuple_t = @\exposid{decayed-tuple}@; - try { - @\exposid{sh_state}@->result.template emplace(Tag(), std::forward(args)...); - } catch (...) { - using tuple_t = tuple; - @\exposid{sh_state}@->result.template emplace(set_error, current_exception()); - } - @\exposid{sh_state}@->notify(); - } - - template - void set_value(Args&&... args) && noexcept { - @\exposid{complete}@(execution::set_value, std::forward(args)...); - } - - template - void set_error(Error&& err) && noexcept { - @\exposid{complete}@(execution::set_error, std::forward(err)); - } - - void set_stopped() && noexcept { - @\exposid{complete}@(execution::set_stopped); - } - - struct @\exposid{env}@ { // \expos - @\exposid{shared-state}@* @\exposid{sh-state}@; // \expos - - inplace_stop_token query(get_stop_token_t) const noexcept { - return @\exposid{sh-state}@->stop_src.get_token(); - } - }; - - @\exposid{env}@ get_env() const noexcept { - return @\exposid{env}@{@\exposid{sh_state}@}; - } - - @\exposid{shared-state}@* @\exposid{sh_state}@; // \expos - }; -} -\end{codeblock} - -\pnum -Let \exposid{shared-state} denote the following exposition-only class template: -\begin{codeblock} -namespace std::execution { - template - struct @\exposid{shared-state}@ { - using @\exposid{variant-type}@ = @\seebelow@; // \expos - using @\exposid{state-list-type}@ = @\seebelow@; // \expos - - explicit @\exposid{shared-state}@(Sndr&& sndr); - - void @\exposid{start-op}@() noexcept; // \expos - void @\exposid{notify}@() noexcept; // \expos - void @\exposid{inc-ref}@() noexcept; // \expos - void @\exposid{dec-ref}@() noexcept; // \expos - - inplace_stop_source @\exposid{stop_src}@{}; // \expos - @\exposid{variant-type}@ @\exposid{result}@{}; // \expos - @\exposid{state-list-type}@ @\exposid{waiting_states}@; // \expos - atomic @\exposid{completed}@{false}; // \expos - atomic @\exposid{ref_count}@{1}; // \expos - connect_result_t> @\exposid{op_state}@; // \expos - }; -} -\end{codeblock} - -\pnum -Let \tcode{Sigs} be a pack of the arguments -to the \tcode{completion_signatures} specialization -named by \tcode{completion_signatures_of_t}. -For type \tcode{Tag} and pack \tcode{Args}, -let \exposid{as-tuple} be an alias template -such that \tcode{\exposid{as-tuple}} denotes -the type \tcode{\exposid{decayed-tuple}}. -Then \exposid{variant-type} denotes the type -\begin{codeblock} -variant, tuple, @\exposid{as-tuple}@...> -\end{codeblock} -but with duplicate types removed. - -\pnum -Let \exposid{state-list-type} be a type -that stores a list of pointers to \exposid{local-state-base} objects and -that permits atomic insertion. - -\begin{itemdecl} -explicit @\exposid{shared-state}@(Sndr&& sndr); -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Initializes \exposid{op_state} with the result of -\tcode{connect(std::forward(sndr), \exposid{split-re\-ceiver}\{this\})}. - -\pnum -\ensures -\exposid{waiting_states} is empty, and \exposid{completed} is \tcode{false}. -\end{itemdescr} - -\begin{itemdecl} -void @\exposid{start-op}@() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Evaluates \tcode{\exposid{inc-ref}()}. -If \tcode{stop_src.stop_requested()} is \tcode{true}, -evaluates \tcode{\exposid{notify}()}; -otherwise, evaluates \tcode{start(\exposid{op_state})}. -\end{itemdescr} - -\begin{itemdecl} -void @\exposid{notify}@() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Atomically does the following: -\begin{itemize} -\item -Sets \tcode{completed} to \tcode{true}, and -\item -Exchanges \tcode{waiting_states} with an empty list, -storing the old value in a local \tcode{prior_states}. -\end{itemize} -Then, for each pointer \tcode{p} in \tcode{prior_states}, -evaluates \tcode{p->\exposid{notify}()}. -Finally, evaluates \tcode{\exposid{dec-ref}()}. -\end{itemdescr} - -\begin{itemdecl} -void @\exposid{inc-ref}@() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Increments \exposid{ref_count}. -\end{itemdescr} - -\begin{itemdecl} -void @\exposid{dec-ref}@() noexcept; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\effects -Decrements \exposid{ref_count}. -If the new value of \exposid{ref_count} is \tcode{0}, -calls \tcode{delete this}. - -\pnum -\sync -If an evaluation of \tcode{\exposid{dec-ref}()} does not -decrement the \tcode{ref_count} to \tcode{0} then -synchronizes with the evaluation of \tcode{dec-ref()} -that decrements \tcode{ref_count} to \tcode{0}. -\end{itemdescr} - -\pnum -Let \exposid{split-impl-tag} be an empty exposition-only class type. -Given an expression \tcode{sndr}, -the expression \tcode{split.transform_sender(sndr)} is equivalent to: -\begin{codeblock} -auto&& [tag, _, child] = sndr; -auto* sh_state = new @\exposid{shared-state}@{std::forward_like(child)}; -return @\exposid{make-sender}@(@\exposid{split-impl-tag}@(), @\exposid{shared-wrapper}@{sh_state, tag}); -\end{codeblock} -where \exposid{shared-wrapper} is an exposition-only class -that manages the reference count of the \exposid{shared-state} object -pointed to by sh_state. -\exposid{shared-wrapper} models \libconcept{copyable} -with move operations nulling out the moved-from object, -copy operations incrementing the reference count -by calling \tcode{sh_state->\exposid{inc-ref}()}, and -assignment operations performing a copy-and-swap operation. -The destructor has no effect if sh_state is null; -otherwise, it decrements the reference count -by evaluating \tcode{sh_state->\exposid{dec-ref}()}. - -\pnum -The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} -is specialized for \exposid{split-impl-tag} as follows: -\begin{codeblock} -namespace std::execution { - template<> - struct @\exposid{impls-for}@<@\exposid{split-impl-tag}@> : @\exposid{default-impls}@ { - static constexpr auto @\exposid{get-state}@ = @\seebelow@; - static constexpr auto @\exposid{start}@ = @\seebelow@; - }; -} -\end{codeblock} - -\pnum -The member -\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{get-state}} -is initialized with a callable object equivalent to -the following lambda expression: -\begin{codeblock} -[](Sndr&& sndr, auto& rcvr) noexcept { - return @\exposid{local-state}@{std::forward(sndr), rcvr}; -} -\end{codeblock} - -\pnum -The member -\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{start}} -is initialized with a callable object -that has a function call operator equivalent to the following: -\begin{codeblock} -template -void operator()(@\exposid{local-state}@& state, Rcvr& rcvr) const noexcept; -\end{codeblock} - -\effects -If \tcode{state.\exposid{sh_state}->\exposid{completed}} is \tcode{true}, -evaluates \tcode{state.\exposid{notify}()} and returns. -Otherwise, does the following in order: -\begin{itemize} -\item -Evaluates -\begin{codeblock} -state.@\exposid{on_stop}@.emplace( - get_stop_token(get_env(rcvr)), - @\exposid{on-stop-request}@{state.@\exposid{sh_state}@->@\exposid{stop_src}@}); -\end{codeblock} -\item -Then atomically does the following: -\begin{itemize} -\item -Reads the value \tcode{c} of -\tcode{state.\exposid{sh_state}->\exposid{completed}}, and -\item -Inserts \tcode{addressof(state)} into -\tcode{state.\exposid{sh_state}->\exposid{waiting_states}} -if \tcode{c} is \tcode{false}. -\end{itemize} -\item -If \tcode{c} is \tcode{true}, -calls \tcode{state.\exposid{notify}()} and returns. -\item -Otherwise, -if \tcode{addressof(state)} is the first item added to -\tcode{state.\exposid{sh_state}->\exposid{waiting_states}}, -evaluates \tcode{state.\exposid{sh_state}->\exposid{start-op}()}. -\end{itemize} - \rSec3[exec.when.all]{\tcode{execution::when_all}} \pnum