|
633 | 633 | struct @\libglobal{bulk_t}@ { @\unspec@ }; |
634 | 634 | struct @\libglobal{bulk_chunked_t}@ { @\unspec@ }; |
635 | 635 | struct @\libglobal{bulk_unchunked_t}@ { @\unspec@ }; |
636 | | - struct @\libglobal{split_t}@ { @\unspec@ }; |
637 | 636 | struct @\libglobal{when_all_t}@ { @\unspec@ }; |
638 | 637 | struct @\libglobal{when_all_with_variant_t}@ { @\unspec@ }; |
639 | 638 | struct @\libglobal{into_variant_t}@ { @\unspec@ }; |
|
655 | 654 | inline constexpr bulk_t @\libglobal{bulk}@{}; |
656 | 655 | inline constexpr bulk_chunked_t @\libglobal{bulk_chunked}@{}; |
657 | 656 | inline constexpr bulk_unchunked_t @\libglobal{bulk_unchunked}@{}; |
658 | | - inline constexpr split_t @\libglobal{split}@{}; |
659 | 657 | inline constexpr when_all_t @\libglobal{when_all}@{}; |
660 | 658 | inline constexpr when_all_with_variant_t @\libglobal{when_all_with_variant}@{}; |
661 | 659 | inline constexpr into_variant_t @\libglobal{into_variant}@{}; |
|
3998 | 3996 | ignore cancellation requests. |
3999 | 3997 | \end{note} |
4000 | 3998 |
|
4001 | | -\rSec3[exec.split]{\tcode{execution::split}} |
4002 | | - |
4003 | | -\pnum |
4004 | | -\tcode{split} adapts an arbitrary sender |
4005 | | -into a sender that can be connected multiple times. |
4006 | | - |
4007 | | -\pnum |
4008 | | -Let \exposid{split-env} be the type of an environment |
4009 | | -such that, given an instance \tcode{env}, |
4010 | | -the expression \tcode{get_stop_token(env)} is well-formed and |
4011 | | -has type \tcode{inplace_stop_token.} |
4012 | | - |
4013 | | -\pnum |
4014 | | -The name \tcode{split} denotes a pipeable sender adaptor object. |
4015 | | -For a subexpression \tcode{sndr}, let \tcode{Sndr} be \tcode{decltype((sndr))}. |
4016 | | -If \tcode{\libconcept{sender_in}<Sndr, \exposid{split-env}>} is \tcode{false}, |
4017 | | -\tcode{split(sndr)} is ill-formed. |
4018 | | - |
4019 | | -\pnum |
4020 | | -Otherwise, the expression \tcode{split(sndr)} is expression-equivalent to: |
4021 | | -\begin{codeblock} |
4022 | | -transform_sender(@\exposid{get-domain-early}@(sndr), @\exposid{make-sender}@(split, {}, sndr)) |
4023 | | -\end{codeblock} |
4024 | | -except that \tcode{sndr} is evaluated only once. |
4025 | | -\begin{note} |
4026 | | -The default implementation of \tcode{transform_sender} |
4027 | | -will have the effect of connecting the sender to a receiver. |
4028 | | -It will return a sender with a different tag type. |
4029 | | -\end{note} |
4030 | | - |
4031 | | -\pnum |
4032 | | -Let \exposid{local-state} denote the following exposition-only class template: |
4033 | | - |
4034 | | -\begin{codeblock} |
4035 | | -namespace std::execution { |
4036 | | - struct @\exposid{local-state-base}@ { // \expos |
4037 | | - virtual ~@\exposid{local-state-base}@() = default; |
4038 | | - virtual void @\exposid{notify}@() noexcept = 0; // \expos |
4039 | | - }; |
4040 | | - |
4041 | | - template<class Sndr, class Rcvr> |
4042 | | - struct @\exposid{local-state}@ : @\exposid{local-state-base}@ { // \expos |
4043 | | - using @\exposid{on-stop-callback}@ = // \expos |
4044 | | - stop_callback_for_t<stop_token_of_t<env_of_t<Rcvr>>, @\exposid{on-stop-request}@>; |
4045 | | - |
4046 | | - @\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; |
4047 | | - ~@\exposid{local-state}@(); |
4048 | | - |
4049 | | - void @\exposid{notify}@() noexcept override; |
4050 | | - |
4051 | | - private: |
4052 | | - optional<@\exposid{on-stop-callback}@> @\exposid{on_stop}@; // \expos |
4053 | | - @\exposid{shared-state}@<Sndr>* @\exposid{sh_state}@; // \expos |
4054 | | - Rcvr* @\exposid{rcvr}@; // \expos |
4055 | | - }; |
4056 | | -} |
4057 | | -\end{codeblock} |
4058 | | - |
4059 | | -\begin{itemdecl} |
4060 | | -@\exposid{local-state}@(Sndr&& sndr, Rcvr& rcvr) noexcept; |
4061 | | -\end{itemdecl} |
4062 | | - |
4063 | | -\begin{itemdescr} |
4064 | | -\pnum |
4065 | | -\effects |
4066 | | -Equivalent to: |
4067 | | -\begin{codeblock} |
4068 | | -auto& [_, data, _] = sndr; |
4069 | | -this->@\exposid{sh_state}@ = data.sh_state.get(); |
4070 | | -this->@\exposid{sh_state}@->@\exposid{inc-ref}@(); |
4071 | | -this->@\exposid{rcvr}@ = addressof(rcvr); |
4072 | | -\end{codeblock} |
4073 | | -\end{itemdescr} |
4074 | | - |
4075 | | -\begin{itemdecl} |
4076 | | -~@\exposid{local-state}@(); |
4077 | | -\end{itemdecl} |
4078 | | - |
4079 | | -\begin{itemdescr} |
4080 | | -\pnum |
4081 | | -\effects |
4082 | | -Equivalent to: |
4083 | | -\begin{codeblock} |
4084 | | -sh_state->@\exposid{dec-ref}@(); |
4085 | | -\end{codeblock} |
4086 | | -\end{itemdescr} |
4087 | | - |
4088 | | -\begin{itemdecl} |
4089 | | -void @\exposid{notify}@() noexcept override; |
4090 | | -\end{itemdecl} |
4091 | | - |
4092 | | -\begin{itemdescr} |
4093 | | -\pnum |
4094 | | -\effects |
4095 | | -Equivalent to: |
4096 | | -\begin{codeblock} |
4097 | | -@\exposid{on_stop}@.reset(); |
4098 | | -visit( |
4099 | | - [this](const auto& tupl) noexcept -> void { |
4100 | | - apply( |
4101 | | - [this](auto tag, const auto&... args) noexcept -> void { |
4102 | | - tag(std::move(*@\exposid{rcvr}@), args...); |
4103 | | - }, |
4104 | | - tupl); |
4105 | | - }, |
4106 | | - @\exposid{sh_state}@->result); |
4107 | | -\end{codeblock} |
4108 | | -\end{itemdescr} |
4109 | | - |
4110 | | -\pnum |
4111 | | -Let \exposid{split-receiver} denote |
4112 | | -the following exposition-only class template: |
4113 | | -\begin{codeblock} |
4114 | | -namespace std::execution { |
4115 | | - template<class Sndr> |
4116 | | - struct @\exposid{split-receiver}@ { // \expos |
4117 | | - using receiver_concept = receiver_t; |
4118 | | - |
4119 | | - template<class Tag, class... Args> |
4120 | | - void @\exposid{complete}@(Tag, Args&&... args) noexcept { // \expos |
4121 | | - using tuple_t = @\exposid{decayed-tuple}@<Tag, Args...>; |
4122 | | - try { |
4123 | | - @\exposid{sh_state}@->result.template emplace<tuple_t>(Tag(), std::forward<Args>(args)...); |
4124 | | - } catch (...) { |
4125 | | - using tuple_t = tuple<set_error_t, exception_ptr>; |
4126 | | - @\exposid{sh_state}@->result.template emplace<tuple_t>(set_error, current_exception()); |
4127 | | - } |
4128 | | - @\exposid{sh_state}@->notify(); |
4129 | | - } |
4130 | | - |
4131 | | - template<class... Args> |
4132 | | - void set_value(Args&&... args) && noexcept { |
4133 | | - @\exposid{complete}@(execution::set_value, std::forward<Args>(args)...); |
4134 | | - } |
4135 | | - |
4136 | | - template<class Error> |
4137 | | - void set_error(Error&& err) && noexcept { |
4138 | | - @\exposid{complete}@(execution::set_error, std::forward<Error>(err)); |
4139 | | - } |
4140 | | - |
4141 | | - void set_stopped() && noexcept { |
4142 | | - @\exposid{complete}@(execution::set_stopped); |
4143 | | - } |
4144 | | - |
4145 | | - struct @\exposid{env}@ { // \expos |
4146 | | - @\exposid{shared-state}@<Sndr>* @\exposid{sh-state}@; // \expos |
4147 | | - |
4148 | | - inplace_stop_token query(get_stop_token_t) const noexcept { |
4149 | | - return @\exposid{sh-state}@->stop_src.get_token(); |
4150 | | - } |
4151 | | - }; |
4152 | | - |
4153 | | - @\exposid{env}@ get_env() const noexcept { |
4154 | | - return @\exposid{env}@{@\exposid{sh_state}@}; |
4155 | | - } |
4156 | | - |
4157 | | - @\exposid{shared-state}@<Sndr>* @\exposid{sh_state}@; // \expos |
4158 | | - }; |
4159 | | -} |
4160 | | -\end{codeblock} |
4161 | | - |
4162 | | -\pnum |
4163 | | -Let \exposid{shared-state} denote the following exposition-only class template: |
4164 | | -\begin{codeblock} |
4165 | | -namespace std::execution { |
4166 | | - template<class Sndr> |
4167 | | - struct @\exposid{shared-state}@ { |
4168 | | - using @\exposid{variant-type}@ = @\seebelow@; // \expos |
4169 | | - using @\exposid{state-list-type}@ = @\seebelow@; // \expos |
4170 | | - |
4171 | | - explicit @\exposid{shared-state}@(Sndr&& sndr); |
4172 | | - |
4173 | | - void @\exposid{start-op}@() noexcept; // \expos |
4174 | | - void @\exposid{notify}@() noexcept; // \expos |
4175 | | - void @\exposid{inc-ref}@() noexcept; // \expos |
4176 | | - void @\exposid{dec-ref}@() noexcept; // \expos |
4177 | | - |
4178 | | - inplace_stop_source @\exposid{stop_src}@{}; // \expos |
4179 | | - @\exposid{variant-type}@ @\exposid{result}@{}; // \expos |
4180 | | - @\exposid{state-list-type}@ @\exposid{waiting_states}@; // \expos |
4181 | | - atomic<bool> @\exposid{completed}@{false}; // \expos |
4182 | | - atomic<size_t> @\exposid{ref_count}@{1}; // \expos |
4183 | | - connect_result_t<Sndr, @\exposid{split-receiver}@<Sndr>> @\exposid{op_state}@; // \expos |
4184 | | - }; |
4185 | | -} |
4186 | | -\end{codeblock} |
4187 | | - |
4188 | | -\pnum |
4189 | | -Let \tcode{Sigs} be a pack of the arguments |
4190 | | -to the \tcode{completion_signatures} specialization |
4191 | | -named by \tcode{completion_signatures_of_t<Sndr>}. |
4192 | | -For type \tcode{Tag} and pack \tcode{Args}, |
4193 | | -let \exposid{as-tuple} be an alias template |
4194 | | -such that \tcode{\exposid{as-tuple}<Tag(Args...)>} denotes |
4195 | | -the type \tcode{\exposid{decayed-tuple}<Tag, Args...>}. |
4196 | | -Then \exposid{variant-type} denotes the type |
4197 | | -\begin{codeblock} |
4198 | | -variant<tuple<set_stopped_t>, tuple<set_error_t, exception_ptr>, @\exposid{as-tuple}@<Sigs>...> |
4199 | | -\end{codeblock} |
4200 | | -but with duplicate types removed. |
4201 | | - |
4202 | | -\pnum |
4203 | | -Let \exposid{state-list-type} be a type |
4204 | | -that stores a list of pointers to \exposid{local-state-base} objects and |
4205 | | -that permits atomic insertion. |
4206 | | - |
4207 | | -\begin{itemdecl} |
4208 | | -explicit @\exposid{shared-state}@(Sndr&& sndr); |
4209 | | -\end{itemdecl} |
4210 | | - |
4211 | | -\begin{itemdescr} |
4212 | | -\pnum |
4213 | | -\effects |
4214 | | -Initializes \exposid{op_state} with the result of |
4215 | | -\tcode{connect(std::forward<Sndr>(sndr), \exposid{split-re\-ceiver}\{this\})}. |
4216 | | - |
4217 | | -\pnum |
4218 | | -\ensures |
4219 | | -\exposid{waiting_states} is empty, and \exposid{completed} is \tcode{false}. |
4220 | | -\end{itemdescr} |
4221 | | - |
4222 | | -\begin{itemdecl} |
4223 | | -void @\exposid{start-op}@() noexcept; |
4224 | | -\end{itemdecl} |
4225 | | - |
4226 | | -\begin{itemdescr} |
4227 | | -\pnum |
4228 | | -\effects |
4229 | | -Evaluates \tcode{\exposid{inc-ref}()}. |
4230 | | -If \tcode{stop_src.stop_requested()} is \tcode{true}, |
4231 | | -evaluates \tcode{\exposid{notify}()}; |
4232 | | -otherwise, evaluates \tcode{start(\exposid{op_state})}. |
4233 | | -\end{itemdescr} |
4234 | | - |
4235 | | -\begin{itemdecl} |
4236 | | -void @\exposid{notify}@() noexcept; |
4237 | | -\end{itemdecl} |
4238 | | - |
4239 | | -\begin{itemdescr} |
4240 | | -\pnum |
4241 | | -\effects |
4242 | | -Atomically does the following: |
4243 | | -\begin{itemize} |
4244 | | -\item |
4245 | | -Sets \tcode{completed} to \tcode{true}, and |
4246 | | -\item |
4247 | | -Exchanges \tcode{waiting_states} with an empty list, |
4248 | | -storing the old value in a local \tcode{prior_states}. |
4249 | | -\end{itemize} |
4250 | | -Then, for each pointer \tcode{p} in \tcode{prior_states}, |
4251 | | -evaluates \tcode{p->\exposid{notify}()}. |
4252 | | -Finally, evaluates \tcode{\exposid{dec-ref}()}. |
4253 | | -\end{itemdescr} |
4254 | | - |
4255 | | -\begin{itemdecl} |
4256 | | -void @\exposid{inc-ref}@() noexcept; |
4257 | | -\end{itemdecl} |
4258 | | - |
4259 | | -\begin{itemdescr} |
4260 | | -\pnum |
4261 | | -\effects |
4262 | | -Increments \exposid{ref_count}. |
4263 | | -\end{itemdescr} |
4264 | | - |
4265 | | -\begin{itemdecl} |
4266 | | -void @\exposid{dec-ref}@() noexcept; |
4267 | | -\end{itemdecl} |
4268 | | - |
4269 | | -\begin{itemdescr} |
4270 | | -\pnum |
4271 | | -\effects |
4272 | | -Decrements \exposid{ref_count}. |
4273 | | -If the new value of \exposid{ref_count} is \tcode{0}, |
4274 | | -calls \tcode{delete this}. |
4275 | | - |
4276 | | -\pnum |
4277 | | -\sync |
4278 | | -If an evaluation of \tcode{\exposid{dec-ref}()} does not |
4279 | | -decrement the \tcode{ref_count} to \tcode{0} then |
4280 | | -synchronizes with the evaluation of \tcode{dec-ref()} |
4281 | | -that decrements \tcode{ref_count} to \tcode{0}. |
4282 | | -\end{itemdescr} |
4283 | | - |
4284 | | -\pnum |
4285 | | -Let \exposid{split-impl-tag} be an empty exposition-only class type. |
4286 | | -Given an expression \tcode{sndr}, |
4287 | | -the expression \tcode{split.transform_sender(sndr)} is equivalent to: |
4288 | | -\begin{codeblock} |
4289 | | -auto&& [tag, _, child] = sndr; |
4290 | | -auto* sh_state = new @\exposid{shared-state}@{std::forward_like<decltype((sndr))>(child)}; |
4291 | | -return @\exposid{make-sender}@(@\exposid{split-impl-tag}@(), @\exposid{shared-wrapper}@{sh_state, tag}); |
4292 | | -\end{codeblock} |
4293 | | -where \exposid{shared-wrapper} is an exposition-only class |
4294 | | -that manages the reference count of the \exposid{shared-state} object |
4295 | | -pointed to by sh_state. |
4296 | | -\exposid{shared-wrapper} models \libconcept{copyable} |
4297 | | -with move operations nulling out the moved-from object, |
4298 | | -copy operations incrementing the reference count |
4299 | | -by calling \tcode{sh_state->\exposid{inc-ref}()}, and |
4300 | | -assignment operations performing a copy-and-swap operation. |
4301 | | -The destructor has no effect if sh_state is null; |
4302 | | -otherwise, it decrements the reference count |
4303 | | -by evaluating \tcode{sh_state->\exposid{dec-ref}()}. |
4304 | | - |
4305 | | -\pnum |
4306 | | -The exposition-only class template \exposid{impls-for}\iref{exec.snd.general} |
4307 | | -is specialized for \exposid{split-impl-tag} as follows: |
4308 | | -\begin{codeblock} |
4309 | | -namespace std::execution { |
4310 | | - template<> |
4311 | | - struct @\exposid{impls-for}@<@\exposid{split-impl-tag}@> : @\exposid{default-impls}@ { |
4312 | | - static constexpr auto @\exposid{get-state}@ = @\seebelow@; |
4313 | | - static constexpr auto @\exposid{start}@ = @\seebelow@; |
4314 | | - }; |
4315 | | -} |
4316 | | -\end{codeblock} |
4317 | | - |
4318 | | -\pnum |
4319 | | -The member |
4320 | | -\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{get-state}} |
4321 | | -is initialized with a callable object equivalent to |
4322 | | -the following lambda expression: |
4323 | | -\begin{codeblock} |
4324 | | -[]<class Sndr>(Sndr&& sndr, auto& rcvr) noexcept { |
4325 | | - return @\exposid{local-state}@{std::forward<Sndr>(sndr), rcvr}; |
4326 | | -} |
4327 | | -\end{codeblock} |
4328 | | - |
4329 | | -\pnum |
4330 | | -The member |
4331 | | -\tcode{\exposid{impls-for}<\exposid{split-impl-tag}>::\exposid{start}} |
4332 | | -is initialized with a callable object |
4333 | | -that has a function call operator equivalent to the following: |
4334 | | -\begin{codeblock} |
4335 | | -template<class Sndr, class Rcvr> |
4336 | | -void operator()(@\exposid{local-state}@<Sndr, Rcvr>& state, Rcvr& rcvr) const noexcept; |
4337 | | -\end{codeblock} |
4338 | | - |
4339 | | -\effects |
4340 | | -If \tcode{state.\exposid{sh_state}->\exposid{completed}} is \tcode{true}, |
4341 | | -evaluates \tcode{state.\exposid{notify}()} and returns. |
4342 | | -Otherwise, does the following in order: |
4343 | | -\begin{itemize} |
4344 | | -\item |
4345 | | -Evaluates |
4346 | | -\begin{codeblock} |
4347 | | -state.@\exposid{on_stop}@.emplace( |
4348 | | - get_stop_token(get_env(rcvr)), |
4349 | | - @\exposid{on-stop-request}@{state.@\exposid{sh_state}@->@\exposid{stop_src}@}); |
4350 | | -\end{codeblock} |
4351 | | -\item |
4352 | | -Then atomically does the following: |
4353 | | -\begin{itemize} |
4354 | | -\item |
4355 | | -Reads the value \tcode{c} of |
4356 | | -\tcode{state.\exposid{sh_state}->\exposid{completed}}, and |
4357 | | -\item |
4358 | | -Inserts \tcode{addressof(state)} into |
4359 | | -\tcode{state.\exposid{sh_state}->\exposid{waiting_states}} |
4360 | | -if \tcode{c} is \tcode{false}. |
4361 | | -\end{itemize} |
4362 | | -\item |
4363 | | -If \tcode{c} is \tcode{true}, |
4364 | | -calls \tcode{state.\exposid{notify}()} and returns. |
4365 | | -\item |
4366 | | -Otherwise, |
4367 | | -if \tcode{addressof(state)} is the first item added to |
4368 | | -\tcode{state.\exposid{sh_state}->\exposid{waiting_states}}, |
4369 | | -evaluates \tcode{state.\exposid{sh_state}->\exposid{start-op}()}. |
4370 | | -\end{itemize} |
4371 | | - |
4372 | 3999 | \rSec3[exec.when.all]{\tcode{execution::when_all}} |
4373 | 4000 |
|
4374 | 4001 | \pnum |
|
0 commit comments