1 /*
2  * Copyright (c) 2021-2022 NVIDIA Corporation
3  *
4  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5  * (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  *
8  *   https://llvm.org/LICENSE.txt
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include "__detail/__basic_sender.hpp"
19 #include "__detail/__config.hpp"
20 #include "__detail/__cpo.hpp"
21 #include "__detail/__domain.hpp"
22 #include "__detail/__env.hpp"
23 #include "__detail/__execution_fwd.hpp"
24 #include "__detail/__intrusive_ptr.hpp"
25 #include "__detail/__meta.hpp"
26 #include "__detail/__scope.hpp"
27 #include "__detail/__type_traits.hpp"
28 #include "__detail/__utility.hpp"
29 #include "concepts.hpp"
30 #include "coroutine.hpp"
31 #include "functional.hpp"
32 #include "stop_token.hpp"
33 
34 #include <atomic>
35 #include <cassert>
36 #include <concepts>
37 #include <condition_variable>
38 #include <cstddef>
39 #include <exception>
40 #include <memory>
41 #include <mutex>
42 #include <optional>
43 #include <stdexcept>
44 #include <system_error>
45 #include <tuple>
46 #include <type_traits>
47 #include <utility>
48 #include <variant>
49 
50 STDEXEC_PRAGMA_PUSH()
51 STDEXEC_PRAGMA_IGNORE_GNU("-Wundefined-inline")
52 STDEXEC_PRAGMA_IGNORE_GNU("-Wsubobject-linkage")
53 STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
54 
55 STDEXEC_PRAGMA_IGNORE_EDG(1302)
56 STDEXEC_PRAGMA_IGNORE_EDG(497)
57 STDEXEC_PRAGMA_IGNORE_EDG(type_qualifiers_ignored_on_reference)
58 
59 namespace stdexec
60 {
61 /////////////////////////////////////////////////////////////////////////////
62 template <class _Sender, class _Scheduler, class _Tag = set_value_t>
63 concept __completes_on = __decays_to<
64     __call_result_t<get_completion_scheduler_t<_Tag>, env_of_t<_Sender>>,
65     _Scheduler>;
66 
67 /////////////////////////////////////////////////////////////////////////////
68 template <class _Sender, class _Scheduler, class _Env>
69 concept __starts_on =
70     __decays_to<__call_result_t<get_scheduler_t, _Env>, _Scheduler>;
71 
72 /////////////////////////////////////////////////////////////////////////////
73 // [execution.receivers]
74 namespace __receivers
75 {
76 struct set_value_t
77 {
78     template <class _Fn, class... _Args>
79     using __f = __minvoke<_Fn, _Args...>;
80 
81     template <class _Receiver, class... _As>
82         requires tag_invocable<set_value_t, _Receiver, _As...>
83     STDEXEC_ATTRIBUTE((host, device, always_inline)) void
operator ()stdexec::__receivers::set_value_t84         operator()(_Receiver&& __rcvr, _As&&... __as) const noexcept
85     {
86         static_assert(nothrow_tag_invocable<set_value_t, _Receiver, _As...>);
87         (void)tag_invoke(set_value_t{}, static_cast<_Receiver&&>(__rcvr),
88                          static_cast<_As&&>(__as)...);
89     }
90 };
91 
92 struct set_error_t
93 {
94     template <class _Fn, class... _Args>
95         requires(sizeof...(_Args) == 1)
96     using __f = __minvoke<_Fn, _Args...>;
97 
98     template <class _Receiver, class _Error>
99         requires tag_invocable<set_error_t, _Receiver, _Error>
100     STDEXEC_ATTRIBUTE((host, device, always_inline)) void
operator ()stdexec::__receivers::set_error_t101         operator()(_Receiver&& __rcvr, _Error&& __err) const noexcept
102     {
103         static_assert(nothrow_tag_invocable<set_error_t, _Receiver, _Error>);
104         (void)tag_invoke(set_error_t{}, static_cast<_Receiver&&>(__rcvr),
105                          static_cast<_Error&&>(__err));
106     }
107 };
108 
109 struct set_stopped_t
110 {
111     template <class _Fn, class... _Args>
112         requires(sizeof...(_Args) == 0)
113     using __f = __minvoke<_Fn, _Args...>;
114 
115     template <class _Receiver>
116         requires tag_invocable<set_stopped_t, _Receiver>
117     STDEXEC_ATTRIBUTE((host, device, always_inline)) void
operator ()stdexec::__receivers::set_stopped_t118         operator()(_Receiver&& __rcvr) const noexcept
119     {
120         static_assert(nothrow_tag_invocable<set_stopped_t, _Receiver>);
121         (void)tag_invoke(set_stopped_t{}, static_cast<_Receiver&&>(__rcvr));
122     }
123 };
124 } // namespace __receivers
125 
126 using __receivers::set_error_t;
127 using __receivers::set_stopped_t;
128 using __receivers::set_value_t;
129 inline constexpr set_value_t set_value{};
130 inline constexpr set_error_t set_error{};
131 inline constexpr set_stopped_t set_stopped{};
132 
133 inline constexpr struct __try_call_t
134 {
135     template <class _Receiver, class _Fun, class... _Args>
136         requires __callable<_Fun, _Args...>
operator ()stdexec::__try_call_t137     void operator()(_Receiver&& __rcvr, _Fun __fun,
138                     _Args&&... __args) const noexcept
139     {
140         if constexpr (__nothrow_callable<_Fun, _Args...>)
141         {
142             static_cast<_Fun&&>(__fun)(static_cast<_Args&&>(__args)...);
143         }
144         else
145         {
146             try
147             {
148                 static_cast<_Fun&&>(__fun)(static_cast<_Args&&>(__args)...);
149             }
150             catch (...)
151             {
152                 set_error(static_cast<_Receiver&&>(__rcvr),
153                           std::current_exception());
154             }
155         }
156     }
157 } __try_call{};
158 
159 namespace __error__
160 {
161 inline constexpr __mstring __unrecognized_sender_type_diagnostic =
162     "The given type cannot be used as a sender with the given environment "
163     "because the attempt to compute the completion signatures failed."_mstr;
164 
165 template <__mstring _Diagnostic = __unrecognized_sender_type_diagnostic>
166 struct _UNRECOGNIZED_SENDER_TYPE_;
167 
168 template <class _Sender>
169 struct _WITH_SENDER_;
170 
171 template <class... _Senders>
172 struct _WITH_SENDERS_;
173 
174 template <class _Env>
175 struct _WITH_ENVIRONMENT_;
176 
177 template <class _Ty>
178 struct _WITH_TYPE_;
179 
180 template <class _Receiver>
181 struct _WITH_RECEIVER_;
182 
183 template <class _Sig>
184 struct _MISSING_COMPLETION_SIGNAL_;
185 } // namespace __error__
186 
187 using __error__::_MISSING_COMPLETION_SIGNAL_;
188 using __error__::_UNRECOGNIZED_SENDER_TYPE_;
189 using __error__::_WITH_ENVIRONMENT_;
190 using __error__::_WITH_RECEIVER_;
191 using __error__::_WITH_TYPE_;
192 
193 template <class _Sender>
194 using _WITH_SENDER_ = __error__::_WITH_SENDER_<__name_of<_Sender>>;
195 
196 template <class... _Senders>
197 using _WITH_SENDERS_ = __error__::_WITH_SENDERS_<__name_of<_Senders>...>;
198 
199 /////////////////////////////////////////////////////////////////////////////
200 // completion_signatures
201 namespace __compl_sigs
202 {
203 template <class _Sig>
204 inline constexpr bool __is_compl_sig = false;
205 template <class... _Args>
206 inline constexpr bool __is_compl_sig<set_value_t(_Args...)> = true;
207 template <class _Error>
208 inline constexpr bool __is_compl_sig<set_error_t(_Error)> = true;
209 template <>
210 inline constexpr bool __is_compl_sig<set_stopped_t()> = true;
211 } // namespace __compl_sigs
212 
213 template <class _Sig>
214 concept __completion_signature = __compl_sigs::__is_compl_sig<_Sig>;
215 
216 template <__completion_signature... _Sigs>
217 struct completion_signatures
218 {};
219 
220 namespace __compl_sigs
221 {
222 template <class _TaggedTuple, class _Tag, class... _Ts>
223 auto __as_tagged_tuple_(_Tag (*)(_Ts...), _TaggedTuple*)
224     -> __mconst<__minvoke<_TaggedTuple, _Tag, _Ts...>>;
225 
226 template <class _Sig, class _TaggedTuple>
227 using __as_tagged_tuple = decltype(__compl_sigs::__as_tagged_tuple_(
228     static_cast<_Sig*>(nullptr), static_cast<_TaggedTuple*>(nullptr)));
229 
230 template <class _TaggedTuple, class _Variant, class... _Sigs>
231 auto __for_all_sigs_(completion_signatures<_Sigs...>*, _TaggedTuple*, _Variant*)
232     -> __mconst<__minvoke<
233         _Variant, __minvoke<__as_tagged_tuple<_Sigs, _TaggedTuple>>...>>;
234 
235 template <class _Completions, class _TaggedTuple, class _Variant>
236 using __for_all_sigs =                          //
237     __minvoke<                                  //
238         decltype(__compl_sigs::__for_all_sigs_( //
239             static_cast<_Completions*>(nullptr),
240             static_cast<_TaggedTuple*>(nullptr),
241             static_cast<_Variant*>(nullptr)))>;
242 
243 template <class _Completions, class _TaggedTuple, class _Variant>
244 using __maybe_for_all_sigs =
245     __meval<__for_all_sigs, _Completions, _TaggedTuple, _Variant>;
246 } // namespace __compl_sigs
247 
248 template <class _Completions>
249 concept __valid_completion_signatures = //
250     __ok<_Completions> && __is_instance_of<_Completions, completion_signatures>;
251 
252 template <class _Completions>
253 using __invalid_completion_signatures_t = //
254     __mbool<!__valid_completion_signatures<_Completions>>;
255 
256 template <__mstring _Msg =
257               "Expected an instance of template completion_signatures<>"_mstr>
258 struct _INVALID_COMPLETION_SIGNATURES_TYPE_
259 {
260     template <class... _Completions>
261     using __f = //
262         __mexception<
263             _INVALID_COMPLETION_SIGNATURES_TYPE_<>,
264             __minvoke<__mfind_if<__q<__invalid_completion_signatures_t>,
265                                  __mcompose<__q<_WITH_TYPE_>, __q<__mfront>>>,
266                       _Completions...>>;
267 };
268 
269 template <class... _Completions>
270 using __concat_completion_signatures_impl_t = //
271     __minvoke<__if_c<(__valid_completion_signatures<_Completions> && ...),
272                      __mconcat<__munique<__q<completion_signatures>>>,
273                      _INVALID_COMPLETION_SIGNATURES_TYPE_<>>,
274               _Completions...>;
275 
276 template <class... _Completions>
277 struct __concat_completion_signatures_
278 {
279     using __t = __meval<__concat_completion_signatures_impl_t, _Completions...>;
280 };
281 
282 template <class... _Completions>
283 using __concat_completion_signatures_t =
284     __t<__concat_completion_signatures_<_Completions...>>;
285 
286 /////////////////////////////////////////////////////////////////////////////
287 // [execution.receivers]
288 template <class _Receiver, class _Tag, class... _Args>
289 auto __try_completion(_Tag (*)(_Args...))
290     -> __mexception<_MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>,
291                     _WITH_RECEIVER_<_Receiver>>;
292 
293 template <class _Receiver, class _Tag, class... _Args>
294     requires nothrow_tag_invocable<_Tag, _Receiver, _Args...>
295 auto __try_completion(_Tag (*)(_Args...)) -> __msuccess;
296 
297 template <class _Receiver, class... _Sigs>
298 auto __try_completions(completion_signatures<_Sigs...>*) -> decltype((
299     __msuccess(), ...,
300     stdexec::__try_completion<_Receiver>(static_cast<_Sigs*>(nullptr))));
301 
302 template <class _Sender, class _Env>
303 using __unrecognized_sender_error = //
304     __mexception<_UNRECOGNIZED_SENDER_TYPE_<>, _WITH_SENDER_<_Sender>,
305                  _WITH_ENVIRONMENT_<_Env>>;
306 
307 template <class _Sender, class _Env>
308 using __completion_signatures_of_t =
309     __call_result_t<get_completion_signatures_t, _Sender, _Env>;
310 
311 /////////////////////////////////////////////////////////////////////////////
312 // early sender type-checking
313 template <class _Sender>
314 concept __well_formed_sender = //
315     !__detail::__non_dependent_sender<_Sender> ||
316     __valid_completion_signatures<
317         __completion_signatures_of_t<_Sender, empty_env>>;
318 
319 /////////////////////////////////////////////////////////////////////////////
320 // [execution.receivers]
321 struct receiver_t
322 {
323     using receiver_concept = receiver_t; // NOT TO SPEC
324 };
325 
326 namespace __detail
327 {
328 template <class _Receiver>
329 concept __enable_receiver =                                              //
330     (STDEXEC_NVHPC(requires { typename _Receiver::receiver_concept; }&&) //
331      derived_from<typename _Receiver::receiver_concept, receiver_t>) ||
332     requires { typename _Receiver::is_receiver; } // back-compat, NOT TO SPEC
333     || STDEXEC_IS_BASE_OF(receiver_t,
334                           _Receiver); // NOT TO SPEC, for receiver_adaptor
335 } // namespace __detail
336 
337 template <class _Receiver>
338 inline constexpr bool enable_receiver =
339     __detail::__enable_receiver<_Receiver>; // NOT TO SPEC
340 
341 template <class _Receiver>
342 concept receiver = enable_receiver<__decay_t<_Receiver>> &&     //
343                    environment_provider<__cref_t<_Receiver>> && //
344                    move_constructible<__decay_t<_Receiver>> &&  //
345                    constructible_from<__decay_t<_Receiver>, _Receiver>;
346 
347 template <class _Receiver, class _Completions>
348 concept receiver_of =      //
349     receiver<_Receiver> && //
350     requires(_Completions* __completions) {
351         {
352             stdexec::__try_completions<__decay_t<_Receiver>>(__completions)
353         } -> __ok;
354     };
355 
356 template <class _Receiver, class _Sender>
357 concept __receiver_from =
358     receiver_of<_Receiver,
359                 __completion_signatures_of_t<_Sender, env_of_t<_Receiver>>>;
360 
361 /////////////////////////////////////////////////////////////////////////////
362 // Some utilities for debugging senders
363 namespace __debug
364 {
365 struct __is_debug_env_t
366 {
tag_invoke(forwarding_query_t,const __is_debug_env_t &)367     friend constexpr auto tag_invoke(forwarding_query_t,
368                                      const __is_debug_env_t&) noexcept -> bool
369     {
370         return true;
371     }
372     template <class _Env>
373         requires tag_invocable<__is_debug_env_t, const _Env&>
374     auto operator()(const _Env&) const noexcept
375         -> tag_invoke_result_t<__is_debug_env_t, const _Env&>;
376 };
377 template <class _Env>
378 using __debug_env_t =
379     __env::__join_t<__env::__with<bool, __is_debug_env_t>, _Env>;
380 
381 template <class _Env>
382 concept __is_debug_env = tag_invocable<__debug::__is_debug_env_t, _Env>;
383 
384 struct __completion_signatures
385 {};
386 
387 #if STDEXEC_MSVC()
388 // MSVCBUG
389 // https://developercommunity.visualstudio.com/t/Explicit-variable-template-specialisatio/10360032
390 // MSVCBUG
391 // https://developercommunity.visualstudio.com/t/Non-function-type-interpreted-as-functio/10447831
392 
393 template <class _Sig>
394 struct __normalize_sig;
395 
396 template <class _Tag, class... _Args>
397 struct __normalize_sig<_Tag(_Args...)>
398 {
399     using __type = _Tag (*)(_Args&&...);
400 };
401 
402 template <class _Sig>
403 using __normalize_sig_t = typename __normalize_sig<_Sig>::__type;
404 #else
405 template <class _Sig>
406 extern int __normalize_sig;
407 
408 template <class _Tag, class... _Args>
409 extern _Tag (*__normalize_sig<_Tag(_Args...)>)(_Args&&...);
410 
411 template <class _Sig>
412 using __normalize_sig_t = decltype(__normalize_sig<_Sig>);
413 #endif
414 
415 template <class... _Sigs>
416 struct __valid_completions
417 {
418     template <derived_from<__valid_completions> _Self, class _Tag,
419               class... _Args>
420         requires __one_of<_Tag (*)(_Args&&...), _Sigs...>
421     STDEXEC_ATTRIBUTE((host,
tag_invoke(_Tag,_Self &&,_Args &&...)422                        device)) friend void tag_invoke(_Tag, _Self&&,
423                                                        _Args&&...) noexcept
424     {
425         STDEXEC_TERMINATE();
426     }
427 };
428 
429 template <class _CvrefSenderId, class _Env, class _Completions>
430 struct __debug_receiver
431 {
432     using __t = __debug_receiver;
433     using __id = __debug_receiver;
434     using receiver_concept = receiver_t;
435 };
436 
437 template <class _CvrefSenderId, class _Env, class... _Sigs>
438 struct __debug_receiver<_CvrefSenderId, _Env,
439                         completion_signatures<_Sigs...>> //
440     : __valid_completions<__normalize_sig_t<_Sigs>...>
441 {
442     using __t = __debug_receiver;
443     using __id = __debug_receiver;
444     using receiver_concept = receiver_t;
445 
446     template <same_as<get_env_t> _Tag>
447     STDEXEC_ATTRIBUTE((host, device))
tag_invoke(_Tag,__debug_receiver)448     friend auto tag_invoke(_Tag, __debug_receiver) noexcept
449         -> __debug_env_t<_Env>
450     {
451         STDEXEC_TERMINATE();
452     }
453 };
454 
455 struct _COMPLETION_SIGNATURES_MISMATCH_
456 {};
457 
458 template <class _Sig>
459 struct _COMPLETION_SIGNATURE_
460 {};
461 
462 template <class... _Sigs>
463 struct _IS_NOT_ONE_OF_
464 {};
465 
466 template <class _Sender>
467 struct _SIGNAL_SENT_BY_SENDER_
468 {};
469 
470 template <class _Warning>
471 [[deprecated(
472     "The sender claims to send a particular set of completions,"
473     " but in actual fact it completes with a result that is not"
474     " one of the declared completion signatures.")]] STDEXEC_ATTRIBUTE((host,
_ATTENTION_()475                                                                         device)) void _ATTENTION_() noexcept
476 {}
477 
478 template <class _Sig>
479 struct __invalid_completion
480 {
481     struct __t
482     {
483         template <class _CvrefSenderId, class _Env, class... _Sigs>
484         // BUGBUG this works around a recently (aug 2023) introduced regression
485         // in nvc++
486             requires(!__one_of<_Sig, _Sigs...>)
__tstdexec::__debug::__invalid_completion::__t487         __t(__debug_receiver<_CvrefSenderId, _Env,
488                              completion_signatures<_Sigs...>>&&) noexcept
489         {
490             using _SenderId = __decay_t<_CvrefSenderId>;
491             using _Sender = stdexec::__t<_SenderId>;
492             using _What =  //
493                 _WARNING_< //
494                     _COMPLETION_SIGNATURES_MISMATCH_,
495                     _COMPLETION_SIGNATURE_<_Sig>, _IS_NOT_ONE_OF_<_Sigs...>,
496                     _SIGNAL_SENT_BY_SENDER_<__name_of<_Sender>>>;
497             __debug::_ATTENTION_<_What>();
498         }
499     };
500 };
501 
502 template <__completion_tag _Tag, class... _Args>
503 STDEXEC_ATTRIBUTE((host, device))
tag_invoke(_Tag,__t<__invalid_completion<_Tag (_Args...)>>,_Args &&...)504 void tag_invoke(_Tag, __t<__invalid_completion<_Tag(_Args...)>>,
505                 _Args&&...) noexcept
506 {}
507 
508 struct __debug_operation
509 {
510     template <same_as<start_t> _Tag>
tag_invoke(_Tag,__debug_operation &)511     friend void tag_invoke(_Tag, __debug_operation&) noexcept
512     {}
513 };
514 
515 ////////////////////////////////////////////////////////////////////////////
516 // `__debug_sender`
517 // ===============
518 //
519 // Understanding why a particular sender doesn't connect to a particular
520 // receiver is nigh impossible in the current design due to limitations in
521 // how the compiler reports overload resolution failure in the presence of
522 // constraints. `__debug_sender` is a utility to assist with the process. It
523 // gives you the deep template instantiation backtrace that you need to
524 // understand where in a chain of senders the problem is occurring.
525 //
526 // ```c++
527 // template <class _Sigs, class _Env = empty_env, class _Sender>
528 //   void __debug_sender(_Sender&& __sndr, _Env = {});
529 //
530 // template <class _Env = empty_env, class _Sender>
531 //   void __debug_sender(_Sender&& __sndr, _Env = {});
532 // ```
533 //
534 // **Usage:**
535 //
536 // To find out where in a chain of senders a sender is failing to connect
537 // to a receiver, pass it to `__debug_sender`, optionally with an
538 // environment argument; e.g. `__debug_sender(sndr [, env])`
539 //
540 // To find out why a sender will not connect to a receiver of a particular
541 // signature, specify the set of completion signatures as an explicit template
542 // argument that names an instantiation of `completion_signatures`; e.g.:
543 // `__debug_sender<completion_signatures<set_value_t(int)>>(sndr [, env])`.
544 //
545 // **How it works:**
546 //
547 // The `__debug_sender` function `connect`'s the sender to a
548 // `__debug_receiver`, whose environment is augmented with a special
549 // `__is_debug_env_t` query. An additional fall-back overload is added to
550 // the `connect` CPO that recognizes receivers whose environments respond to
551 // that query and lets them through. Then in a non-immediate context, it
552 // looks for a `tag_invoke(connect_t...)` overload for the input sender and
553 // receiver. This will recurse until it hits the `tag_invoke` call that is
554 // causing the failure.
555 //
556 // At least with clang, this gives me a nice backtrace, at the bottom of
557 // which is the faulty `tag_invoke` overload with a mention of the
558 // constraint that failed.
559 template <class _Sigs, class _Env = empty_env, class _Sender>
__debug_sender(_Sender && __sndr,const _Env &={})560 void __debug_sender(_Sender&& __sndr, const _Env& = {})
561 {
562     if constexpr (!__is_debug_env<_Env>)
563     {
564         if (sizeof(_Sender) == ~0u)
565         { // never true
566             using _Receiver =
567                 __debug_receiver<__cvref_id<_Sender>, _Env, _Sigs>;
568             using _Operation = connect_result_t<_Sender, _Receiver>;
569             // static_assert(receiver_of<_Receiver, _Sigs>);
570             if constexpr (!same_as<_Operation, __debug_operation>)
571             {
572                 auto __op = connect(static_cast<_Sender&&>(__sndr),
573                                     _Receiver{});
574                 start(__op);
575             }
576         }
577     }
578 }
579 
580 template <class _Env = empty_env, class _Sender>
__debug_sender(_Sender && __sndr,const _Env &={})581 void __debug_sender(_Sender&& __sndr, const _Env& = {})
582 {
583     if constexpr (!__is_debug_env<_Env>)
584     {
585         if (sizeof(_Sender) == ~0)
586         { // never true
587             using _Sigs =
588                 __completion_signatures_of_t<_Sender, __debug_env_t<_Env>>;
589             if constexpr (!same_as<_Sigs, __debug::__completion_signatures>)
590             {
591                 using _Receiver =
592                     __debug_receiver<__cvref_id<_Sender>, _Env, _Sigs>;
593                 using _Operation = connect_result_t<_Sender, _Receiver>;
594                 // static_assert(receiver_of<_Receiver, _Sigs>);
595                 if constexpr (!same_as<_Operation, __debug_operation>)
596                 {
597                     auto __op = connect(static_cast<_Sender&&>(__sndr),
598                                         _Receiver{});
599                     start(__op);
600                 }
601             }
602         }
603     }
604 }
605 } // namespace __debug
606 
607 using __debug::__debug_sender;
608 using __debug::__is_debug_env;
609 
610 /////////////////////////////////////////////////////////////////////////////
611 // dependent_domain
612 struct dependent_domain
613 {
614     template <sender_expr _Sender, class _Env>
615         requires same_as<__early_domain_of_t<_Sender>, dependent_domain>
616     STDEXEC_ATTRIBUTE((always_inline)) decltype(auto)
617         transform_sender(_Sender&& __sndr, const _Env& __env) const;
618 };
619 
620 /////////////////////////////////////////////////////////////////////////////
621 // [execution.transform_sender]
622 namespace __domain
623 {
624 struct __transform_env
625 {
626     template <class _Domain, class _Sender, class _Env>
627     STDEXEC_ATTRIBUTE((always_inline))
628     /*constexpr*/
operator ()stdexec::__domain::__transform_env629     decltype(auto) operator()(_Domain __dom, _Sender&& __sndr,
630                               _Env&& __env) const noexcept
631     {
632         if constexpr (__domain::__has_transform_env<_Domain, _Sender, _Env>)
633         {
634             return __dom.transform_env(static_cast<_Sender&&>(__sndr),
635                                        static_cast<_Env&&>(__env));
636         }
637         else
638         {
639             return default_domain().transform_env(
640                 static_cast<_Sender&&>(__sndr), static_cast<_Env&&>(__env));
641         }
642     }
643 };
644 
645 struct __transform_sender_1
646 {
647     template <class _Domain, class _Sender, class... _Env>
648     STDEXEC_ATTRIBUTE((always_inline))
649     /*constexpr*/
operator ()stdexec::__domain::__transform_sender_1650     decltype(auto) operator()(_Domain __dom, _Sender&& __sndr,
651                               const _Env&... __env) const
652     {
653         if constexpr (__domain::__has_transform_sender<_Domain, _Sender,
654                                                        _Env...>)
655         {
656             return __dom.transform_sender(static_cast<_Sender&&>(__sndr),
657                                           __env...);
658         }
659         else
660         {
661             return default_domain().transform_sender(
662                 static_cast<_Sender&&>(__sndr), __env...);
663         }
664     }
665 };
666 
667 template <class _Ty, class _Uy>
668 concept __decay_same_as = same_as<__decay_t<_Ty>, __decay_t<_Uy>>;
669 
670 struct __transform_sender
671 {
672     template <class _Self = __transform_sender, class _Domain, class _Sender,
673               class... _Env>
674     STDEXEC_ATTRIBUTE((always_inline))
675     /*constexpr*/
operator ()stdexec::__domain::__transform_sender676     decltype(auto) operator()(_Domain __dom, _Sender&& __sndr,
677                               const _Env&... __env) const
678     {
679         using _Sender2 = __call_result_t<__transform_sender_1, _Domain, _Sender,
680                                          const _Env&...>;
681         // If the transformation doesn't change the sender's type, then do not
682         // apply the transform recursively.
683         if constexpr (__decay_same_as<_Sender, _Sender2>)
684         {
685             return __transform_sender_1()(__dom, static_cast<_Sender&&>(__sndr),
686                                           __env...);
687         }
688         else
689         {
690             // We transformed the sender and got back a different sender.
691             // Transform that one too.
692             return _Self()(__dom,
693                            __transform_sender_1()(
694                                __dom, static_cast<_Sender&&>(__sndr), __env...),
695                            __env...);
696         }
697     }
698 };
699 
700 struct __transform_dependent_sender
701 {
702     // If we are doing a lazy customization of a type whose domain is
703     // value-dependent (e.g., let_value), first transform the sender to
704     // determine the domain. Then continue transforming the sender with the
705     // requested domain.
706     template <class _Domain, sender_expr _Sender, class _Env>
707         requires same_as<__early_domain_of_t<_Sender>, dependent_domain>
operator ()stdexec::__domain::__transform_dependent_sender708     /*constexpr*/ auto operator()(_Domain __dom, _Sender&& __sndr,
709                                   const _Env& __env) const -> decltype(auto)
710     {
711         static_assert(__none_of<_Domain, dependent_domain>);
712         return __transform_sender()(__dom,
713                                     dependent_domain().transform_sender(
714                                         static_cast<_Sender&&>(__sndr), __env),
715                                     __env);
716     }
717 };
718 } // namespace __domain
719 
720 /////////////////////////////////////////////////////////////////////////////
721 // [execution.transform_sender]
722 inline constexpr struct transform_sender_t :
723     __domain::__transform_sender,
724     __domain::__transform_dependent_sender
725 {
726     using __domain::__transform_sender::operator();
727     using __domain::__transform_dependent_sender::operator();
728 } transform_sender{};
729 
730 template <class _Domain, class _Sender, class... _Env>
731 using transform_sender_result_t =
732     __call_result_t<transform_sender_t, _Domain, _Sender, _Env...>;
733 
734 inline constexpr __domain::__transform_env transform_env{};
735 
736 struct _CHILD_SENDERS_WITH_DIFFERENT_DOMAINS_
737 {};
738 
739 template <sender_expr _Sender, class _Env>
740     requires same_as<__early_domain_of_t<_Sender>, dependent_domain>
transform_sender(_Sender && __sndr,const _Env & __env) const741 auto dependent_domain::transform_sender(_Sender&& __sndr,
742                                         const _Env& __env) const
743     -> decltype(auto)
744 {
745     // apply any algorithm-specific transformation to the environment
746     const auto& __env2 = transform_env(*this, static_cast<_Sender&&>(__sndr),
747                                        __env);
748 
749     // recursively transform the sender to determine the domain
750     return __sexpr_apply(static_cast<_Sender&&>(__sndr),
751                          [&]<class _Tag, class _Data, class... _Childs>(
752                              _Tag, _Data&& __data, _Childs&&... __childs) {
753         // TODO: propagate meta-exceptions here:
754         auto __sndr2 = __make_sexpr<_Tag>(
755             static_cast<_Data&&>(__data),
756             __domain::__transform_sender()(
757                 *this, static_cast<_Childs&&>(__childs), __env2)...);
758         using _Sender2 = decltype(__sndr2);
759 
760         auto __domain2 = __sexpr_apply(__sndr2, __domain::__common_domain_fn());
761         using _Domain2 = decltype(__domain2);
762 
763         if constexpr (same_as<_Domain2, __none_such>)
764         {
765             return __mexception<_CHILD_SENDERS_WITH_DIFFERENT_DOMAINS_,
766                                 _WITH_SENDER_<_Sender2>>();
767         }
768         else
769         {
770             return __domain::__transform_sender()(__domain2, std::move(__sndr2),
771                                                   __env);
772         }
773     });
774 }
775 
776 /////////////////////////////////////////////////////////////////////////////
777 template <class _Tag, class _Domain, class _Sender, class... _Args>
778 concept __has_implementation_for =
779     __domain::__has_apply_sender<_Domain, _Tag, _Sender, _Args...> ||
780     __domain::__has_apply_sender<default_domain, _Tag, _Sender, _Args...>;
781 
782 /////////////////////////////////////////////////////////////////////////////
783 // [execution.apply_sender]
784 inline constexpr struct apply_sender_t
785 {
786     template <class _Domain, class _Tag, class _Sender, class... _Args>
787         requires __has_implementation_for<_Tag, _Domain, _Sender, _Args...>
788     STDEXEC_ATTRIBUTE((always_inline))
789         /*constexpr*/
790         decltype(auto)
operator ()stdexec::apply_sender_t791             operator()(_Domain __dom, _Tag, _Sender&& __sndr,
792                        _Args&&... __args) const
793     {
794         if constexpr (__domain::__has_apply_sender<_Domain, _Tag, _Sender,
795                                                    _Args...>)
796         {
797             return __dom.apply_sender(_Tag(), static_cast<_Sender&&>(__sndr),
798                                       static_cast<_Args&&>(__args)...);
799         }
800         else
801         {
802             return default_domain().apply_sender(
803                 _Tag(), static_cast<_Sender&&>(__sndr),
804                 static_cast<_Args&&>(__args)...);
805         }
806     }
807 } apply_sender{};
808 
809 template <class _Domain, class _Tag, class _Sender, class... _Args>
810 using apply_sender_result_t =
811     __call_result_t<apply_sender_t, _Domain, _Tag, _Sender, _Args...>;
812 
813 /////////////////////////////////////////////////////////////////////////////
814 // [execution.sndtraits]
815 namespace __get_completion_signatures
816 {
817 template <class _Sender, class _Env>
818 using __tfx_sender =
819     transform_sender_result_t<__late_domain_of_t<_Sender, _Env>, _Sender, _Env>;
820 
821 template <class _Sender, class _Env>
822 concept __with_tag_invoke = //
823     tag_invocable<get_completion_signatures_t, __tfx_sender<_Sender, _Env>,
824                   _Env>;
825 
826 template <class _Sender, class _Env>
827 using __member_alias_t = //
828     typename __decay_t<__tfx_sender<_Sender, _Env>>::completion_signatures;
829 
830 template <class _Sender, class _Env = empty_env>
831 concept __with_member_alias = __mvalid<__member_alias_t, _Sender, _Env>;
832 
833 struct get_completion_signatures_t
834 {
835     template <class _Sender, class _Env>
__implstdexec::__get_completion_signatures::get_completion_signatures_t836     static auto __impl()
837     {
838         static_assert(sizeof(_Sender),
839                       "Incomplete type used with get_completion_signatures");
840         static_assert(sizeof(_Env),
841                       "Incomplete type used with get_completion_signatures");
842 
843         // Compute the type of the transformed sender:
844         using _TfxSender = __tfx_sender<_Sender, _Env>;
845 
846         if constexpr (__merror<_TfxSender>)
847         {
848             // Computing the type of the transformed sender returned an error
849             // type. Propagate it.
850             return static_cast<_TfxSender (*)()>(nullptr);
851         }
852         else if constexpr (__with_tag_invoke<_Sender, _Env>)
853         {
854             using _Result = tag_invoke_result_t<get_completion_signatures_t,
855                                                 _TfxSender, _Env>;
856             return static_cast<_Result (*)()>(nullptr);
857         }
858         else if constexpr (__with_member_alias<_Sender, _Env>)
859         {
860             using _Result = __member_alias_t<_Sender, _Env>;
861             return static_cast<_Result (*)()>(nullptr);
862         }
863         else if constexpr (__awaitable<_Sender, __env::__promise<_Env>>)
864         {
865             using _AwaitResult =
866                 __await_result_t<_Sender, __env::__promise<_Env>>;
867             using _Result = completion_signatures<
868                 // set_value_t() or set_value_t(T)
869                 __minvoke<__remove<void, __qf<set_value_t>>, _AwaitResult>,
870                 set_error_t(std::exception_ptr), set_stopped_t()>;
871             return static_cast<_Result (*)()>(nullptr);
872         }
873         else if constexpr (__is_debug_env<_Env>)
874         {
875             using __tag_invoke::tag_invoke;
876             // This ought to cause a hard error that indicates where the problem
877             // is.
878             using _Completions [[maybe_unused]] =
879                 tag_invoke_result_t<get_completion_signatures_t, _Sender, _Env>;
880             return static_cast<__debug::__completion_signatures (*)()>(nullptr);
881         }
882         else
883         {
884             using _Result =
885                 __mexception<_UNRECOGNIZED_SENDER_TYPE_<>,
886                              _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
887             return static_cast<_Result (*)()>(nullptr);
888         }
889     }
890 
891     // NOT TO SPEC: if we're unable to compute the completion signatures,
892     // return an error type instead of SFINAE.
893     template <class _Sender, class _Env = empty_env>
operator ()stdexec::__get_completion_signatures::get_completion_signatures_t894     constexpr auto operator()(_Sender&&, const _Env&) const noexcept
895         -> decltype(__impl<_Sender, _Env>()())
896     {
897         return {};
898     }
899 };
900 } // namespace __get_completion_signatures
901 
902 using __get_completion_signatures::get_completion_signatures_t;
903 inline constexpr get_completion_signatures_t get_completion_signatures{};
904 
905 /////////////////////////////////////////////////////////////////////////////
906 // [execution.senders]
907 struct sender_t
908 {
909     using sender_concept = sender_t;
910 };
911 
912 namespace __detail
913 {
914 template <class _Sender>
915 concept __enable_sender =                     //
916     derived_from<typename _Sender::sender_concept, sender_t> ||
917     requires { typename _Sender::is_sender; } // NOT TO SPEC back compat
918     || __awaitable<_Sender, __env::__promise<empty_env>>;
919 } // namespace __detail
920 
921 template <class _Sender>
922 inline constexpr bool enable_sender = __detail::__enable_sender<_Sender>;
923 
924 template <class _Sender, class _Env = empty_env>
925 concept sender = enable_sender<__decay_t<_Sender>> &&                  //
926                  environment_provider<__cref_t<_Sender>> &&            //
927                  __detail::__consistent_completion_domains<_Sender> && //
928                  move_constructible<__decay_t<_Sender>> &&             //
929                  constructible_from<__decay_t<_Sender>, _Sender>;
930 
931 template <class _Sender, class _Env = empty_env>
932 concept sender_in =    //
933     sender<_Sender> && //
934     requires(_Sender&& __sndr, _Env&& __env) {
935         {
936             get_completion_signatures(static_cast<_Sender&&>(__sndr),
937                                       static_cast<_Env&&>(__env))
938         } -> __valid_completion_signatures;
939     };
940 
941 #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
942 // __checked_completion_signatures is for catching logic bugs in a typed
943 // sender's metadata. If sender<S> and sender_in<S, Ctx> are both true, then
944 // they had better report the same metadata. This completion signatures wrapper
945 // enforces that at compile time.
946 template <class _Sender, class _Env>
__checked_completion_signatures(_Sender && __sndr,const _Env & __env)947 auto __checked_completion_signatures(_Sender&& __sndr,
948                                      const _Env& __env) noexcept
949 {
950     using __completions_t = __completion_signatures_of_t<_Sender, _Env>;
951     stdexec::__debug_sender<__completions_t>(static_cast<_Sender&&>(__sndr),
952                                              __env);
953     return __completions_t{};
954 }
955 
956 template <class _Sender, class _Env = empty_env>
957     requires sender_in<_Sender, _Env>
958 using completion_signatures_of_t =
959     decltype(stdexec::__checked_completion_signatures(__declval<_Sender>(),
960                                                       __declval<_Env>()));
961 #else
962 template <class _Sender, class _Env = empty_env>
963     requires sender_in<_Sender, _Env>
964 using completion_signatures_of_t = __completion_signatures_of_t<_Sender, _Env>;
965 #endif
966 
967 struct __not_a_variant
968 {
969     __not_a_variant() = delete;
970 };
971 template <class... _Ts>
972 using __variant = //
973     __minvoke<__if_c<sizeof...(_Ts) != 0,
974                      __transform<__q<__decay_t>, __munique<__q<std::variant>>>,
975                      __mconst<__not_a_variant>>,
976               _Ts...>;
977 
978 using __nullable_variant_t =
979     __munique<__mbind_front_q<std::variant, std::monostate>>;
980 
981 template <class... _Ts>
982 using __decayed_tuple = __meval<std::tuple, __decay_t<_Ts>...>;
983 
984 template <class _Tag, class _Tuple>
985 struct __select_completions_for
986 {
987     template <same_as<_Tag> _Tag2, class... _Args>
988     using __f = __minvoke<_Tag2, _Tuple, _Args...>;
989 };
990 
991 template <class _Tuple>
992 struct __invoke_completions
993 {
994     template <class _Tag, class... _Args>
995     using __f = __minvoke<_Tag, _Tuple, _Args...>;
996 };
997 
998 template <class _Tag, class _Tuple>
999 using __select_completions_for_or = //
1000     __with_default<__select_completions_for<_Tag, _Tuple>, __>;
1001 
1002 template <class _Tag, class _Completions>
1003 using __only_gather_signal = //
1004     __compl_sigs::__maybe_for_all_sigs<
1005         _Completions, __select_completions_for_or<_Tag, __qf<_Tag>>,
1006         __remove<__, __q<completion_signatures>>>;
1007 
1008 template <class _Tag, class _Completions, class _Tuple, class _Variant>
1009 using __gather_signal = //
1010     __compl_sigs::__maybe_for_all_sigs<__only_gather_signal<_Tag, _Completions>,
1011                                        __invoke_completions<_Tuple>, _Variant>;
1012 
1013 template <class _Tag, class _Sender, class _Env, class _Tuple, class _Variant>
1014 using __gather_completions_for = //
1015     __meval<                     //
1016         __gather_signal, _Tag, __completion_signatures_of_t<_Sender, _Env>,
1017         _Tuple, _Variant>;
1018 
1019 template <                               //
1020     class _Sender,                       //
1021     class _Env = empty_env,              //
1022     class _Tuple = __q<__decayed_tuple>, //
1023     class _Variant = __q<__variant>>
1024 using __try_value_types_of_t =           //
1025     __gather_completions_for<set_value_t, _Sender, _Env, _Tuple, _Variant>;
1026 
1027 template <                               //
1028     class _Sender,                       //
1029     class _Env = empty_env,              //
1030     class _Tuple = __q<__decayed_tuple>, //
1031     class _Variant = __q<__variant>>
1032     requires sender_in<_Sender, _Env>
1033 using __value_types_of_t = //
1034     __msuccess_or_t<__try_value_types_of_t<_Sender, _Env, _Tuple, _Variant>>;
1035 
1036 template <class _Sender, class _Env = empty_env,
1037           class _Variant = __q<__variant>>
1038 using __try_error_types_of_t =
1039     __gather_completions_for<set_error_t, _Sender, _Env, __q<__midentity>,
1040                              _Variant>;
1041 
1042 template <class _Sender, class _Env = empty_env,
1043           class _Variant = __q<__variant>>
1044     requires sender_in<_Sender, _Env>
1045 using __error_types_of_t =
1046     __msuccess_or_t<__try_error_types_of_t<_Sender, _Env, _Variant>>;
1047 
1048 template <                                              //
1049     class _Sender,                                      //
1050     class _Env = empty_env,                             //
1051     template <class...> class _Tuple = __decayed_tuple, //
1052     template <class...> class _Variant = __variant>
1053     requires sender_in<_Sender, _Env>
1054 using value_types_of_t =
1055     __value_types_of_t<_Sender, _Env, __q<_Tuple>, __q<_Variant>>;
1056 
1057 template <class _Sender, class _Env = empty_env,
1058           template <class...> class _Variant = __variant>
1059     requires sender_in<_Sender, _Env>
1060 using error_types_of_t = __error_types_of_t<_Sender, _Env, __q<_Variant>>;
1061 
1062 template <class _Tag, class _Sender, class _Env = empty_env>
1063 using __try_count_of = //
1064     __compl_sigs::__maybe_for_all_sigs<
1065         __completion_signatures_of_t<_Sender, _Env>, __q<__mfront>,
1066         __mcount<_Tag>>;
1067 
1068 template <class _Tag, class _Sender, class _Env = empty_env>
1069     requires sender_in<_Sender, _Env>
1070 using __count_of = __msuccess_or_t<__try_count_of<_Tag, _Sender, _Env>>;
1071 
1072 template <class _Tag, class _Sender, class _Env = empty_env>
1073     requires __mvalid<__count_of, _Tag, _Sender, _Env>
1074 inline constexpr bool __sends = (__v<__count_of<_Tag, _Sender, _Env>> != 0);
1075 
1076 template <class _Sender, class _Env = empty_env>
1077     requires __mvalid<__count_of, set_stopped_t, _Sender, _Env>
1078 inline constexpr bool sends_stopped = __sends<set_stopped_t, _Sender, _Env>;
1079 
1080 template <class _Sender, class _Env = empty_env>
1081 using __single_sender_value_t =
1082     __value_types_of_t<_Sender, _Env, __msingle_or<void>, __q<__msingle>>;
1083 
1084 template <class _Sender, class _Env = empty_env>
1085 using __single_value_variant_sender_t =
1086     value_types_of_t<_Sender, _Env, __types, __msingle>;
1087 
1088 template <class _Sender, class _Env = empty_env>
1089 concept __single_typed_sender =
1090     sender_in<_Sender, _Env> &&
1091     __mvalid<__single_sender_value_t, _Sender, _Env>;
1092 
1093 template <class _Sender, class _Env = empty_env>
1094 concept __single_value_variant_sender =
1095     sender_in<_Sender, _Env> &&
1096     __mvalid<__single_value_variant_sender_t, _Sender, _Env>;
1097 
1098 template <class... Errs>
1099 using __nofail = __mbool<sizeof...(Errs) == 0>;
1100 
1101 template <class _Sender, class _Env = empty_env>
1102 concept __nofail_sender = sender_in<_Sender, _Env> &&
1103                           (__v<error_types_of_t<_Sender, _Env, __nofail>>);
1104 
1105 /////////////////////////////////////////////////////////////////////////////
1106 namespace __compl_sigs
1107 {
1108 template <class... _Args>
1109 using __default_set_value = completion_signatures<set_value_t(_Args...)>;
1110 
1111 template <class _Error>
1112 using __default_set_error = completion_signatures<set_error_t(_Error)>;
1113 
1114 template <__valid_completion_signatures... _Sigs>
1115 using __ensure_concat_ =
1116     __minvoke<__mconcat<__q<completion_signatures>>, _Sigs...>;
1117 
1118 template <class... _Sigs>
1119 using __ensure_concat = __mtry_eval<__ensure_concat_, _Sigs...>;
1120 
1121 template <class _Sender, class _Env, class _Sigs, class _SetVal, class _SetErr,
1122           class _SetStp>
1123 using __compl_sigs_impl = //
1124     __concat_completion_signatures_t<
1125         _Sigs,
1126         __mtry_eval<__try_value_types_of_t, _Sender, _Env, _SetVal,
1127                     __q<__ensure_concat>>,
1128         __mtry_eval<__try_error_types_of_t, _Sender, _Env,
1129                     __transform<_SetErr, __q<__ensure_concat>>>,
1130         __if<__try_count_of<set_stopped_t, _Sender, _Env>, _SetStp,
1131              completion_signatures<>>>;
1132 
1133 template <class _Sender, class _Env, class _Sigs, class _SetVal, class _SetErr,
1134           class _SetStp>
1135     requires __mvalid<__compl_sigs_impl, _Sender, _Env, _Sigs, _SetVal, _SetErr,
1136                       _SetStp>
1137 extern __compl_sigs_impl<_Sender, _Env, _Sigs, _SetVal, _SetErr, _SetStp>
1138     __compl_sigs_v;
1139 
1140 template <class _Sender, class _Env, class _Sigs, class _SetVal, class _SetErr,
1141           class _SetStp>
1142 using __compl_sigs_t =
1143     decltype(__compl_sigs_v<_Sender, _Env, _Sigs, _SetVal, _SetErr, _SetStp>);
1144 
1145 template <                                                      //
1146     class _Sender,                                              //
1147     class _Env = empty_env,                                     //
1148     class _Sigs = completion_signatures<>,                      //
1149     class _SetValue = __q<__default_set_value>,                 //
1150     class _SetError = __q<__default_set_error>,                 //
1151     class _SetStopped = completion_signatures<set_stopped_t()>> //
1152 using __try_make_completion_signatures =                        //
1153     __meval<__compl_sigs_t, _Sender, _Env, _Sigs, _SetValue, _SetError,
1154             _SetStopped>;
1155 } // namespace __compl_sigs
1156 
1157 using __compl_sigs::__try_make_completion_signatures;
1158 
1159 /////////////////////////////////////////////////////////////////////////////
1160 // NOT TO SPEC
1161 //
1162 // make_completion_signatures
1163 // ==========================
1164 //
1165 // `make_completion_signatures` takes a sender, and environment, and a bunch
1166 // of other template arguments for munging the completion signatures of a
1167 // sender in interesting ways.
1168 //
1169 //  ```c++
1170 //  template <class... Args>
1171 //    using __default_set_value = completion_signatures<set_value_t(Args...)>;
1172 //
1173 //  template <class Err>
1174 //    using __default_set_error = completion_signatures<set_error_t(Err)>;
1175 //
1176 //  template <
1177 //    sender Sndr,
1178 //    class Env = empty_env,
1179 //    class AddlSigs = completion_signatures<>,
1180 //    template <class...> class SetValue = __default_set_value,
1181 //    template <class> class SetError = __default_set_error,
1182 //    class SetStopped = completion_signatures<set_stopped_t()>>
1183 //      requires sender_in<Sndr, Env>
1184 //  using make_completion_signatures =
1185 //    completion_signatures< ... >;
1186 //  ```
1187 //
1188 //  * `SetValue` : an alias template that accepts a set of value types and
1189 //    returns an instance of `completion_signatures`.
1190 //  * `SetError` : an alias template that accepts an error types and returns a
1191 //    an instance of `completion_signatures`.
1192 //  * `SetStopped` : an instantiation of `completion_signatures` with a list
1193 //    of completion signatures `Sigs...` to the added to the list if the
1194 //    sender can complete with a stopped signal.
1195 //  * `AddlSigs` : an instantiation of `completion_signatures` with a list of
1196 //    completion signatures `Sigs...` to the added to the list
1197 //    unconditionally.
1198 //
1199 //  `make_completion_signatures` does the following:
1200 //  * Let `VCs...` be a pack of the `completion_signatures` types in the
1201 //    `__typelist` named by `value_types_of_t<Sndr, Env, SetValue,
1202 //    __typelist>`, and let `Vs...` be the concatenation of the packs that are
1203 //    template arguments to each `completion_signature` in `VCs...`.
1204 //  * Let `ECs...` be a pack of the `completion_signatures` types in the
1205 //    `__typelist` named by `error_types_of_t<Sndr, Env, __errorlist>`, where
1206 //    `__errorlist` is an alias template such that `__errorlist<Ts...>` names
1207 //    `__typelist<SetError<Ts>...>`, and let `Es...` by the concatenation of
1208 //    the packs that are the template arguments to each `completion_signature`
1209 //    in `ECs...`.
1210 //  * Let `Ss...` be an empty pack if `sends_stopped<Sndr, Env>` is
1211 //    `false`; otherwise, a pack containing the template arguments of the
1212 //    `completion_signatures` instantiation named by `SetStopped`.
1213 //  * Let `MoreSigs...` be a pack of the template arguments of the
1214 //    `completion_signatures` instantiation named by `AddlSigs`.
1215 //
1216 //  Then `make_completion_signatures<Sndr, Env, AddlSigs, SetValue, SetError,
1217 //  SendsStopped>` names the type `completion_signatures< Sigs... >` where
1218 //  `Sigs...` is the unique set of types in `[Vs..., Es..., Ss...,
1219 //  MoreSigs...]`.
1220 //
1221 //  If any of the above type computations are ill-formed,
1222 //  `make_completion_signatures<Sndr, Env, AddlSigs, SetValue, SetError,
1223 //  SendsStopped>` is an alias for an empty struct
1224 template <                                                                   //
1225     class _Sender,                                                           //
1226     class _Env = empty_env,                                                  //
1227     __valid_completion_signatures _Sigs = completion_signatures<>,           //
1228     template <class...> class _SetValue = __compl_sigs::__default_set_value, //
1229     template <class> class _SetError = __compl_sigs::__default_set_error,    //
1230     __valid_completion_signatures _SetStopped =
1231         completion_signatures<set_stopped_t()>>
1232     requires sender_in<_Sender, _Env>
1233 using make_completion_signatures = //
1234     __msuccess_or_t<               //
1235         __try_make_completion_signatures<_Sender, _Env, _Sigs, __q<_SetValue>,
1236                                          __q<_SetError>, _SetStopped>>;
1237 
1238 // Needed fairly often
1239 using __with_exception_ptr =
1240     completion_signatures<set_error_t(std::exception_ptr)>;
1241 
1242 /////////////////////////////////////////////////////////////////////////////
1243 // [execution.senders.schedule]
1244 namespace __schedule
1245 {
1246 struct schedule_t
1247 {
1248     template <class _Scheduler>
1249         requires tag_invocable<schedule_t, _Scheduler>
1250     STDEXEC_ATTRIBUTE((host, device)) auto
operator ()stdexec::__schedule::schedule_t1251         operator()(_Scheduler&& __sched) const
1252         noexcept(nothrow_tag_invocable<schedule_t, _Scheduler>)
1253     {
1254         static_assert(sender<tag_invoke_result_t<schedule_t, _Scheduler>>);
1255         return tag_invoke(schedule_t{}, static_cast<_Scheduler&&>(__sched));
1256     }
1257 
tag_invoke(forwarding_query_t,schedule_t)1258     friend constexpr auto tag_invoke(forwarding_query_t, schedule_t) -> bool
1259     {
1260         return false;
1261     }
1262 };
1263 } // namespace __schedule
1264 
1265 using __schedule::schedule_t;
1266 inline constexpr schedule_t schedule{};
1267 
1268 // NOT TO SPEC
1269 template <class _Tag, const auto& _Predicate>
1270 concept tag_category = //
1271     requires {
1272         typename __mbool<bool{_Predicate(_Tag{})}>;
1273         requires bool {
1274             _Predicate(_Tag{})
1275         };
1276     };
1277 
1278 /////////////////////////////////////////////////////////////////////////////
1279 // [execution.schedulers]
1280 template <class _Scheduler>
1281 concept __has_schedule = //
1282     requires(_Scheduler&& __sched) {
1283         {
1284             schedule(static_cast<_Scheduler&&>(__sched))
1285         } -> sender;
1286     };
1287 
1288 template <class _Scheduler>
1289 concept __sender_has_completion_scheduler =
1290     requires(_Scheduler&& __sched,
1291              get_completion_scheduler_t<set_value_t>&& __tag) {
1292         {
1293             tag_invoke(std::move(__tag),
1294                        get_env(schedule(static_cast<_Scheduler&&>(__sched))))
1295         } -> same_as<__decay_t<_Scheduler>>;
1296     };
1297 
1298 template <class _Scheduler>
1299 concept scheduler =                                  //
1300     __has_schedule<_Scheduler> &&                    //
1301     __sender_has_completion_scheduler<_Scheduler> && //
1302     equality_comparable<__decay_t<_Scheduler>> &&    //
1303     copy_constructible<__decay_t<_Scheduler>>;
1304 
1305 template <scheduler _Scheduler>
1306 using schedule_result_t = __call_result_t<schedule_t, _Scheduler>;
1307 
1308 template <receiver _Receiver>
1309 using __current_scheduler_t =
1310     __call_result_t<get_scheduler_t, env_of_t<_Receiver>>;
1311 
1312 template <class _SchedulerProvider>
1313 concept __scheduler_provider = //
1314     requires(const _SchedulerProvider& __sp) {
1315         {
1316             get_scheduler(__sp)
1317         } -> scheduler;
1318     };
1319 
1320 /////////////////////////////////////////////////////////////////////////////
1321 // [execution.op_state]
1322 namespace __start
1323 {
1324 struct start_t
1325 {
1326     template <class _Op>
1327         requires tag_invocable<start_t, _Op&>
operator ()stdexec::__start::start_t1328     STDEXEC_ATTRIBUTE((always_inline)) void operator()(_Op& __op) const noexcept
1329     {
1330         static_assert(nothrow_tag_invocable<start_t, _Op&>);
1331         (void)tag_invoke(start_t{}, __op);
1332     }
1333 };
1334 } // namespace __start
1335 
1336 using __start::start_t;
1337 inline constexpr start_t start{};
1338 
1339 /////////////////////////////////////////////////////////////////////////////
1340 // [execution.op_state]
1341 template <class _Op>
1342 concept operation_state =    //
1343     destructible<_Op> &&     //
1344     std::is_object_v<_Op> && //
1345     requires(_Op& __op) {    //
1346         start(__op);
1347     };
1348 
1349 #if !STDEXEC_STD_NO_COROUTINES_
1350 /////////////////////////////////////////////////////////////////////////////
1351 // __connect_awaitable_
1352 namespace __connect_awaitable_
1353 {
1354 struct __promise_base
1355 {
initial_suspendstdexec::__connect_awaitable_::__promise_base1356     auto initial_suspend() noexcept -> __coro::suspend_always
1357     {
1358         return {};
1359     }
1360 
final_suspendstdexec::__connect_awaitable_::__promise_base1361     [[noreturn]] auto final_suspend() noexcept -> __coro::suspend_always
1362     {
1363         std::terminate();
1364     }
1365 
unhandled_exceptionstdexec::__connect_awaitable_::__promise_base1366     [[noreturn]] void unhandled_exception() noexcept
1367     {
1368         std::terminate();
1369     }
1370 
return_voidstdexec::__connect_awaitable_::__promise_base1371     [[noreturn]] void return_void() noexcept
1372     {
1373         std::terminate();
1374     }
1375 };
1376 
1377 struct __operation_base
1378 {
1379     __coro::coroutine_handle<> __coro_;
1380 
__operation_basestdexec::__connect_awaitable_::__operation_base1381     explicit __operation_base(__coro::coroutine_handle<> __hcoro) noexcept :
1382         __coro_(__hcoro)
1383     {}
1384 
__operation_basestdexec::__connect_awaitable_::__operation_base1385     __operation_base(__operation_base&& __other) noexcept :
1386         __coro_(std::exchange(__other.__coro_, {}))
1387     {}
1388 
~__operation_basestdexec::__connect_awaitable_::__operation_base1389     ~__operation_base()
1390     {
1391         if (__coro_)
1392         {
1393 #if STDEXEC_MSVC()
1394             // MSVCBUG
1395             // https://developercommunity.visualstudio.com/t/Double-destroy-of-a-local-in-coroutine-d/10456428
1396 
1397             // Reassign __coro_ before calling destroy to make the mutation
1398             // observable and to hopefully ensure that the compiler does not
1399             // eliminate it.
1400             auto __coro = __coro_;
1401             __coro_ = {};
1402             __coro.destroy();
1403 #else
1404             __coro_.destroy();
1405 #endif
1406         }
1407     }
1408 
tag_invoke(start_t,__operation_base & __self)1409     friend void tag_invoke(start_t, __operation_base& __self) noexcept
1410     {
1411         __self.__coro_.resume();
1412     }
1413 };
1414 
1415 template <class _ReceiverId>
1416 struct __promise;
1417 
1418 template <class _ReceiverId>
1419 struct __operation
1420 {
1421     struct __t : __operation_base
1422     {
1423         using promise_type = stdexec::__t<__promise<_ReceiverId>>;
1424         using __operation_base::__operation_base;
1425     };
1426 };
1427 
1428 template <class _ReceiverId>
1429 struct __promise
1430 {
1431     using _Receiver = stdexec::__t<_ReceiverId>;
1432 
1433     struct __t : __promise_base
1434     {
1435         using __id = __promise;
1436 
__tstdexec::__connect_awaitable_::__promise::__t1437         explicit __t(auto&, _Receiver& __rcvr) noexcept : __rcvr_(__rcvr) {}
1438 
unhandled_stoppedstdexec::__connect_awaitable_::__promise::__t1439         auto unhandled_stopped() noexcept -> __coro::coroutine_handle<>
1440         {
1441             set_stopped(static_cast<_Receiver&&>(__rcvr_));
1442             // Returning noop_coroutine here causes the __connect_awaitable
1443             // coroutine to never resume past the point where it co_await's
1444             // the awaitable.
1445             return __coro::noop_coroutine();
1446         }
1447 
get_return_objectstdexec::__connect_awaitable_::__promise::__t1448         auto get_return_object() noexcept
1449             -> stdexec::__t<__operation<_ReceiverId>>
1450         {
1451             return stdexec::__t<__operation<_ReceiverId>>{
1452                 __coro::coroutine_handle<__t>::from_promise(*this)};
1453         }
1454 
1455         template <class _Awaitable>
await_transformstdexec::__connect_awaitable_::__promise::__t1456         auto await_transform(_Awaitable&& __awaitable) noexcept -> _Awaitable&&
1457         {
1458             return static_cast<_Awaitable&&>(__awaitable);
1459         }
1460 
1461         template <class _Awaitable>
1462             requires tag_invocable<as_awaitable_t, _Awaitable, __t&>
await_transformstdexec::__connect_awaitable_::__promise::__t1463         auto await_transform(_Awaitable&& __awaitable) //
1464             noexcept(nothrow_tag_invocable<as_awaitable_t, _Awaitable, __t&>)
1465                 -> tag_invoke_result_t<as_awaitable_t, _Awaitable, __t&>
1466         {
1467             return tag_invoke(as_awaitable,
1468                               static_cast<_Awaitable&&>(__awaitable), *this);
1469         }
1470 
1471         // Pass through the get_env receiver query
tag_invokestdexec::__connect_awaitable_::__promise1472         friend auto tag_invoke(get_env_t, const __t& __self) noexcept
1473             -> env_of_t<_Receiver>
1474         {
1475             return get_env(__self.__rcvr_);
1476         }
1477 
1478         _Receiver& __rcvr_;
1479     };
1480 };
1481 
1482 template <receiver _Receiver>
1483 using __promise_t = __t<__promise<__id<_Receiver>>>;
1484 
1485 template <receiver _Receiver>
1486 using __operation_t = __t<__operation<__id<_Receiver>>>;
1487 
1488 struct __connect_awaitable_t
1489 {
1490   private:
1491     template <class _Fun, class... _Ts>
__co_callstdexec::__connect_awaitable_::__connect_awaitable_t1492     static auto __co_call(_Fun __fun, _Ts&&... __as) noexcept
1493     {
1494         auto __fn = [&, __fun]() noexcept {
1495             __fun(static_cast<_Ts&&>(__as)...);
1496         };
1497 
1498         struct __awaiter
1499         {
1500             decltype(__fn) __fn_;
1501 
1502             static constexpr auto await_ready() noexcept -> bool
1503             {
1504                 return false;
1505             }
1506 
1507             void await_suspend(__coro::coroutine_handle<>) noexcept
1508             {
1509                 __fn_();
1510             }
1511 
1512             [[noreturn]] void await_resume() noexcept
1513             {
1514                 std::terminate();
1515             }
1516         };
1517 
1518         return __awaiter{__fn};
1519     }
1520 
1521     template <class _Awaitable, class _Receiver>
1522 #if STDEXEC_GCC() && (__GNUC__ > 11)
1523     __attribute__((__used__))
1524 #endif
1525     static auto
__co_implstdexec::__connect_awaitable_::__connect_awaitable_t1526         __co_impl(_Awaitable __awaitable, _Receiver __rcvr)
1527             -> __operation_t<_Receiver>
1528     {
1529         using __result_t = __await_result_t<_Awaitable, __promise_t<_Receiver>>;
1530         std::exception_ptr __eptr;
1531         try
1532         {
1533             if constexpr (same_as<__result_t, void>)
1534                 co_await (
1535                     co_await static_cast<_Awaitable&&>(__awaitable),
1536                     __co_call(set_value, static_cast<_Receiver&&>(__rcvr)));
1537             else
1538                 co_await __co_call(
1539                     set_value, static_cast<_Receiver&&>(__rcvr),
1540                     co_await static_cast<_Awaitable&&>(__awaitable));
1541         }
1542         catch (...)
1543         {
1544             __eptr = std::current_exception();
1545         }
1546         co_await __co_call(set_error, static_cast<_Receiver&&>(__rcvr),
1547                            static_cast<std::exception_ptr&&>(__eptr));
1548     }
1549 
1550     template <receiver _Receiver, class _Awaitable>
1551     using __completions_t = //
1552         completion_signatures<
1553             __minvoke<      // set_value_t() or set_value_t(T)
1554                 __remove<void, __qf<set_value_t>>,
1555                 __await_result_t<_Awaitable, __promise_t<_Receiver>>>,
1556             set_error_t(std::exception_ptr), set_stopped_t()>;
1557 
1558   public:
1559     template <class _Receiver, __awaitable<__promise_t<_Receiver>> _Awaitable>
1560         requires receiver_of<_Receiver, __completions_t<_Receiver, _Awaitable>>
operator ()stdexec::__connect_awaitable_::__connect_awaitable_t1561     auto operator()(_Awaitable&& __awaitable, _Receiver __rcvr) const
1562         -> __operation_t<_Receiver>
1563     {
1564         return __co_impl(static_cast<_Awaitable&&>(__awaitable),
1565                          static_cast<_Receiver&&>(__rcvr));
1566     }
1567 };
1568 } // namespace __connect_awaitable_
1569 
1570 using __connect_awaitable_::__connect_awaitable_t;
1571 #else
1572 struct __connect_awaitable_t
1573 {};
1574 #endif
1575 inline constexpr __connect_awaitable_t __connect_awaitable{};
1576 
1577 /////////////////////////////////////////////////////////////////////////////
1578 // [execution.senders.connect]
1579 namespace __connect
1580 {
1581 struct connect_t;
1582 
1583 template <class _Sender, class _Receiver>
1584 using __tfx_sender = //
1585     transform_sender_result_t<__late_domain_of_t<_Sender, env_of_t<_Receiver&>>,
1586                               _Sender, env_of_t<_Receiver&>>;
1587 
1588 template <class _Sender, class _Receiver>
1589 concept __connectable_with_tag_invoke_ =       //
1590     receiver<_Receiver> &&                     //
1591     sender_in<_Sender, env_of_t<_Receiver>> && //
1592     __receiver_from<_Receiver, _Sender> &&     //
1593     tag_invocable<connect_t, _Sender, _Receiver>;
1594 
1595 template <class _Sender, class _Receiver>
1596 concept __connectable_with_tag_invoke = //
1597     __connectable_with_tag_invoke_<__tfx_sender<_Sender, _Receiver>, _Receiver>;
1598 
1599 template <class _Sender, class _Receiver>
1600 concept __connectable_with_co_await = //
1601     __callable<__connect_awaitable_t, __tfx_sender<_Sender, _Receiver>,
1602                _Receiver>;
1603 
1604 struct connect_t
1605 {
1606     template <class _Sender, class _Env>
__check_signaturesstdexec::__connect::connect_t1607     static constexpr auto __check_signatures() -> bool
1608     {
1609         if constexpr (sender_in<_Sender, _Env>)
1610         {
1611             // Instantiate __debug_sender via completion_signatures_of_t
1612             // to check that the actual completions match the expected
1613             // completions.
1614             //
1615             // Instantiate completion_signatures_of_t only if sender_in
1616             // is true to workaround Clang not implementing CWG#2369 yet
1617             // (connect() does have a constraint for _Sender satisfying
1618             // sender_in).
1619             using __checked_signatures
1620                 [[maybe_unused]] = completion_signatures_of_t<_Sender, _Env>;
1621         }
1622         return true;
1623     }
1624 
1625     template <class _Sender, class _Receiver>
__select_implstdexec::__connect::connect_t1626     static constexpr auto __select_impl() noexcept
1627     {
1628         using _Domain = __late_domain_of_t<_Sender, env_of_t<_Receiver&>>;
1629         constexpr bool _NothrowTfxSender =
1630             __nothrow_callable<get_env_t, _Receiver&> &&
1631             __nothrow_callable<transform_sender_t, _Domain, _Sender,
1632                                env_of_t<_Receiver&>>;
1633         using _TfxSender = __tfx_sender<_Sender, _Receiver&>;
1634 
1635 #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
1636         static_assert(__check_signatures<_TfxSender, env_of_t<_Receiver>>());
1637 #endif
1638 
1639         if constexpr (__connectable_with_tag_invoke<_Sender, _Receiver>)
1640         {
1641             using _Result =
1642                 tag_invoke_result_t<connect_t, _TfxSender, _Receiver>;
1643             constexpr bool _Nothrow = //
1644                 _NothrowTfxSender &&
1645                 nothrow_tag_invocable<connect_t, _TfxSender, _Receiver>;
1646             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
1647         }
1648         else if constexpr (__connectable_with_co_await<_Sender, _Receiver>)
1649         {
1650             using _Result =
1651                 __call_result_t<__connect_awaitable_t, _TfxSender, _Receiver>;
1652             return static_cast<_Result (*)()>(nullptr);
1653         }
1654         else
1655         {
1656             using _Result = __debug::__debug_operation;
1657             return static_cast<_Result (*)() noexcept(_NothrowTfxSender)>(
1658                 nullptr);
1659         }
1660     }
1661 
1662     template <class _Sender, class _Receiver>
1663     using __select_impl_t = decltype(__select_impl<_Sender, _Receiver>());
1664 
1665     template <sender _Sender, receiver _Receiver>
1666         requires __connectable_with_tag_invoke<_Sender, _Receiver> ||
1667                  __connectable_with_co_await<_Sender, _Receiver> ||
1668                  __is_debug_env<env_of_t<_Receiver>>
1669     auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const
1670         noexcept(__nothrow_callable<__select_impl_t<_Sender, _Receiver>>)
1671             -> __call_result_t<__select_impl_t<_Sender, _Receiver>>
1672     {
1673         using _TfxSender = __tfx_sender<_Sender, _Receiver&>;
1674         auto&& __env = get_env(__rcvr);
1675         auto __domain = __get_late_domain(__sndr, __env);
1676 
1677         if constexpr (__connectable_with_tag_invoke<_Sender, _Receiver>)
1678         {
1679             static_assert(
1680                 operation_state<
1681                     tag_invoke_result_t<connect_t, _TfxSender, _Receiver>>,
1682                 "stdexec::connect(sender, receiver) must return a type that "
1683                 "satisfies the operation_state concept");
1684             return tag_invoke(connect_t{},
1685                               transform_sender(__domain,
1686                                                static_cast<_Sender&&>(__sndr),
1687                                                __env),
1688                               static_cast<_Receiver&&>(__rcvr));
1689         }
1690         else if constexpr (__connectable_with_co_await<_Sender, _Receiver>)
1691         {
1692             return __connect_awaitable( //
1693                 transform_sender(__domain, static_cast<_Sender&&>(__sndr),
1694                                  __env),
1695                 static_cast<_Receiver&&>(__rcvr));
1696         }
1697         else
1698         {
1699             // This should generate an instantiation backtrace that contains
1700             // useful debugging information.
1701             using __tag_invoke::tag_invoke;
1702             tag_invoke(*this,
1703                        transform_sender(__domain,
1704                                         static_cast<_Sender&&>(__sndr), __env),
1705                        static_cast<_Receiver&&>(__rcvr));
1706         }
1707     }
1708 
tag_invoke(forwarding_query_t,connect_t)1709     friend constexpr auto tag_invoke(forwarding_query_t, connect_t) noexcept
1710         -> bool
1711     {
1712         return false;
1713     }
1714 };
1715 } // namespace __connect
1716 
1717 using __connect::connect_t;
1718 inline constexpr __connect::connect_t connect{};
1719 
1720 /////////////////////////////////////////////////////////////////////////////
1721 // [exec.snd]
1722 template <class _Sender, class _Receiver>
1723 concept sender_to = receiver<_Receiver> &&                     //
1724                     sender_in<_Sender, env_of_t<_Receiver>> && //
1725                     __receiver_from<_Receiver, _Sender> &&     //
1726                     requires(_Sender&& __sndr, _Receiver&& __rcvr) {
1727                         connect(static_cast<_Sender&&>(__sndr),
1728                                 static_cast<_Receiver&&>(__rcvr));
1729                     };
1730 
1731 template <class _Tag, class... _Args>
1732 auto __tag_of_sig_(_Tag (*)(_Args...)) -> _Tag;
1733 template <class _Sig>
1734 using __tag_of_sig_t =
1735     decltype(stdexec::__tag_of_sig_(static_cast<_Sig*>(nullptr)));
1736 
1737 template <class _Sender, class _SetSig, class _Env = empty_env>
1738 concept sender_of =
1739     sender_in<_Sender, _Env> &&
1740     same_as<__types<_SetSig>, __gather_completions_for<
1741                                   __tag_of_sig_t<_SetSig>, _Sender, _Env,
1742                                   __qf<__tag_of_sig_t<_SetSig>>, __q<__types>>>;
1743 
1744 #if !STDEXEC_STD_NO_COROUTINES_
1745 /////////////////////////////////////////////////////////////////////////////
1746 // stdexec::as_awaitable [execution.coro_utils.as_awaitable]
1747 namespace __as_awaitable
1748 {
1749 struct __void
1750 {};
1751 template <class _Value>
1752 using __value_or_void_t = __if<std::is_same<_Value, void>, __void, _Value>;
1753 template <class _Value>
1754 using __expected_t =
1755     std::variant<std::monostate, __value_or_void_t<_Value>, std::exception_ptr>;
1756 
1757 template <class _Value>
1758 struct __receiver_base
1759 {
1760     using receiver_concept = receiver_t;
1761 
1762     template <same_as<set_value_t> _Tag, class... _Us>
1763         requires constructible_from<__value_or_void_t<_Value>, _Us...>
tag_invoke(_Tag,__receiver_base && __self,_Us &&...__us)1764     friend void tag_invoke(_Tag, __receiver_base&& __self,
1765                            _Us&&... __us) noexcept
1766     {
1767         try
1768         {
1769             __self.__result_->template emplace<1>(static_cast<_Us&&>(__us)...);
1770             __self.__continuation_.resume();
1771         }
1772         catch (...)
1773         {
1774             set_error(static_cast<__receiver_base&&>(__self),
1775                       std::current_exception());
1776         }
1777     }
1778 
1779     template <same_as<set_error_t> _Tag, class _Error>
tag_invoke(_Tag,__receiver_base && __self,_Error && __err)1780     friend void tag_invoke(_Tag, __receiver_base&& __self,
1781                            _Error&& __err) noexcept
1782     {
1783         if constexpr (__decays_to<_Error, std::exception_ptr>)
1784             __self.__result_->template emplace<2>(static_cast<_Error&&>(__err));
1785         else if constexpr (__decays_to<_Error, std::error_code>)
1786             __self.__result_->template emplace<2>(
1787                 std::make_exception_ptr(std::system_error(__err)));
1788         else
1789             __self.__result_->template emplace<2>(
1790                 std::make_exception_ptr(static_cast<_Error&&>(__err)));
1791         __self.__continuation_.resume();
1792     }
1793 
1794     __expected_t<_Value>* __result_;
1795     __coro::coroutine_handle<> __continuation_;
1796 };
1797 
1798 template <class _PromiseId, class _Value>
1799 struct __receiver
1800 {
1801     using _Promise = stdexec::__t<_PromiseId>;
1802 
1803     struct __t : __receiver_base<_Value>
1804     {
1805         using __id = __receiver;
1806 
1807         template <same_as<set_stopped_t> _Tag>
tag_invokestdexec::__as_awaitable::__receiver1808         friend void tag_invoke(_Tag, __t&& __self) noexcept
1809         {
1810             auto __continuation =
1811                 __coro::coroutine_handle<_Promise>::from_address(
1812                     __self.__continuation_.address());
1813             __coro::coroutine_handle<> __stopped_continuation =
1814                 __continuation.promise().unhandled_stopped();
1815             __stopped_continuation.resume();
1816         }
1817 
1818         // Forward get_env query to the coroutine promise
tag_invokestdexec::__as_awaitable::__receiver1819         friend auto tag_invoke(get_env_t, const __t& __self) noexcept
1820             -> env_of_t<_Promise&>
1821         {
1822             auto __continuation =
1823                 __coro::coroutine_handle<_Promise>::from_address(
1824                     __self.__continuation_.address());
1825             return get_env(__continuation.promise());
1826         }
1827     };
1828 };
1829 
1830 // BUGBUG NOT TO SPEC: make senders of more-than-one-value awaitable
1831 // by packaging the values into a tuple.
1832 // See: https://github.com/cplusplus/sender-receiver/issues/182
1833 template <std::size_t _Count>
1834 extern const __q<__decayed_tuple> __as_single;
1835 
1836 template <>
1837 inline const __q<__midentity> __as_single<1>;
1838 
1839 template <>
1840 inline const __mconst<void> __as_single<0>;
1841 
1842 template <class... _Values>
1843 using __single_value =
1844     __minvoke<decltype(__as_single<sizeof...(_Values)>), _Values...>;
1845 
1846 template <class _Sender, class _Promise>
1847 using __value_t =
1848     __decay_t<__value_types_of_t<_Sender, env_of_t<_Promise&>,
1849                                  __q<__single_value>, __msingle_or<void>>>;
1850 
1851 template <class _Sender, class _Promise>
1852 using __receiver_t =
1853     __t<__receiver<__id<_Promise>, __value_t<_Sender, _Promise>>>;
1854 
1855 template <class _Value>
1856 struct __sender_awaitable_base
1857 {
await_readystdexec::__as_awaitable::__sender_awaitable_base1858     [[nodiscard]] auto await_ready() const noexcept -> bool
1859     {
1860         return false;
1861     }
1862 
await_resumestdexec::__as_awaitable::__sender_awaitable_base1863     auto await_resume() -> _Value
1864     {
1865         switch (__result_.index())
1866         {
1867             case 0: // receiver contract not satisfied
1868                 STDEXEC_ASSERT(!"_Should never get here");
1869                 break;
1870             case 1: // set_value
1871                 if constexpr (!std::is_void_v<_Value>)
1872                     return static_cast<_Value&&>(std::get<1>(__result_));
1873                 else
1874                     return;
1875             case 2: // set_error
1876                 std::rethrow_exception(std::get<2>(__result_));
1877         }
1878         std::terminate();
1879     }
1880 
1881   protected:
1882     __expected_t<_Value> __result_;
1883 };
1884 
1885 template <class _PromiseId, class _SenderId>
1886 struct __sender_awaitable
1887 {
1888     using _Promise = stdexec::__t<_PromiseId>;
1889     using _Sender = stdexec::__t<_SenderId>;
1890     using __value = __value_t<_Sender, _Promise>;
1891 
1892     struct __t : __sender_awaitable_base<__value>
1893     {
__tstdexec::__as_awaitable::__sender_awaitable::__t1894         __t(_Sender&& sndr, __coro::coroutine_handle<_Promise> __hcoro) //
1895             noexcept(__nothrow_connectable<_Sender, __receiver>) :
1896             __op_state_(connect(static_cast<_Sender&&>(sndr),
1897                                 __receiver{{&this->__result_, __hcoro}}))
1898         {}
1899 
await_suspendstdexec::__as_awaitable::__sender_awaitable::__t1900         void await_suspend(__coro::coroutine_handle<_Promise>) noexcept
1901         {
1902             start(__op_state_);
1903         }
1904 
1905       private:
1906         using __receiver = __receiver_t<_Sender, _Promise>;
1907         connect_result_t<_Sender, __receiver> __op_state_;
1908     };
1909 };
1910 
1911 template <class _Promise, class _Sender>
1912 using __sender_awaitable_t =
1913     __t<__sender_awaitable<__id<_Promise>, __id<_Sender>>>;
1914 
1915 template <class _Sender, class _Promise>
1916 concept __awaitable_sender =
1917     sender_in<_Sender, env_of_t<_Promise&>> &&             //
1918     __mvalid<__value_t, _Sender, _Promise> &&              //
1919     sender_to<_Sender, __receiver_t<_Sender, _Promise>> && //
1920     requires(_Promise& __promise) {
1921         {
1922             __promise.unhandled_stopped()
1923         } -> convertible_to<__coro::coroutine_handle<>>;
1924     };
1925 
1926 struct __unspecified
1927 {
1928     auto get_return_object() noexcept -> __unspecified;
1929     auto initial_suspend() noexcept -> __unspecified;
1930     auto final_suspend() noexcept -> __unspecified;
1931     void unhandled_exception() noexcept;
1932     void return_void() noexcept;
1933     auto unhandled_stopped() noexcept -> __coro::coroutine_handle<>;
1934 };
1935 
1936 struct as_awaitable_t
1937 {
1938     template <class _Tp, class _Promise>
__select_impl_stdexec::__as_awaitable::as_awaitable_t1939     static constexpr auto __select_impl_() noexcept
1940     {
1941         if constexpr (tag_invocable<as_awaitable_t, _Tp, _Promise&>)
1942         {
1943             using _Result = tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&>;
1944             constexpr bool _Nothrow =
1945                 nothrow_tag_invocable<as_awaitable_t, _Tp, _Promise&>;
1946             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
1947             // NOLINTNEXTLINE(bugprone-branch-clone)
1948         }
1949         else if constexpr (__awaitable<_Tp, __unspecified>)
1950         { // NOT __awaitable<_Tp, _Promise> !!
1951             using _Result = _Tp&&;
1952             return static_cast<_Result (*)() noexcept>(nullptr);
1953         }
1954         else if constexpr (__awaitable_sender<_Tp, _Promise>)
1955         {
1956             using _Result = __sender_awaitable_t<_Promise, _Tp>;
1957             constexpr bool _Nothrow = __nothrow_constructible_from<
1958                 _Result, _Tp, __coro::coroutine_handle<_Promise>>;
1959             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
1960         }
1961         else
1962         {
1963             using _Result = _Tp&&;
1964             return static_cast<_Result (*)() noexcept>(nullptr);
1965         }
1966     }
1967     template <class _Tp, class _Promise>
1968     using __select_impl_t = decltype(__select_impl_<_Tp, _Promise>());
1969 
1970     template <class _Tp, class _Promise>
operator ()stdexec::__as_awaitable::as_awaitable_t1971     auto operator()(_Tp&& __t, _Promise& __promise) const
1972         noexcept(__nothrow_callable<__select_impl_t<_Tp, _Promise>>)
1973             -> __call_result_t<__select_impl_t<_Tp, _Promise>>
1974     {
1975         if constexpr (tag_invocable<as_awaitable_t, _Tp, _Promise&>)
1976         {
1977             using _Result = tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&>;
1978             static_assert(__awaitable<_Result, _Promise>);
1979             return tag_invoke(*this, static_cast<_Tp&&>(__t), __promise);
1980             // NOLINTNEXTLINE(bugprone-branch-clone)
1981         }
1982         else if constexpr (__awaitable<_Tp, __unspecified>)
1983         { // NOT __awaitable<_Tp, _Promise> !!
1984             return static_cast<_Tp&&>(__t);
1985         }
1986         else if constexpr (__awaitable_sender<_Tp, _Promise>)
1987         {
1988             auto __hcoro =
1989                 __coro::coroutine_handle<_Promise>::from_promise(__promise);
1990             return __sender_awaitable_t<_Promise, _Tp>{static_cast<_Tp&&>(__t),
1991                                                        __hcoro};
1992         }
1993         else
1994         {
1995             return static_cast<_Tp&&>(__t);
1996         }
1997     }
1998 };
1999 } // namespace __as_awaitable
2000 
2001 using __as_awaitable::as_awaitable_t;
2002 inline constexpr as_awaitable_t as_awaitable{};
2003 
2004 namespace __with_awaitable_senders
2005 {
2006 
2007 template <class _Promise = void>
2008 class __continuation_handle;
2009 
2010 template <>
2011 class __continuation_handle<void>
2012 {
2013   public:
2014     __continuation_handle() = default;
2015 
2016     template <class _Promise>
__continuation_handle(__coro::coroutine_handle<_Promise> __coro)2017     __continuation_handle(__coro::coroutine_handle<_Promise> __coro) noexcept :
2018         __coro_(__coro)
2019     {
2020         if constexpr (requires(_Promise& __promise) {
2021                           __promise.unhandled_stopped();
2022                       })
2023         {
2024             __stopped_callback_ =
2025                 [](void* __address) noexcept -> __coro::coroutine_handle<> {
2026                 // This causes the rest of the coroutine (the part after the
2027                 // co_await of the sender) to be skipped and invokes the calling
2028                 // coroutine's stopped handler.
2029                 return __coro::coroutine_handle<_Promise>::from_address(
2030                            __address)
2031                     .promise()
2032                     .unhandled_stopped();
2033             };
2034         }
2035         // If _Promise doesn't implement unhandled_stopped(), then if a
2036         // "stopped" unwind reaches this point, it's considered an unhandled
2037         // exception and terminate() is called.
2038     }
2039 
handle() const2040     [[nodiscard]] auto handle() const noexcept -> __coro::coroutine_handle<>
2041     {
2042         return __coro_;
2043     }
2044 
unhandled_stopped() const2045     [[nodiscard]] auto unhandled_stopped() const noexcept
2046         -> __coro::coroutine_handle<>
2047     {
2048         return __stopped_callback_(__coro_.address());
2049     }
2050 
2051   private:
2052     __coro::coroutine_handle<> __coro_{};
2053     using __stopped_callback_t = __coro::coroutine_handle<> (*)(void*) noexcept;
2054     __stopped_callback_t __stopped_callback_ =
__anon996f5b230302(void*) 2055         [](void*) noexcept -> __coro::coroutine_handle<> { std::terminate(); };
2056 };
2057 
2058 template <class _Promise>
2059 class __continuation_handle
2060 {
2061   public:
2062     __continuation_handle() = default;
2063 
__continuation_handle(__coro::coroutine_handle<_Promise> __coro)2064     __continuation_handle(__coro::coroutine_handle<_Promise> __coro) noexcept :
2065         __continuation_{__coro}
2066     {}
2067 
handle() const2068     auto handle() const noexcept -> __coro::coroutine_handle<_Promise>
2069     {
2070         return __coro::coroutine_handle<_Promise>::from_address(
2071             __continuation_.handle().address());
2072     }
2073 
unhandled_stopped() const2074     [[nodiscard]] auto unhandled_stopped() const noexcept
2075         -> __coro::coroutine_handle<>
2076     {
2077         return __continuation_.unhandled_stopped();
2078     }
2079 
2080   private:
2081     __continuation_handle<> __continuation_{};
2082 };
2083 
2084 struct __with_awaitable_senders_base
2085 {
2086     template <class _OtherPromise>
set_continuationstdexec::__with_awaitable_senders::__with_awaitable_senders_base2087     void set_continuation(
2088         __coro::coroutine_handle<_OtherPromise> __hcoro) noexcept
2089     {
2090         static_assert(!std::is_void_v<_OtherPromise>);
2091         __continuation_ = __hcoro;
2092     }
2093 
set_continuationstdexec::__with_awaitable_senders::__with_awaitable_senders_base2094     void set_continuation(__continuation_handle<> __continuation) noexcept
2095     {
2096         __continuation_ = __continuation;
2097     }
2098 
continuationstdexec::__with_awaitable_senders::__with_awaitable_senders_base2099     [[nodiscard]] auto continuation() const noexcept -> __continuation_handle<>
2100     {
2101         return __continuation_;
2102     }
2103 
unhandled_stoppedstdexec::__with_awaitable_senders::__with_awaitable_senders_base2104     auto unhandled_stopped() noexcept -> __coro::coroutine_handle<>
2105     {
2106         return __continuation_.unhandled_stopped();
2107     }
2108 
2109   private:
2110     __continuation_handle<> __continuation_{};
2111 };
2112 
2113 template <class _Promise>
2114 struct with_awaitable_senders : __with_awaitable_senders_base
2115 {
2116     template <class _Value>
await_transformstdexec::__with_awaitable_senders::with_awaitable_senders2117     auto await_transform(_Value&& __val)
2118         -> __call_result_t<as_awaitable_t, _Value, _Promise&>
2119     {
2120         static_assert(derived_from<_Promise, with_awaitable_senders>);
2121         return as_awaitable(static_cast<_Value&&>(__val),
2122                             static_cast<_Promise&>(*this));
2123     }
2124 };
2125 } // namespace __with_awaitable_senders
2126 
2127 using __with_awaitable_senders::__continuation_handle;
2128 using __with_awaitable_senders::with_awaitable_senders;
2129 #endif
2130 
2131 namespace
2132 {
2133 inline constexpr auto __ref = []<class _Ty>(_Ty& __ty) noexcept {
2134     return [__ty = &__ty]() noexcept -> decltype(auto) { return (*__ty); };
2135 };
2136 } // namespace
2137 
2138 template <class _Ty>
2139 using __ref_t = decltype(__ref(__declval<_Ty&>()));
2140 
2141 /////////////////////////////////////////////////////////////////////////////
2142 // NOT TO SPEC: __submit
2143 namespace __submit_
2144 {
2145 template <class _OpRef>
2146 struct __receiver
2147 {
2148     using receiver_concept = receiver_t;
2149     using __t = __receiver;
2150     using __id = __receiver;
2151 
2152     using _Operation = __decay_t<__call_result_t<_OpRef>>;
2153     using _Receiver = stdexec::__t<__mapply<__q<__msecond>, _Operation>>;
2154 
2155     _OpRef __opref_;
2156 
2157     // Forward all the receiver ops, and delete the operation state.
2158     template <__completion_tag _Tag, class... _As>
2159         requires __callable<_Tag, _Receiver, _As...>
tag_invoke(_Tag __tag,__receiver && __self,_As &&...__as)2160     friend void tag_invoke(_Tag __tag, __receiver&& __self,
2161                            _As&&... __as) noexcept
2162     {
2163         __tag(static_cast<_Receiver&&>(__self.__opref_().__rcvr_),
2164               static_cast<_As&&>(__as)...);
2165         __self.__delete_op();
2166     }
2167 
__delete_opstdexec::__submit_::__receiver2168     void __delete_op() noexcept
2169     {
2170         _Operation* __op = &__opref_();
2171         if constexpr (__callable<get_allocator_t, env_of_t<_Receiver>>)
2172         {
2173             auto&& __env = get_env(__op->__rcvr_);
2174             auto __alloc = get_allocator(__env);
2175             using _Alloc = decltype(__alloc);
2176             using _OpAlloc = typename std::allocator_traits<
2177                 _Alloc>::template rebind_alloc<_Operation>;
2178             _OpAlloc __op_alloc{__alloc};
2179             std::allocator_traits<_OpAlloc>::destroy(__op_alloc, __op);
2180             std::allocator_traits<_OpAlloc>::deallocate(__op_alloc, __op, 1);
2181         }
2182         else
2183         {
2184             delete __op;
2185         }
2186     }
2187 
2188     // Forward all receiver queries.
tag_invoke(get_env_t,const __receiver & __self)2189     friend auto tag_invoke(get_env_t, const __receiver& __self) noexcept
2190         -> env_of_t<_Receiver&>
2191     {
2192         return get_env(__self.__opref_().__rcvr_);
2193     }
2194 };
2195 
2196 template <class _SenderId, class _ReceiverId>
2197 struct __operation
2198 {
2199     using _Sender = stdexec::__t<_SenderId>;
2200     using _Receiver = stdexec::__t<_ReceiverId>;
2201     using __receiver_t = __receiver<__ref_t<__operation>>;
2202 
2203     STDEXEC_ATTRIBUTE((no_unique_address))
2204     _Receiver __rcvr_;
2205     connect_result_t<_Sender, __receiver_t> __op_state_;
2206 
__operationstdexec::__submit_::__operation2207     __operation(_Sender&& __sndr, _Receiver __rcvr) :
2208         __rcvr_(static_cast<_Receiver&&>(__rcvr)),
2209         __op_state_(
2210             connect(static_cast<_Sender&&>(__sndr), __receiver_t{__ref(*this)}))
2211     {}
2212 };
2213 
2214 struct __submit_t
2215 {
2216     template <receiver _Receiver, sender_to<_Receiver> _Sender>
operator ()stdexec::__submit_::__submit_t2217     void operator()(_Sender&& __sndr, _Receiver __rcvr) const noexcept(false)
2218     {
2219         if constexpr (__callable<get_allocator_t, env_of_t<_Receiver>>)
2220         {
2221             auto&& __env = get_env(__rcvr);
2222             auto __alloc = get_allocator(__env);
2223             using _Alloc = decltype(__alloc);
2224             using _Op = __operation<__id<_Sender>, __id<_Receiver>>;
2225             using _OpAlloc = typename std::allocator_traits<
2226                 _Alloc>::template rebind_alloc<_Op>;
2227             _OpAlloc __op_alloc{__alloc};
2228             auto __op = std::allocator_traits<_OpAlloc>::allocate(__op_alloc,
2229                                                                   1);
2230             try
2231             {
2232                 std::allocator_traits<_OpAlloc>::construct(
2233                     __op_alloc, __op, static_cast<_Sender&&>(__sndr),
2234                     static_cast<_Receiver&&>(__rcvr));
2235                 start(__op->__op_state_);
2236             }
2237             catch (...)
2238             {
2239                 std::allocator_traits<_OpAlloc>::deallocate(__op_alloc, __op,
2240                                                             1);
2241                 throw;
2242             }
2243         }
2244         else
2245         {
2246             start((new __operation<__id<_Sender>, __id<_Receiver>>{
2247                        static_cast<_Sender&&>(__sndr),
2248                        static_cast<_Receiver&&>(__rcvr)})
2249                       ->__op_state_);
2250         }
2251     }
2252 };
2253 } // namespace __submit_
2254 
2255 using __submit_::__submit_t;
2256 inline constexpr __submit_t __submit{};
2257 
2258 namespace __inln
2259 {
2260 struct __schedule_t
2261 {};
2262 
2263 struct __scheduler
2264 {
2265     using __t = __scheduler;
2266     using __id = __scheduler;
2267 
2268     template <class _Tag = __schedule_t>
2269     STDEXEC_ATTRIBUTE((host, device))
tag_invoke(schedule_t,__scheduler)2270     friend auto tag_invoke(schedule_t, __scheduler)
2271     {
2272         return __make_sexpr<_Tag>();
2273     }
2274 
tag_invoke(get_forward_progress_guarantee_t,__scheduler)2275     friend auto tag_invoke(get_forward_progress_guarantee_t,
2276                            __scheduler) noexcept -> forward_progress_guarantee
2277     {
2278         return forward_progress_guarantee::weakly_parallel;
2279     }
2280 
2281     auto operator==(const __scheduler&) const noexcept -> bool = default;
2282 };
2283 } // namespace __inln
2284 
2285 template <>
2286 struct __sexpr_impl<__inln::__schedule_t> : __sexpr_defaults
2287 {
2288     static constexpr auto get_attrs = //
2289         [](__ignore) noexcept
2290         -> __env::__with<__inln::__scheduler,
__anon996f5b230502stdexec::__sexpr_impl2291                          get_completion_scheduler_t<set_value_t>> {
2292         return __env::__with(__inln::__scheduler{},
2293                              get_completion_scheduler<set_value_t>);
2294     };
2295 
2296     static constexpr auto get_completion_signatures = //
2297         [](__ignore,
__anon996f5b230602stdexec::__sexpr_impl2298            __ignore) noexcept -> completion_signatures<set_value_t()> {
2299         return {};
2300     };
2301 
2302     static constexpr auto start = //
2303         []<class _Receiver>(__ignore, _Receiver& __rcvr) noexcept -> void {
2304         set_value(static_cast<_Receiver&&>(__rcvr));
2305     };
2306 };
2307 
2308 /////////////////////////////////////////////////////////////////////////////
2309 // [execution.senders.consumer.start_detached]
2310 namespace __start_detached
2311 {
2312 template <class _EnvId>
2313 struct __detached_receiver
2314 {
2315     using _Env = stdexec::__t<_EnvId>;
2316 
2317     struct __t
2318     {
2319         using receiver_concept = receiver_t;
2320         using __id = __detached_receiver;
2321         STDEXEC_ATTRIBUTE((no_unique_address))
2322         _Env __env_;
2323 
2324         template <same_as<set_value_t> _Tag, class... _As>
tag_invokestdexec::__start_detached::__detached_receiver2325         friend void tag_invoke(_Tag, __t&&, _As&&...) noexcept
2326         {}
2327 
2328         template <same_as<set_error_t> _Tag, class _Error>
tag_invokestdexec::__start_detached::__detached_receiver2329         [[noreturn]] friend void tag_invoke(_Tag, __t&&, _Error&&) noexcept
2330         {
2331             std::terminate();
2332         }
2333 
2334         template <same_as<set_stopped_t> _Tag>
tag_invokestdexec::__start_detached::__detached_receiver2335         friend void tag_invoke(_Tag, __t&&) noexcept
2336         {}
2337 
tag_invokestdexec::__start_detached::__detached_receiver2338         friend auto tag_invoke(get_env_t, const __t& __self) noexcept
2339             -> const _Env&
2340         {
2341             // BUGBUG NOT TO SPEC
2342             return __self.__env_;
2343         }
2344     };
2345 };
2346 template <class _Env = empty_env>
2347 using __detached_receiver_t = __t<__detached_receiver<__id<__decay_t<_Env>>>>;
2348 
2349 struct start_detached_t
2350 {
2351     template <sender_in<empty_env> _Sender>
2352         requires __callable<apply_sender_t, __early_domain_of_t<_Sender>,
2353                             start_detached_t, _Sender>
operator ()stdexec::__start_detached::start_detached_t2354     void operator()(_Sender&& __sndr) const
2355     {
2356         auto __domain = __get_early_domain(__sndr);
2357         stdexec::apply_sender(__domain, *this, static_cast<_Sender&&>(__sndr));
2358     }
2359 
2360     template <class _Env, sender_in<_Env> _Sender>
2361         requires __callable<apply_sender_t, __late_domain_of_t<_Sender, _Env>,
2362                             start_detached_t, _Sender, _Env>
operator ()stdexec::__start_detached::start_detached_t2363     void operator()(_Sender&& __sndr, _Env&& __env) const
2364     {
2365         auto __domain = __get_late_domain(__sndr, __env);
2366         stdexec::apply_sender(__domain, *this, static_cast<_Sender&&>(__sndr),
2367                               static_cast<_Env&&>(__env));
2368     }
2369 
2370     using _Sender = __0;
2371     using __legacy_customizations_t =
2372         __types<tag_invoke_t(start_detached_t,
2373                              get_completion_scheduler_t<set_value_t>(
2374                                  get_env_t(const _Sender&)),
2375                              _Sender),
2376                 tag_invoke_t(start_detached_t, _Sender)>;
2377 
2378     template <class _Sender, class _Env = empty_env>
2379         requires sender_to<_Sender, __detached_receiver_t<_Env>>
apply_senderstdexec::__start_detached::start_detached_t2380     void apply_sender(_Sender&& __sndr, _Env&& __env = {}) const
2381     {
2382         __submit(static_cast<_Sender&&>(__sndr),
2383                  __detached_receiver_t<_Env>{static_cast<_Env&&>(__env)});
2384     }
2385 };
2386 } // namespace __start_detached
2387 
2388 using __start_detached::start_detached_t;
2389 inline constexpr start_detached_t start_detached{};
2390 
2391 /////////////////////////////////////////////////////////////////////////////
2392 // [execution.senders.factories]
2393 namespace __just
2394 {
2395 template <class _JustTag>
2396 struct __impl : __sexpr_defaults
2397 {
2398     using __tag_t = typename _JustTag::__tag_t;
2399 
2400     static constexpr auto get_completion_signatures =
2401         []<class _Sender>(_Sender&&, __ignore) noexcept {
2402         static_assert(sender_expr_for<_Sender, _JustTag>);
2403         return completion_signatures<
2404             __mapply<__qf<__tag_t>, __decay_t<__data_of<_Sender>>>>{};
2405     };
2406 
2407     static constexpr auto start =
2408         []<class _State, class _Receiver>(_State& __state,
2409                                           _Receiver& __rcvr) noexcept -> void {
2410         __tup::__apply(
2411             [&]<class... _Ts>(_Ts&... __ts) noexcept {
2412             __tag_t()(std::move(__rcvr), std::move(__ts)...);
2413         },
2414             __state);
2415     };
2416 };
2417 
2418 struct just_t
2419 {
2420     using __tag_t = set_value_t;
2421 
2422     template <__movable_value... _Ts>
2423     STDEXEC_ATTRIBUTE((host, device))
operator ()stdexec::__just::just_t2424     auto operator()(_Ts&&... __ts) const
2425         noexcept((__nothrow_decay_copyable<_Ts> && ...))
2426     {
2427         return __make_sexpr<just_t>(__tuple{static_cast<_Ts&&>(__ts)...});
2428     }
2429 };
2430 
2431 struct just_error_t
2432 {
2433     using __tag_t = set_error_t;
2434 
2435     template <__movable_value _Error>
2436     STDEXEC_ATTRIBUTE((host, device))
operator ()stdexec::__just::just_error_t2437     auto operator()(_Error&& __err) const
2438         noexcept(__nothrow_decay_copyable<_Error>)
2439     {
2440         return __make_sexpr<just_error_t>(
2441             __tuple{static_cast<_Error&&>(__err)});
2442     }
2443 };
2444 
2445 struct just_stopped_t
2446 {
2447     using __tag_t = set_stopped_t;
2448 
2449     template <class _Tag = just_stopped_t>
2450     STDEXEC_ATTRIBUTE((host, device))
operator ()stdexec::__just::just_stopped_t2451     auto operator()() const noexcept
2452     {
2453         return __make_sexpr<_Tag>(__tuple{});
2454     }
2455 };
2456 } // namespace __just
2457 
2458 using __just::just_error_t;
2459 using __just::just_stopped_t;
2460 using __just::just_t;
2461 
2462 template <>
2463 struct __sexpr_impl<just_t> : __just::__impl<just_t>
2464 {};
2465 
2466 template <>
2467 struct __sexpr_impl<just_error_t> : __just::__impl<just_error_t>
2468 {};
2469 
2470 template <>
2471 struct __sexpr_impl<just_stopped_t> : __just::__impl<just_stopped_t>
2472 {};
2473 
2474 inline constexpr just_t just{};
2475 inline constexpr just_error_t just_error{};
2476 inline constexpr just_stopped_t just_stopped{};
2477 
2478 /////////////////////////////////////////////////////////////////////////////
2479 // [execution.execute]
2480 namespace __execute_
2481 {
2482 template <class _Fun>
2483 struct __as_receiver
2484 {
2485     using receiver_concept = receiver_t;
2486     _Fun __fun_;
2487 
2488     template <same_as<set_value_t> _Tag>
tag_invoke(_Tag,__as_receiver && __rcvr)2489     friend void tag_invoke(_Tag, __as_receiver&& __rcvr) noexcept
2490     {
2491         try
2492         {
2493             __rcvr.__fun_();
2494         }
2495         catch (...)
2496         {
2497             set_error(static_cast<__as_receiver&&>(__rcvr),
2498                       std::exception_ptr());
2499         }
2500     }
2501 
2502     template <same_as<set_error_t> _Tag>
tag_invoke(_Tag,__as_receiver &&,std::exception_ptr)2503     [[noreturn]] friend void tag_invoke(_Tag, __as_receiver&&,
2504                                         std::exception_ptr) noexcept
2505     {
2506         std::terminate();
2507     }
2508 
2509     template <same_as<set_stopped_t> _Tag>
tag_invoke(_Tag,__as_receiver &&)2510     friend void tag_invoke(_Tag, __as_receiver&&) noexcept
2511     {}
2512 
tag_invoke(get_env_t,const __as_receiver &)2513     friend auto tag_invoke(get_env_t, const __as_receiver&) noexcept
2514         -> empty_env
2515     {
2516         return {};
2517     }
2518 };
2519 
2520 struct execute_t
2521 {
2522     template <scheduler _Scheduler, class _Fun>
2523         requires __callable<_Fun&> && move_constructible<_Fun>
operator ()stdexec::__execute_::execute_t2524     void operator()(_Scheduler&& __sched, _Fun __fun) const noexcept(false)
2525     {
2526         // Look for a legacy customization
2527         if constexpr (tag_invocable<execute_t, _Scheduler, _Fun>)
2528         {
2529             tag_invoke(execute_t{}, static_cast<_Scheduler&&>(__sched),
2530                        static_cast<_Fun&&>(__fun));
2531         }
2532         else
2533         {
2534             auto __domain = query_or(get_domain, __sched, default_domain());
2535             stdexec::apply_sender(__domain, *this,
2536                                   schedule(static_cast<_Scheduler&&>(__sched)),
2537                                   static_cast<_Fun&&>(__fun));
2538         }
2539     }
2540 
2541     template <sender_of<set_value_t()> _Sender, class _Fun>
2542         requires __callable<_Fun&> && move_constructible<_Fun>
apply_senderstdexec::__execute_::execute_t2543     void apply_sender(_Sender&& __sndr, _Fun __fun) const noexcept(false)
2544     {
2545         __submit(static_cast<_Sender&&>(__sndr),
2546                  __as_receiver<_Fun>{static_cast<_Fun&&>(__fun)});
2547     }
2548 };
2549 } // namespace __execute_
2550 
2551 using __execute_::execute_t;
2552 inline constexpr execute_t execute{};
2553 
2554 // NOT TO SPEC:
2555 namespace __closure
2556 {
2557 template <__class _Dp>
2558 struct sender_adaptor_closure;
2559 } // namespace __closure
2560 
2561 using __closure::sender_adaptor_closure;
2562 
2563 template <class _Tp>
2564 concept __sender_adaptor_closure =
2565     derived_from<__decay_t<_Tp>, sender_adaptor_closure<__decay_t<_Tp>>> &&
2566     move_constructible<__decay_t<_Tp>> &&
2567     constructible_from<__decay_t<_Tp>, _Tp>;
2568 
2569 template <class _Tp, class _Sender>
2570 concept __sender_adaptor_closure_for =
2571     __sender_adaptor_closure<_Tp> && sender<__decay_t<_Sender>> &&
2572     __callable<_Tp, __decay_t<_Sender>> &&
2573     sender<__call_result_t<_Tp, __decay_t<_Sender>>>;
2574 
2575 namespace __closure
2576 {
2577 template <class _T0, class _T1>
2578 struct __compose : sender_adaptor_closure<__compose<_T0, _T1>>
2579 {
2580     STDEXEC_ATTRIBUTE((no_unique_address))
2581     _T0 __t0_;
2582     STDEXEC_ATTRIBUTE((no_unique_address))
2583     _T1 __t1_;
2584 
2585     template <sender _Sender>
2586         requires __callable<_T0, _Sender> &&
2587                  __callable<_T1, __call_result_t<_T0, _Sender>>
2588     STDEXEC_ATTRIBUTE((always_inline))
2589         __call_result_t<_T1, __call_result_t<_T0, _Sender>>
operator ()stdexec::__closure::__compose2590         operator()(_Sender&& __sndr) &&
2591     {
2592         return static_cast<_T1&&>(__t1_)(
2593             static_cast<_T0&&>(__t0_)(static_cast<_Sender&&>(__sndr)));
2594     }
2595 
2596     template <sender _Sender>
2597         requires __callable<const _T0&, _Sender> &&
2598                  __callable<const _T1&, __call_result_t<const _T0&, _Sender>>
2599     STDEXEC_ATTRIBUTE((always_inline))
2600         __call_result_t<_T1, __call_result_t<_T0, _Sender>>
operator ()stdexec::__closure::__compose2601         operator()(_Sender&& __sndr) const&
2602     {
2603         return __t1_(__t0_(static_cast<_Sender&&>(__sndr)));
2604     }
2605 };
2606 
2607 template <__class _Dp>
2608 struct sender_adaptor_closure
2609 {};
2610 
2611 template <sender _Sender, __sender_adaptor_closure_for<_Sender> _Closure>
2612 STDEXEC_ATTRIBUTE((always_inline))
operator |(_Sender && __sndr,_Closure && __clsur)2613 __call_result_t<_Closure, _Sender> operator|(_Sender&& __sndr,
2614                                              _Closure&& __clsur)
2615 {
2616     return static_cast<_Closure&&>(__clsur)(static_cast<_Sender&&>(__sndr));
2617 }
2618 
2619 template <__sender_adaptor_closure _T0, __sender_adaptor_closure _T1>
2620 STDEXEC_ATTRIBUTE((always_inline))
operator |(_T0 && __t0,_T1 && __t1)2621 __compose<__decay_t<_T0>, __decay_t<_T1>> operator|(_T0&& __t0, _T1&& __t1)
2622 {
2623     return {{}, static_cast<_T0&&>(__t0), static_cast<_T1&&>(__t1)};
2624 }
2625 
2626 template <class _Fun, class... _As>
2627 struct __binder_back : sender_adaptor_closure<__binder_back<_Fun, _As...>>
2628 {
2629     STDEXEC_ATTRIBUTE((no_unique_address))
2630     _Fun __fun_;
2631     std::tuple<_As...> __as_;
2632 
2633     template <sender _Sender>
2634         requires __callable<_Fun, _Sender, _As...>
2635     STDEXEC_ATTRIBUTE((host, device,
2636                        always_inline)) __call_result_t<_Fun, _Sender, _As...>
operator ()stdexec::__closure::__binder_back2637         operator()(_Sender&& __sndr) && noexcept(
2638             __nothrow_callable<_Fun, _Sender, _As...>)
2639     {
2640         return __apply(
2641             [&__sndr,
2642              this](_As&... __as) -> __call_result_t<_Fun, _Sender, _As...> {
2643             return static_cast<_Fun&&>(__fun_)(static_cast<_Sender&&>(__sndr),
2644                                                static_cast<_As&&>(__as)...);
2645         },
2646             __as_);
2647     }
2648 
2649     template <sender _Sender>
2650         requires __callable<const _Fun&, _Sender, const _As&...>
2651     STDEXEC_ATTRIBUTE((host, device)) auto
operator ()stdexec::__closure::__binder_back2652         operator()(_Sender&& __sndr) const& //
2653         noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
2654             -> __call_result_t<const _Fun&, _Sender, const _As&...>
2655     {
2656         return __apply(
2657             [&__sndr, this](const _As&... __as)
2658                 -> __call_result_t<const _Fun&, _Sender, const _As&...> {
2659             return __fun_(static_cast<_Sender&&>(__sndr), __as...);
2660         },
2661             __as_);
2662     }
2663 };
2664 } // namespace __closure
2665 
2666 using __closure::__binder_back;
2667 
2668 namespace __adaptors
2669 {
2670 STDEXEC_PRAGMA_PUSH()
2671 STDEXEC_PRAGMA_IGNORE_GNU("-Wold-style-cast")
2672 
2673 // A derived-to-base cast that works even when the base is not
2674 // accessible from derived.
2675 template <class _Tp, class _Up>
2676 STDEXEC_ATTRIBUTE((host, device))
__c_cast(_Up && u)2677 auto __c_cast(_Up&& u) noexcept -> __copy_cvref_t<_Up&&, _Tp>
2678     requires __decays_to<_Tp, _Tp>
2679 {
2680     static_assert(std::is_reference_v<__copy_cvref_t<_Up&&, _Tp>>);
2681     static_assert(STDEXEC_IS_BASE_OF(_Tp, __decay_t<_Up>));
2682     return (__copy_cvref_t<_Up&&, _Tp>)static_cast<_Up&&>(u);
2683 }
2684 STDEXEC_PRAGMA_POP()
2685 
2686 namespace __no
2687 {
2688 struct __nope
2689 {};
2690 
2691 struct __receiver : __nope
2692 {
2693     using receiver_concept = receiver_t;
2694 };
2695 
2696 template <same_as<set_error_t> _Tag>
2697 void tag_invoke(_Tag, __receiver, std::exception_ptr) noexcept;
2698 template <same_as<set_stopped_t> _Tag>
2699 void tag_invoke(_Tag, __receiver) noexcept;
2700 auto tag_invoke(get_env_t, __receiver) noexcept -> empty_env;
2701 } // namespace __no
2702 
2703 using __not_a_receiver = __no::__receiver;
2704 
2705 template <class _Base>
2706 struct __adaptor_base
2707 {
2708     template <class _T1>
2709         requires constructible_from<_Base, _T1>
__adaptor_basestdexec::__adaptors::__adaptor_base2710     explicit __adaptor_base(_T1&& __base) : __base_(static_cast<_T1&&>(__base))
2711     {}
2712 
2713   private:
2714     STDEXEC_ATTRIBUTE((no_unique_address))
2715     _Base __base_;
2716 
2717   protected:
2718     STDEXEC_ATTRIBUTE((host, device, always_inline))
2719 
basestdexec::__adaptors::__adaptor_base2720     _Base& base() & noexcept
2721     {
2722         return __base_;
2723     }
2724 
2725     STDEXEC_ATTRIBUTE((host, device, always_inline))
2726 
basestdexec::__adaptors::__adaptor_base2727     const _Base& base() const& noexcept
2728     {
2729         return __base_;
2730     }
2731 
2732     STDEXEC_ATTRIBUTE((host, device, always_inline))
2733 
basestdexec::__adaptors::__adaptor_base2734     _Base&& base() && noexcept
2735     {
2736         return static_cast<_Base&&>(__base_);
2737     }
2738 };
2739 
2740 template <derived_from<__no::__nope> _Base>
2741 struct __adaptor_base<_Base>
2742 {};
2743 
2744 // BUGBUG Not to spec: on gcc and nvc++, member functions in derived classes
2745 // don't shadow type aliases of the same name in base classes. :-O
2746 // On mingw gcc, 'bool(type::existing_member_function)' evaluates to true,
2747 // but 'int(type::existing_member_function)' is an error (as desired).
2748 #define STDEXEC_DISPATCH_MEMBER(_TAG)                                          \
2749     template <class _Self, class... _Ts>                                       \
2750     STDEXEC_ATTRIBUTE((host, device, always_inline))                           \
2751     static auto __call_##_TAG(_Self&& __self, _Ts&&... __ts) noexcept          \
2752         -> decltype((static_cast<_Self&&>(__self))                             \
2753                         ._TAG(static_cast<_Ts&&>(__ts)...))                    \
2754     {                                                                          \
2755         static_assert(noexcept((static_cast<_Self&&>(__self))                  \
2756                                    ._TAG(static_cast<_Ts&&>(__ts)...)));       \
2757         return static_cast<_Self&&>(__self)._TAG(static_cast<_Ts&&>(__ts)...); \
2758     } /**/
2759 #define STDEXEC_CALL_MEMBER(_TAG, ...) __call_##_TAG(__VA_ARGS__)
2760 
2761 #if STDEXEC_CLANG()
2762 // Only clang gets this right.
2763 #define STDEXEC_MISSING_MEMBER(_Dp, _TAG) requires { typename _Dp::_TAG; }
2764 #define STDEXEC_DEFINE_MEMBER(_TAG)                                            \
2765     STDEXEC_DISPATCH_MEMBER(_TAG) using _TAG = void
2766 #else
2767 #define STDEXEC_MISSING_MEMBER(_Dp, _TAG) (__missing_##_TAG<_Dp>())
2768 #define STDEXEC_DEFINE_MEMBER(_TAG)                                            \
2769     template <class _Dp>                                                       \
2770     static constexpr bool __missing_##_TAG() noexcept                          \
2771     {                                                                          \
2772         return requires { requires bool(int(_Dp::_TAG)); };                    \
2773     }                                                                          \
2774     STDEXEC_DISPATCH_MEMBER(_TAG)                                              \
2775     static constexpr int _TAG = 1 /**/
2776 #endif
2777 
2778 template <__class _Derived, class _Base = __not_a_receiver>
2779 struct receiver_adaptor : __adaptor_base<_Base>, receiver_t
2780 {
2781     friend _Derived;
2782     STDEXEC_DEFINE_MEMBER(set_value);
2783     STDEXEC_DEFINE_MEMBER(set_error);
2784     STDEXEC_DEFINE_MEMBER(set_stopped);
2785     STDEXEC_DEFINE_MEMBER(get_env);
2786 
2787     static constexpr bool __has_base = !derived_from<_Base, __no::__nope>;
2788 
2789     template <class _Dp>
2790     using __base_from_derived_t = decltype(__declval<_Dp>().base());
2791 
2792     using __get_base_t =
2793         __if_c<__has_base, __mbind_back_q<__copy_cvref_t, _Base>,
2794                __q<__base_from_derived_t>>;
2795 
2796     template <class _Dp>
2797     using __base_t = __minvoke<__get_base_t, _Dp&&>;
2798 
2799     template <class _Dp>
2800     STDEXEC_ATTRIBUTE((host, device))
__get_basestdexec::__adaptors::receiver_adaptor2801     static auto __get_base(_Dp&& __self) noexcept -> __base_t<_Dp>
2802     {
2803         if constexpr (__has_base)
2804         {
2805             return __c_cast<receiver_adaptor>(static_cast<_Dp&&>(__self))
2806                 .base();
2807         }
2808         else
2809         {
2810             return static_cast<_Dp&&>(__self).base();
2811         }
2812     }
2813 
2814     template <same_as<set_value_t> _SetValue, class... _As>
2815     STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_SetValue,_Derived && __self,_As &&...__as)2816     friend auto tag_invoke(_SetValue, _Derived&& __self,
2817                            _As&&... __as) noexcept //
2818         -> __msecond<                              //
2819             __if_c<same_as<set_value_t, _SetValue>>,
2820             decltype(STDEXEC_CALL_MEMBER(set_value,
2821                                          static_cast<_Derived&&>(__self),
2822                                          static_cast<_As&&>(__as)...))>
2823     {
2824         static_assert(noexcept(
2825             STDEXEC_CALL_MEMBER(set_value, static_cast<_Derived&&>(__self),
2826                                 static_cast<_As&&>(__as)...)));
2827         STDEXEC_CALL_MEMBER(set_value, static_cast<_Derived&&>(__self),
2828                             static_cast<_As&&>(__as)...);
2829     }
2830 
2831     template <same_as<set_value_t> _SetValue, class _Dp = _Derived,
2832               class... _As>
STDEXEC_MISSING_MEMBER(_Dp,set_value)2833         requires STDEXEC_MISSING_MEMBER
2834     (_Dp, set_value) &&
2835         tag_invocable<_SetValue, __base_t<_Dp>, _As...> STDEXEC_ATTRIBUTE((
2836             host, device,
2837             always_inline)) friend void tag_invoke(_SetValue, _Derived&& __self,
2838                                                    _As&&... __as) noexcept
2839     {
2840         stdexec::set_value(__get_base(static_cast<_Dp&&>(__self)),
2841                            static_cast<_As&&>(__as)...);
2842     }
2843 
2844     template <same_as<set_error_t> _SetError, class _Error>
2845     STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_SetError,_Derived && __self,_Error && __err)2846     friend auto tag_invoke(_SetError, _Derived&& __self,
2847                            _Error&& __err) noexcept //
2848         -> __msecond<                               //
2849             __if_c<same_as<set_error_t, _SetError>>,
2850             decltype(STDEXEC_CALL_MEMBER(set_error,
2851                                          static_cast<_Derived&&>(__self),
2852                                          static_cast<_Error&&>(__err)))>
2853     {
2854         static_assert(noexcept(
2855             STDEXEC_CALL_MEMBER(set_error, static_cast<_Derived&&>(__self),
2856                                 static_cast<_Error&&>(__err))));
2857         STDEXEC_CALL_MEMBER(set_error, static_cast<_Derived&&>(__self),
2858                             static_cast<_Error&&>(__err));
2859     }
2860 
2861     template <same_as<set_error_t> _SetError, class _Error,
2862               class _Dp = _Derived>
STDEXEC_MISSING_MEMBER(_Dp,set_error)2863         requires STDEXEC_MISSING_MEMBER
2864     (_Dp, set_error) &&
2865         tag_invocable<_SetError, __base_t<_Dp>, _Error> STDEXEC_ATTRIBUTE((
2866             host, device,
2867             always_inline)) friend void tag_invoke(_SetError, _Derived&& __self,
2868                                                    _Error&& __err) noexcept
2869     {
2870         stdexec::set_error(__get_base(static_cast<_Derived&&>(__self)),
2871                            static_cast<_Error&&>(__err));
2872     }
2873 
2874     template <same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
2875     STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_SetStopped,_Derived && __self)2876     friend auto tag_invoke(_SetStopped, _Derived&& __self) noexcept //
2877         -> __msecond<                                               //
2878             __if_c<same_as<set_stopped_t, _SetStopped>>,
2879             decltype(STDEXEC_CALL_MEMBER(set_stopped,
2880                                          static_cast<_Dp&&>(__self)))>
2881     {
2882         static_assert(noexcept(
2883             STDEXEC_CALL_MEMBER(set_stopped, static_cast<_Derived&&>(__self))));
2884         STDEXEC_CALL_MEMBER(set_stopped, static_cast<_Derived&&>(__self));
2885     }
2886 
2887     template <same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
STDEXEC_MISSING_MEMBER(_Dp,set_stopped)2888         requires STDEXEC_MISSING_MEMBER
2889     (_Dp, set_stopped) &&
2890         tag_invocable<_SetStopped, __base_t<_Dp>> STDEXEC_ATTRIBUTE(
2891             (host, device,
2892              always_inline)) friend void tag_invoke(_SetStopped,
2893                                                     _Derived&& __self) noexcept
2894     {
2895         stdexec::set_stopped(__get_base(static_cast<_Derived&&>(__self)));
2896     }
2897 
2898     // Pass through the get_env receiver query
2899     template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
2900     STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_GetEnv,const _Derived & __self)2901     friend auto tag_invoke(_GetEnv, const _Derived& __self) noexcept
2902         -> decltype(STDEXEC_CALL_MEMBER(get_env,
2903                                         static_cast<const _Dp&>(__self)))
2904     {
2905         static_assert(noexcept(STDEXEC_CALL_MEMBER(get_env, __self)));
2906         return STDEXEC_CALL_MEMBER(get_env, __self);
2907     }
2908 
2909     template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
STDEXEC_MISSING_MEMBER(_Dp,get_env)2910         requires STDEXEC_MISSING_MEMBER
2911     (_Dp, get_env)
2912         STDEXEC_ATTRIBUTE((host, device, always_inline)) friend auto tag_invoke(
2913             _GetEnv, const _Derived& __self) noexcept
2914         -> env_of_t<__base_t<const _Dp&>>
2915     {
2916         return stdexec::get_env(__get_base(__self));
2917     }
2918 
2919   public:
2920     receiver_adaptor() = default;
2921     using __adaptor_base<_Base>::__adaptor_base;
2922 
2923     using receiver_concept = receiver_t;
2924 };
2925 } // namespace __adaptors
2926 
2927 template <__class _Derived, receiver _Base = __adaptors::__not_a_receiver>
2928 using receiver_adaptor = __adaptors::receiver_adaptor<_Derived, _Base>;
2929 
2930 template <class _Receiver, class _Fun, class... _As>
2931 concept __receiver_of_invoke_result = //
2932     receiver_of<_Receiver, completion_signatures<
2933                                __minvoke<__remove<void, __qf<set_value_t>>,
2934                                          __invoke_result_t<_Fun, _As...>>>>;
2935 
2936 template <bool _CanThrow = false, class _Receiver, class _Fun, class... _As>
__set_value_invoke(_Receiver && __rcvr,_Fun && __fun,_As &&...__as)2937 void __set_value_invoke(_Receiver&& __rcvr, _Fun&& __fun,
2938                         _As&&... __as) noexcept(!_CanThrow)
2939 {
2940     if constexpr (_CanThrow || __nothrow_invocable<_Fun, _As...>)
2941     {
2942         if constexpr (same_as<void, __invoke_result_t<_Fun, _As...>>)
2943         {
2944             __invoke(static_cast<_Fun&&>(__fun), static_cast<_As&&>(__as)...);
2945             set_value(static_cast<_Receiver&&>(__rcvr));
2946         }
2947         else
2948         {
2949             set_value(static_cast<_Receiver&&>(__rcvr),
2950                       __invoke(static_cast<_Fun&&>(__fun),
2951                                static_cast<_As&&>(__as)...));
2952         }
2953     }
2954     else
2955     {
2956         try
2957         {
2958             stdexec::__set_value_invoke<true>(static_cast<_Receiver&&>(__rcvr),
2959                                               static_cast<_Fun&&>(__fun),
2960                                               static_cast<_As&&>(__as)...);
2961         }
2962         catch (...)
2963         {
2964             set_error(static_cast<_Receiver&&>(__rcvr),
2965                       std::current_exception());
2966         }
2967     }
2968 }
2969 
2970 template <class _Fun>
2971 struct _WITH_FUNCTION_
2972 {};
2973 
2974 template <class... _Args>
2975 struct _WITH_ARGUMENTS_
2976 {};
2977 
2978 inline constexpr __mstring __not_callable_diag =
2979     "The specified function is not callable with the arguments provided."_mstr;
2980 
2981 template <__mstring _Context, __mstring _Diagnostic = __not_callable_diag>
2982 struct _NOT_CALLABLE_
2983 {};
2984 
2985 template <__mstring _Context>
2986 struct __callable_error
2987 {
2988     template <class _Fun, class... _Args>
2989     using __f =       //
2990         __mexception< //
2991             _NOT_CALLABLE_<_Context>, _WITH_FUNCTION_<_Fun>,
2992             _WITH_ARGUMENTS_<_Args...>>;
2993 };
2994 
2995 template <class _Fun, class... _Args>
2996     requires __invocable<_Fun, _Args...>
2997 using __non_throwing_ = __mbool<__nothrow_invocable<_Fun, _Args...>>;
2998 
2999 template <class _Tag, class _Fun, class _Sender, class _Env, class _Catch>
3000 using __with_error_invoke_t = //
3001     __if<__gather_completions_for<
3002              _Tag, _Sender, _Env,
3003              __mbind_front<__mtry_catch_q<__non_throwing_, _Catch>, _Fun>,
3004              __q<__mand>>,
3005          completion_signatures<>, __with_exception_ptr>;
3006 
3007 template <class _Fun, class... _Args>
3008     requires __invocable<_Fun, _Args...>
3009 using __set_value_invoke_t = //
3010     completion_signatures<__minvoke<__remove<void, __qf<set_value_t>>,
3011                                     __invoke_result_t<_Fun, _Args...>>>;
3012 
3013 /////////////////////////////////////////////////////////////////////////////
3014 // [execution.senders.adaptors.then]
3015 namespace __then
3016 {
3017 inline constexpr __mstring __then_context =
3018     "In stdexec::then(Sender, Function)..."_mstr;
3019 using __on_not_callable = __callable_error<__then_context>;
3020 
3021 template <class _Fun, class _CvrefSender, class _Env>
3022 using __completion_signatures_t = //
3023     __try_make_completion_signatures<
3024         _CvrefSender, _Env,
3025         __with_error_invoke_t<set_value_t, _Fun, _CvrefSender, _Env,
3026                               __on_not_callable>,
3027         __mbind_front<__mtry_catch_q<__set_value_invoke_t, __on_not_callable>,
3028                       _Fun>>;
3029 
3030 ////////////////////////////////////////////////////////////////////////////////////////////////
3031 struct then_t
3032 {
3033     template <sender _Sender, __movable_value _Fun>
operator ()stdexec::__then::then_t3034     auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender
3035         auto
3036     {
3037         auto __domain = __get_early_domain(__sndr);
3038         return stdexec::transform_sender(
3039             __domain, __make_sexpr<then_t>(static_cast<_Fun&&>(__fun),
3040                                            static_cast<_Sender&&>(__sndr)));
3041     }
3042 
3043     template <__movable_value _Fun>
3044     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__then::then_t3045     __binder_back<then_t, _Fun> operator()(_Fun __fun) const
3046     {
3047         return {{}, {}, {static_cast<_Fun&&>(__fun)}};
3048     }
3049 
3050     using _Sender = __1;
3051     using _Fun = __0;
3052     using __legacy_customizations_t =
3053         __types<tag_invoke_t(then_t,
3054                              get_completion_scheduler_t<set_value_t>(
3055                                  get_env_t(_Sender&)),
3056                              _Sender, _Fun),
3057                 tag_invoke_t(then_t, _Sender, _Fun)>;
3058 };
3059 
3060 struct __then_impl : __sexpr_defaults
3061 {
3062     static constexpr auto get_completion_signatures = //
3063         []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
3064         -> __completion_signatures_t<__decay_t<__data_of<_Sender>>,
3065                                      __child_of<_Sender>, _Env> {
3066         static_assert(sender_expr_for<_Sender, then_t>);
3067         return {};
3068     };
3069 
3070     static constexpr auto complete = //
3071         []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
3072                                        _Tag,
3073                                        _Args&&... __args) noexcept -> void {
3074         if constexpr (std::same_as<_Tag, set_value_t>)
3075         {
3076             stdexec::__set_value_invoke(std::move(__rcvr), std::move(__state),
3077                                         static_cast<_Args&&>(__args)...);
3078         }
3079         else
3080         {
3081             _Tag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
3082         }
3083     };
3084 };
3085 } // namespace __then
3086 
3087 using __then::then_t;
3088 
3089 /// @brief The then sender adaptor, which invokes a function with the result of
3090 ///        a sender, making the result available to the next receiver.
3091 /// @hideinitializer
3092 inline constexpr then_t then{};
3093 
3094 template <>
3095 struct __sexpr_impl<then_t> : __then::__then_impl
3096 {};
3097 
3098 /////////////////////////////////////////////////////////////////////////////
3099 // [execution.senders.adaptors.upon_error]
3100 namespace __upon_error
3101 {
3102 inline constexpr __mstring __upon_error_context =
3103     "In stdexec::upon_error(Sender, Function)..."_mstr;
3104 using __on_not_callable = __callable_error<__upon_error_context>;
3105 
3106 template <class _Fun, class _CvrefSender, class _Env>
3107 using __completion_signatures_t = //
3108     __try_make_completion_signatures<
3109         _CvrefSender, _Env,
3110         __with_error_invoke_t<set_error_t, _Fun, _CvrefSender, _Env,
3111                               __on_not_callable>,
3112         __q<__compl_sigs::__default_set_value>,
3113         __mbind_front<__mtry_catch_q<__set_value_invoke_t, __on_not_callable>,
3114                       _Fun>>;
3115 
3116 ////////////////////////////////////////////////////////////////////////////////////////////////
3117 struct upon_error_t
3118 {
3119     template <sender _Sender, __movable_value _Fun>
operator ()stdexec::__upon_error::upon_error_t3120     auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender
3121         auto
3122     {
3123         auto __domain = __get_early_domain(__sndr);
3124         return stdexec::transform_sender(
3125             __domain,
3126             __make_sexpr<upon_error_t>(static_cast<_Fun&&>(__fun),
3127                                        static_cast<_Sender&&>(__sndr)));
3128     }
3129 
3130     template <__movable_value _Fun>
3131     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__upon_error::upon_error_t3132     __binder_back<upon_error_t, _Fun> operator()(_Fun __fun) const
3133     {
3134         return {{}, {}, {static_cast<_Fun&&>(__fun)}};
3135     }
3136 
3137     using _Sender = __1;
3138     using _Fun = __0;
3139     using __legacy_customizations_t =
3140         __types<tag_invoke_t(upon_error_t,
3141                              get_completion_scheduler_t<set_value_t>(
3142                                  get_env_t(_Sender&)),
3143                              _Sender, _Fun),
3144                 tag_invoke_t(upon_error_t, _Sender, _Fun)>;
3145 };
3146 
3147 struct __upon_error_impl : __sexpr_defaults
3148 {
3149     static constexpr auto get_completion_signatures = //
3150         []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
3151         -> __completion_signatures_t<__decay_t<__data_of<_Sender>>,
3152                                      __child_of<_Sender>, _Env> {
3153         static_assert(sender_expr_for<_Sender, upon_error_t>);
3154         return {};
3155     };
3156 
3157     static constexpr auto complete = //
3158         []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
3159                                        _Tag,
3160                                        _Args&&... __args) noexcept -> void {
3161         if constexpr (std::same_as<_Tag, set_error_t>)
3162         {
3163             stdexec::__set_value_invoke(std::move(__rcvr), std::move(__state),
3164                                         static_cast<_Args&&>(__args)...);
3165         }
3166         else
3167         {
3168             _Tag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
3169         }
3170     };
3171 };
3172 } // namespace __upon_error
3173 
3174 using __upon_error::upon_error_t;
3175 inline constexpr upon_error_t upon_error{};
3176 
3177 template <>
3178 struct __sexpr_impl<upon_error_t> : __upon_error::__upon_error_impl
3179 {};
3180 
3181 /////////////////////////////////////////////////////////////////////////////
3182 // [execution.senders.adaptors.upon_stopped]
3183 namespace __upon_stopped
3184 {
3185 inline constexpr __mstring __upon_stopped_context =
3186     "In stdexec::upon_stopped(Sender, Function)..."_mstr;
3187 using __on_not_callable = __callable_error<__upon_stopped_context>;
3188 
3189 template <class _Fun, class _CvrefSender, class _Env>
3190 using __completion_signatures_t = //
3191     __try_make_completion_signatures<
3192         _CvrefSender, _Env,
3193         __with_error_invoke_t<set_stopped_t, _Fun, _CvrefSender, _Env,
3194                               __on_not_callable>,
3195         __q<__compl_sigs::__default_set_value>,
3196         __q<__compl_sigs::__default_set_error>, __set_value_invoke_t<_Fun>>;
3197 
3198 ////////////////////////////////////////////////////////////////////////////////////////////////
3199 struct upon_stopped_t
3200 {
3201     template <sender _Sender, __movable_value _Fun>
3202         requires __callable<_Fun>
operator ()stdexec::__upon_stopped::upon_stopped_t3203     auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender
3204         auto
3205     {
3206         auto __domain = __get_early_domain(__sndr);
3207         return stdexec::transform_sender(
3208             __domain,
3209             __make_sexpr<upon_stopped_t>(static_cast<_Fun&&>(__fun),
3210                                          static_cast<_Sender&&>(__sndr)));
3211     }
3212 
3213     template <__movable_value _Fun>
3214         requires __callable<_Fun>
3215     STDEXEC_ATTRIBUTE((always_inline)) __binder_back<upon_stopped_t, _Fun>
operator ()stdexec::__upon_stopped::upon_stopped_t3216         operator()(_Fun __fun) const
3217     {
3218         return {{}, {}, {static_cast<_Fun&&>(__fun)}};
3219     }
3220 
3221     using _Sender = __1;
3222     using _Fun = __0;
3223     using __legacy_customizations_t =
3224         __types<tag_invoke_t(upon_stopped_t,
3225                              get_completion_scheduler_t<set_value_t>(
3226                                  get_env_t(_Sender&)),
3227                              _Sender, _Fun),
3228                 tag_invoke_t(upon_stopped_t, _Sender, _Fun)>;
3229 };
3230 
3231 struct __upon_stopped_impl : __sexpr_defaults
3232 {
3233     static constexpr auto get_completion_signatures = //
3234         []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
3235         -> __completion_signatures_t<__decay_t<__data_of<_Sender>>,
3236                                      __child_of<_Sender>, _Env> {
3237         static_assert(sender_expr_for<_Sender, upon_stopped_t>);
3238         return {};
3239     };
3240 
3241     static constexpr auto complete = //
3242         []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
3243                                        _Tag,
3244                                        _Args&&... __args) noexcept -> void {
3245         if constexpr (std::same_as<_Tag, set_stopped_t>)
3246         {
3247             stdexec::__set_value_invoke(std::move(__rcvr), std::move(__state),
3248                                         static_cast<_Args&&>(__args)...);
3249         }
3250         else
3251         {
3252             _Tag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
3253         }
3254     };
3255 };
3256 } // namespace __upon_stopped
3257 
3258 using __upon_stopped::upon_stopped_t;
3259 inline constexpr upon_stopped_t upon_stopped{};
3260 
3261 template <>
3262 struct __sexpr_impl<upon_stopped_t> : __upon_stopped::__upon_stopped_impl
3263 {};
3264 
3265 /////////////////////////////////////////////////////////////////////////////
3266 // [execution.senders.adaptors.bulk]
3267 namespace __bulk
3268 {
3269 inline constexpr __mstring __bulk_context =
3270     "In stdexec::bulk(Sender, Shape, Function)..."_mstr;
3271 using __on_not_callable = __callable_error<__bulk_context>;
3272 
3273 template <class _Shape, class _Fun>
3274 struct __data
3275 {
3276     _Shape __shape_;
3277     STDEXEC_ATTRIBUTE((no_unique_address))
3278     _Fun __fun_;
3279     static constexpr auto __mbrs_ =
3280         __mliterals<&__data::__shape_, &__data::__fun_>();
3281 };
3282 template <class _Shape, class _Fun>
3283 __data(_Shape, _Fun) -> __data<_Shape, _Fun>;
3284 
3285 template <class _Ty>
3286 using __decay_ref = __decay_t<_Ty>&;
3287 
3288 template <class _CvrefSender, class _Env, class _Shape, class _Fun,
3289           class _Catch>
3290 using __with_error_invoke_t = //
3291     __if<__try_value_types_of_t<
3292              _CvrefSender, _Env,
3293              __transform<__q<__decay_ref>,
3294                          __mbind_front<__mtry_catch_q<__non_throwing_, _Catch>,
3295                                        _Fun, _Shape>>,
3296              __q<__mand>>,
3297          completion_signatures<>, __with_exception_ptr>;
3298 
3299 template <class _CvrefSender, class _Env, class _Shape, class _Fun>
3300 using __completion_signatures = //
3301     __try_make_completion_signatures<
3302         _CvrefSender, _Env,
3303         __with_error_invoke_t<_CvrefSender, _Env, _Shape, _Fun,
3304                               __on_not_callable>>;
3305 
3306 struct bulk_t
3307 {
3308     template <sender _Sender, integral _Shape, __movable_value _Fun>
3309     STDEXEC_ATTRIBUTE((host, device))
operator ()stdexec::__bulk::bulk_t3310     auto operator()(_Sender&& __sndr, _Shape __shape, _Fun __fun) const
3311         -> __well_formed_sender auto
3312     {
3313         auto __domain = __get_early_domain(__sndr);
3314         return stdexec::transform_sender(
3315             __domain,
3316             __make_sexpr<bulk_t>(__data{__shape, static_cast<_Fun&&>(__fun)},
3317                                  static_cast<_Sender&&>(__sndr)));
3318     }
3319 
3320     template <integral _Shape, class _Fun>
3321     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__bulk::bulk_t3322     __binder_back<bulk_t, _Shape, _Fun> operator()(_Shape __shape,
3323                                                    _Fun __fun) const
3324     {
3325         return {{},
3326                 {},
3327                 {static_cast<_Shape&&>(__shape), static_cast<_Fun&&>(__fun)}};
3328     }
3329 
3330     // This describes how to use the pieces of a bulk sender to find
3331     // legacy customizations of the bulk algorithm.
3332     using _Sender = __1;
3333     using _Shape = __nth_member<0>(__0);
3334     using _Fun = __nth_member<1>(__0);
3335     using __legacy_customizations_t =
3336         __types<tag_invoke_t(bulk_t,
3337                              get_completion_scheduler_t<set_value_t>(
3338                                  get_env_t(_Sender&)),
3339                              _Sender, _Shape, _Fun),
3340                 tag_invoke_t(bulk_t, _Sender, _Shape, _Fun)>;
3341 };
3342 
3343 struct __bulk_impl : __sexpr_defaults
3344 {
3345     template <class _Sender>
3346     using __fun_t = decltype(__decay_t<__data_of<_Sender>>::__fun_);
3347 
3348     template <class _Sender>
3349     using __shape_t = decltype(__decay_t<__data_of<_Sender>>::__shape_);
3350 
3351     static constexpr auto get_completion_signatures = //
3352         []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
3353         -> __completion_signatures<__child_of<_Sender>, _Env,
3354                                    __shape_t<_Sender>, __fun_t<_Sender>> {
3355         static_assert(sender_expr_for<_Sender, bulk_t>);
3356         return {};
3357     };
3358 
3359     static constexpr auto complete = //
3360         []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
3361                                        _Tag,
3362                                        _Args&&... __args) noexcept -> void {
3363         if constexpr (std::same_as<_Tag, set_value_t>)
3364         {
3365             using __shape_t = decltype(__state.__shape_);
3366             if constexpr (noexcept(__state.__fun_(__shape_t{}, __args...)))
3367             {
3368                 for (__shape_t __i{}; __i != __state.__shape_; ++__i)
3369                 {
3370                     __state.__fun_(__i, __args...);
3371                 }
3372                 _Tag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
3373             }
3374             else
3375             {
3376                 try
3377                 {
3378                     for (__shape_t __i{}; __i != __state.__shape_; ++__i)
3379                     {
3380                         __state.__fun_(__i, __args...);
3381                     }
3382                     _Tag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
3383                 }
3384                 catch (...)
3385                 {
3386                     set_error(std::move(__rcvr), std::current_exception());
3387                 }
3388             }
3389         }
3390         else
3391         {
3392             _Tag()(std::move(__rcvr), static_cast<_Args&&>(__args)...);
3393         }
3394     };
3395 };
3396 } // namespace __bulk
3397 
3398 using __bulk::bulk_t;
3399 inline constexpr bulk_t bulk{};
3400 
3401 template <>
3402 struct __sexpr_impl<bulk_t> : __bulk::__bulk_impl
3403 {};
3404 
3405 ////////////////////////////////////////////////////////////////////////////
3406 // shared components of split and ensure_started
3407 //
3408 // The split and ensure_started algorithms are very similar in implementation.
3409 // The salient differences are:
3410 //
3411 // split: the input async operation is always connected. It is only
3412 //   started when one of the split senders is connected and started.
3413 //   split senders are copyable, so there are multiple operation states
3414 //   to be notified on completion. These are stored in an instrusive
3415 //   linked list.
3416 //
3417 // ensure_started: the input async operation is always started, so
3418 //   the internal receiver will always be completed. The ensure_started
3419 //   sender is move-only and single-shot, so there will only ever be one
3420 //   operation state to be notified on completion.
3421 //
3422 // The shared state should add-ref itself when the input async
3423 // operation is started and release itself when its completion
3424 // is notified.
3425 namespace __shared
3426 {
3427 template <class _BaseEnv>
3428 using __env_t =                //
3429     __env::__join_t<__env::__with<in_place_stop_token, get_stop_token_t>,
3430                     _BaseEnv>; // BUGBUG NOT TO SPEC
3431 
3432 struct __on_stop_request
3433 {
3434     in_place_stop_source& __stop_source_;
3435 
operator ()stdexec::__shared::__on_stop_request3436     void operator()() noexcept
3437     {
3438         __stop_source_.request_stop();
3439     }
3440 };
3441 
3442 template <class _Receiver>
__notify_visitor(_Receiver & __rcvr)3443 auto __notify_visitor(_Receiver& __rcvr) noexcept
3444 {
3445     return [&]<class _Tuple>(_Tuple&& __tupl) noexcept -> void {
3446         __apply(
3447             [&](auto __tag, auto&&... __args) noexcept -> void {
3448             __tag(static_cast<_Receiver&&>(__rcvr),
3449                   __forward_like<_Tuple>(__args)...);
3450         },
3451             __tupl);
3452     };
3453 }
3454 
3455 enum class __action_kind : bool
3456 {
3457     __notify,
3458     __detach
3459 };
3460 
3461 struct __local_state_base : __immovable
3462 {
3463     using __action_fn = void(__local_state_base*, __action_kind) noexcept;
3464 
3465     __action_fn* __action_{};
3466     __local_state_base* __next_{};
3467 };
3468 
3469 template <class _CvrefSender, class _Env>
3470 struct __shared_state;
3471 
3472 // Each operation state of a split sender has one of these,
3473 // created when a split sender is connected. There are 0 or
3474 // more of them per input async operation. It is what
3475 // the split sender's `get_state` fn returns. It holds a
3476 // reference to the shared state of the input async operation.
3477 template <class _CvrefSender, class _Receiver>
3478 struct __local_state :
3479     __local_state_base,
3480     __enable_receiver_from_this<_CvrefSender, _Receiver>
3481 {
3482     using __data_t = __decay_t<__data_of<_CvrefSender>>;
3483     using __shared_state_t = __mapply<__q<__mfront>, __data_t>;
3484     using __on_stop_cb_t = //
3485         typename stop_token_of_t<env_of_t<_Receiver>&>::template callback_type<
3486             __on_stop_request>;
3487     using __tag_t = tag_of_t<_CvrefSender>;
3488     static_assert(__one_of<__tag_t, __split::__split_t,
3489                            __ensure_started::__ensure_started_t>);
3490 
__local_statestdexec::__shared::__local_state3491     explicit __local_state(_CvrefSender&& __sndr) noexcept :
3492         __local_state::__local_state_base{{},
3493                                           &__action<tag_of_t<_CvrefSender>>},
3494         __shared_state_(STDEXEC_CALL_EXPLICIT_THIS_MEMFN(
3495                             static_cast<_CvrefSender&&>(__sndr),
3496                             apply)(__detail::__get_data())
3497                             .__shared_state)
3498     {}
3499 
~__local_statestdexec::__shared::__local_state3500     ~__local_state()
3501     {
3502         __action_(this, __action_kind::__detach);
3503     }
3504 
3505     // This is called when the input async operation completes; or,
3506     // if it has already completed when start is called, it is called
3507     // from start:
3508     template <class _Tag>
__actionstdexec::__shared::__local_state3509     static void __action(__local_state_base* __self,
3510                          __action_kind __kind) noexcept
3511     {
3512         auto* const __op = static_cast<__local_state*>(__self);
3513         if (__kind == __action_kind::__notify)
3514         {
3515             __op->__on_stop_.reset();
3516 
3517             // The split algorithm sends by T const&. ensure_started sends by
3518             // T&&.
3519             if constexpr (same_as<__split::__split_t, _Tag>)
3520             {
3521                 std::visit(__notify_visitor(__op->__receiver()),
3522                            std::as_const(__op->__shared_state_->__data_));
3523             }
3524             else
3525             {
3526                 std::visit(__notify_visitor(__op->__receiver()),
3527                            std::move(__op->__shared_state_->__data_));
3528             }
3529         }
3530         else
3531         {
3532             // This is a detach operation
3533             if constexpr (same_as<__split::__split_t, _Tag>)
3534             {
3535                 // no-op
3536             }
3537             else
3538             {
3539                 __op->__shared_state_->__detach();
3540             }
3541         }
3542     }
3543 
3544     std::optional<__on_stop_cb_t> __on_stop_{};
3545     __intrusive_ptr<__shared_state_t> __shared_state_;
3546 };
3547 
3548 template <class _CvrefSenderId, class _EnvId>
3549 struct __receiver
3550 {
3551     using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
3552     using _Env = stdexec::__t<_EnvId>;
3553 
3554     struct __t
3555     {
3556         using receiver_concept = receiver_t;
3557         using __id = __receiver;
3558 
__tstdexec::__shared::__receiver::__t3559         explicit __t(
3560             __shared_state<_CvrefSender, _Env>* __shared_state) noexcept :
3561             __shared_state_(__shared_state)
3562         {}
3563 
3564         template <__completion_tag _Tag, class... _As>
tag_invokestdexec::__shared::__receiver3565         friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
3566         {
3567             __shared_state<_CvrefSender, _Env>& __state =
3568                 *__self.__shared_state_;
3569 
3570             try
3571             {
3572                 using __tuple_t = __decayed_tuple<_Tag, _As...>;
3573                 __state.__data_.template emplace<__tuple_t>(
3574                     __tag, static_cast<_As&&>(__as)...);
3575             }
3576             catch (...)
3577             {
3578                 using __tuple_t =
3579                     __decayed_tuple<set_error_t, std::exception_ptr>;
3580                 __state.__data_.template emplace<__tuple_t>(
3581                     set_error, std::current_exception());
3582             }
3583 
3584             __state.__notify();
3585         }
3586 
tag_invokestdexec::__shared::__receiver3587         friend auto tag_invoke(get_env_t, const __t& __self) noexcept
3588             -> const __env_t<_Env>&
3589         {
3590             return __self.__shared_state_->__env_;
3591         }
3592 
3593         __shared_state<_CvrefSender, _Env>* __shared_state_;
3594     };
3595 };
3596 
3597 template <class _CvrefSender, class _Env>
3598 struct __shared_state :
3599     __enable_intrusive_from_this<__shared_state<_CvrefSender, _Env>>
3600 {
3601     using __variant_t = __compl_sigs::__for_all_sigs<
3602         __completion_signatures_of_t<_CvrefSender, _Env>, __q<__decayed_tuple>,
3603         __mbind_front_q<__variant,
3604                         std::tuple<set_stopped_t>, // Initial state of the
3605                                                    // variant is set_stopped
3606                         std::tuple<set_error_t, std::exception_ptr>>>;
3607 
3608     using __receiver_t = __t<__receiver<__cvref_id<_CvrefSender>, __id<_Env>>>;
3609 
3610     in_place_stop_source __stop_source_{};
3611     __variant_t __data_;
3612     std::atomic<void*> __head_{nullptr};
3613     __env_t<_Env> __env_;
3614     connect_result_t<_CvrefSender, __receiver_t> __op_state2_;
3615 
__shared_statestdexec::__shared::__shared_state3616     explicit __shared_state(_CvrefSender&& __sndr, _Env __env) :
3617         __env_(__env::__join(
3618             __env::__with(__stop_source_.get_token(), get_stop_token),
3619             static_cast<_Env&&>(__env))),
3620         __op_state2_(
3621             connect(static_cast<_CvrefSender&&>(__sndr), __receiver_t{this}))
3622     {}
3623 
__start_opstdexec::__shared::__shared_state3624     void __start_op() noexcept
3625     {
3626         // the inner sender isn't running. if we reach here, then
3627         // one way or the other, __shared_state::__notify() will be
3628         // called, which decrements the ref count of *this.
3629         // So we need to increment it here:
3630         this->__inc_ref();
3631 
3632         if (__stop_source_.stop_requested())
3633         {
3634             // 1. resets __head to completion state
3635             // 2. notifies waiting threads
3636             // 3. propagates "stopped" signal to `out_r'`
3637             __notify();
3638         }
3639         else
3640         {
3641             stdexec::start(__op_state2_);
3642         }
3643     }
3644 
3645     // This is called when the shared async operation completes:
__notifystdexec::__shared::__shared_state3646     void __notify() noexcept
3647     {
3648         void* const __completion_state = static_cast<void*>(this);
3649         void* const __old = __head_.exchange(__completion_state,
3650                                              std::memory_order_acq_rel);
3651         auto* __state = static_cast<__local_state_base*>(__old);
3652 
3653         while (__state != nullptr)
3654         {
3655             __local_state_base* __next = __state->__next_;
3656             __state->__action_(__state, __action_kind::__notify);
3657             __state = __next;
3658         }
3659 
3660         // The async operation has completed, so we can release our
3661         // ref-count on it:
3662         this->__dec_ref();
3663     }
3664 
__detachstdexec::__shared::__shared_state3665     void __detach() noexcept
3666     {
3667         // Check to see if this operation was ever started. If not,
3668         // detach the (potentially still running) operation:
3669         if (nullptr == __head_.load(std::memory_order_acquire))
3670         {
3671             __stop_source_.request_stop();
3672         }
3673     }
3674 };
3675 
3676 template <class _Cvref, class _CvrefSenderId, class _EnvId>
3677 using __completions_t = //
3678     __try_make_completion_signatures<
3679         // NOT TO SPEC:
3680         // See https://github.com/cplusplus/sender-receiver/issues/23
3681         __cvref_t<_CvrefSenderId>, __env_t<__t<_EnvId>>,
3682         completion_signatures<set_error_t(
3683                                   __minvoke<_Cvref, std::exception_ptr>),
3684                               set_stopped_t()>, // NOT TO SPEC
3685         __transform<_Cvref,
3686                     __mcompose<__q<completion_signatures>, __qf<set_value_t>>>,
3687         __transform<_Cvref,
3688                     __mcompose<__q<completion_signatures>, __qf<set_error_t>>>>;
3689 
3690 template <class _Ty>
3691 using __clref_t = const __decay_t<_Ty>&;
3692 
3693 template <class _Ty>
3694 using __rref_t = __decay_t<_Ty>&&;
3695 
3696 template <class _Tag>
3697 using __cvref_results_t = //
3698     __if_c<same_as<_Tag, __split::__split_t>, __q<__clref_t>, __q<__rref_t>>;
3699 
3700 template <class _Tag>
__get_completion_signatures_fn()3701 inline auto __get_completion_signatures_fn() noexcept
3702 { //
3703     return
3704         []<template <class> class _Data, class _ShState>(
3705             auto, const _Data<_ShState>&) //
3706         -> __mapply<__mbind_front_q<__completions_t, __cvref_results_t<_Tag>>,
3707                     _ShState> { return {}; };
3708 }
3709 
3710 template <class _Tag>
3711 struct __shared_impl : __sexpr_defaults
3712 {
3713     static constexpr auto get_state = //
3714         []<class _Sender, class _Receiver>(
3715             _Sender&& __sndr,
3716             _Receiver&) noexcept -> __local_state<_Sender, _Receiver> {
3717         static_assert(sender_expr_for<_Sender, _Tag>);
3718         return __local_state<_Sender, _Receiver>{
3719             static_cast<_Sender&&>(__sndr)};
3720     };
3721 
3722     static constexpr auto get_completion_signatures = //
3723         []<class _Self, class _OtherEnv>(_Self&&, _OtherEnv&&) noexcept
3724         -> __call_result_t<__sexpr_apply_t, _Self,
3725                            __result_of<__get_completion_signatures_fn<_Tag>>> {
3726         static_assert(sender_expr_for<_Self, _Tag>);
3727         return {};
3728     };
3729 
3730     static constexpr auto start = //
3731         []<class _Sender, class _Receiver>(
3732             __local_state<_Sender, _Receiver>& __state,
3733             _Receiver& __rcvr) noexcept -> void {
3734         auto* __shared_state = __state.__shared_state_.get();
3735         std::atomic<void*>& __head = __shared_state->__head_;
3736         void* const __completion_state = static_cast<void*>(__shared_state);
3737         void* __old = __head.load(std::memory_order_acquire);
3738 
3739         if (__old != __completion_state)
3740         {
3741             __state.__on_stop_.emplace(
3742                 get_stop_token(stdexec::get_env(__rcvr)),
3743                 __on_stop_request{__shared_state->__stop_source_});
3744 
3745             if constexpr (same_as<_Tag, __ensure_started::__ensure_started_t>)
3746             {
3747                 // Check if the stop_source has requested cancellation
3748                 if (__shared_state->__stop_source_.stop_requested())
3749                 {
3750                     // Stop has already been requested. Don't bother starting
3751                     // the child operations.
3752                     stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr));
3753                     return;
3754                 }
3755             }
3756         }
3757 
3758         // With the split algorithm, multiple split senders can be started
3759         // simultaneously, but only one should start the async operation. The
3760         // following loop atomically (re)tries to set the pointer to the head of
3761         // the list to __state. When it finally succeeds, the prior value is
3762         // checked. If it is nullptr, then this split sender has won the race
3763         // and has the honor of starting the async operation.
3764         do
3765         {
3766             if (__old == __completion_state)
3767             {
3768                 __state.template __action<_Tag>(&__state,
3769                                                 __action_kind::__notify);
3770                 return;
3771             }
3772             __state.__next_ = static_cast<__local_state_base*>(__old);
3773         } while (!__head.compare_exchange_weak(
3774             __old, static_cast<void*>(&__state), std::memory_order_release,
3775             std::memory_order_acquire));
3776 
3777         if constexpr (same_as<_Tag, __split::__split_t>)
3778         {
3779             if (__old == nullptr)
3780             {
3781                 __shared_state->__start_op();
3782             }
3783         }
3784     };
3785 };
3786 } // namespace __shared
3787 
3788 ////////////////////////////////////////////////////////////////////////////
3789 // [execution.senders.adaptors.split]
3790 namespace __split
3791 {
3792 using namespace __shared;
3793 
3794 template <class _ShState>
3795 struct __data
3796 {
__datastdexec::__split::__data3797     explicit __data(__intrusive_ptr<_ShState> __shared_state) noexcept :
3798         __shared_state(std::move(__shared_state))
3799     {}
3800 
3801     __intrusive_ptr<_ShState> __shared_state;
3802 };
3803 
3804 struct __split_t
3805 {};
3806 
3807 struct split_t
3808 {
3809     template <sender _Sender, class _Env = empty_env>
3810         requires sender_in<_Sender, _Env> && __decay_copyable<env_of_t<_Sender>>
operator ()stdexec::__split::split_t3811     auto operator()(_Sender&& __sndr, _Env&& __env = {}) const
3812         -> __well_formed_sender auto
3813     {
3814         auto __domain = __get_late_domain(__sndr, __env);
3815         return stdexec::transform_sender(
3816             __domain, __make_sexpr<split_t>(static_cast<_Env&&>(__env),
3817                                             static_cast<_Sender&&>(__sndr)));
3818     }
3819 
3820     STDEXEC_ATTRIBUTE((always_inline))
3821 
operator ()stdexec::__split::split_t3822     __binder_back<split_t> operator()() const
3823     {
3824         return {{}, {}, {}};
3825     }
3826 
3827     using _Sender = __1;
3828     using __legacy_customizations_t = //
3829         __types<tag_invoke_t(split_t,
3830                              get_completion_scheduler_t<set_value_t>(
3831                                  get_env_t(const _Sender&)),
3832                              _Sender),
3833                 tag_invoke_t(split_t, _Sender)>;
3834 
3835     template <class _CvrefSender, class _Env>
3836     using __receiver_t =
3837         __t<__meval<__receiver, __cvref_id<_CvrefSender>, __id<_Env>>>;
3838 
3839     template <class _Sender>
transform_senderstdexec::__split::split_t3840     static auto transform_sender(_Sender&& __sndr)
3841     {
3842         using _Receiver =
3843             __receiver_t<__child_of<_Sender>, __decay_t<__data_of<_Sender>>>;
3844         static_assert(sender_to<__child_of<_Sender>, _Receiver>);
3845         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
3846                              [&]<class _Env, class _Child>(
3847                                  __ignore, _Env&& __env, _Child&& __child) {
3848             auto __state =
3849                 __make_intrusive<__shared_state<_Child, __decay_t<_Env>>>(
3850                     static_cast<_Child&&>(__child), static_cast<_Env&&>(__env));
3851             return __make_sexpr<__split_t>(__data{std::move(__state)});
3852         });
3853     }
3854 };
3855 } // namespace __split
3856 
3857 using __split::split_t;
3858 inline constexpr split_t split{};
3859 
3860 template <>
3861 struct __sexpr_impl<__split::__split_t> :
3862     __shared::__shared_impl<__split::__split_t>
3863 {};
3864 
3865 /////////////////////////////////////////////////////////////////////////////
3866 // [execution.senders.adaptors.ensure_started]
3867 namespace __ensure_started
3868 {
3869 using namespace __shared;
3870 
3871 // Each ensure_started sender has one of these, created when
3872 // ensure_started() is called.
3873 template <class _ShState>
3874 struct __data
3875 {
__datastdexec::__ensure_started::__data3876     explicit __data(__intrusive_ptr<_ShState> __ptr) noexcept :
3877         __shared_state(std::move(__ptr))
3878     {
3879         // Eagerly launch the async operation.
3880         __shared_state->__start_op();
3881     }
3882 
3883     __data(__data&&) noexcept = default;
3884     auto operator=(__data&&) noexcept -> __data& = default;
3885 
~__datastdexec::__ensure_started::__data3886     ~__data()
3887     {
3888         if (__shared_state != nullptr)
3889         {
3890             // detach from the still-running operation.
3891             // NOT TO SPEC: This also requests cancellation.
3892             __shared_state->__detach();
3893         }
3894     }
3895 
3896     __intrusive_ptr<_ShState> __shared_state;
3897 };
3898 
3899 struct __ensure_started_t
3900 {};
3901 
3902 struct ensure_started_t
3903 {
3904     template <sender _Sender, class _Env = empty_env>
3905         requires sender_in<_Sender, _Env> && __decay_copyable<env_of_t<_Sender>>
operator ()stdexec::__ensure_started::ensure_started_t3906     [[nodiscard]] auto operator()(_Sender&& __sndr, _Env&& __env = {}) const
3907         -> __well_formed_sender auto
3908     {
3909         if constexpr (sender_expr_for<_Sender, __ensure_started_t>)
3910         {
3911             return static_cast<_Sender&&>(__sndr);
3912         }
3913         else
3914         {
3915             auto __domain = __get_late_domain(__sndr, __env);
3916             return stdexec::transform_sender(
3917                 __domain,
3918                 __make_sexpr<ensure_started_t>(static_cast<_Env&&>(__env),
3919                                                static_cast<_Sender&&>(__sndr)));
3920         }
3921     }
3922 
3923     STDEXEC_ATTRIBUTE((always_inline))
3924 
operator ()stdexec::__ensure_started::ensure_started_t3925     __binder_back<ensure_started_t> operator()() const
3926     {
3927         return {{}, {}, {}};
3928     }
3929 
3930     using _Sender = __1;
3931     using __legacy_customizations_t = //
3932         __types<tag_invoke_t(ensure_started_t,
3933                              get_completion_scheduler_t<set_value_t>(
3934                                  get_env_t(const _Sender&)),
3935                              _Sender),
3936                 tag_invoke_t(ensure_started_t, _Sender)>;
3937 
3938     template <class _CvrefSender, class _Env>
3939     using __receiver_t =
3940         __t<__meval<__receiver, __cvref_id<_CvrefSender>, __id<_Env>>>;
3941 
3942     template <class _Sender>
transform_senderstdexec::__ensure_started::ensure_started_t3943     static auto transform_sender(_Sender&& __sndr)
3944     {
3945         using _Receiver =
3946             __receiver_t<__child_of<_Sender>, __decay_t<__data_of<_Sender>>>;
3947         static_assert(sender_to<__child_of<_Sender>, _Receiver>);
3948         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
3949                              [&]<class _Env, class _Child>(
3950                                  __ignore, _Env&& __env, _Child&& __child) {
3951             auto __state =
3952                 __make_intrusive<__shared_state<_Child, __decay_t<_Env>>>(
3953                     static_cast<_Child&&>(__child), static_cast<_Env&&>(__env));
3954             return __make_sexpr<__ensure_started_t>(__data{std::move(__state)});
3955         });
3956     }
3957 };
3958 } // namespace __ensure_started
3959 
3960 using __ensure_started::ensure_started_t;
3961 inline constexpr ensure_started_t ensure_started{};
3962 
3963 template <>
3964 struct __sexpr_impl<__ensure_started::__ensure_started_t> :
3965     __shared::__shared_impl<__ensure_started::__ensure_started_t>
3966 {};
3967 
3968 STDEXEC_PRAGMA_PUSH()
3969 STDEXEC_PRAGMA_IGNORE_EDG(not_used_in_partial_spec_arg_list)
3970 
3971 /////////////////////////////////////////////////////////////////////////////
3972 // a receiver adaptor that augments its environment
3973 namespace __detail
3974 {
3975 template <auto _ReceiverPtr, auto... _EnvFns>
3976 struct __receiver_with;
3977 
3978 template <class _Operation, class _Receiver,
3979           _Receiver _Operation::*_ReceiverPtr, auto... _EnvFns>
3980 struct __receiver_with<_ReceiverPtr, _EnvFns...>
3981 {
3982     struct __t : receiver_adaptor<__t>
3983     {
3984         using __id = __receiver_with;
3985         using __env_t = __env::__join_t<__result_of<_EnvFns, _Operation*>...,
3986                                         env_of_t<_Receiver>>;
3987 
3988         _Operation* __op_state_;
3989 
basestdexec::__detail::__receiver_with::__t3990         auto base() && noexcept -> _Receiver&&
3991         {
3992             return static_cast<_Receiver&&>(__op_state_->*_ReceiverPtr);
3993         }
3994 
get_envstdexec::__detail::__receiver_with::__t3995         auto get_env() const noexcept -> __env_t
3996         {
3997             return __env::__join(_EnvFns(__op_state_)...,
3998                                  stdexec::get_env(__op_state_->*_ReceiverPtr));
3999         }
4000     };
4001 };
4002 } // namespace __detail
4003 
4004 STDEXEC_PRAGMA_POP()
4005 
4006 //////////////////////////////////////////////////////////////////////////////
4007 // [exec.let]
4008 namespace __let
4009 {
4010 template <class _Set, class _Domain = dependent_domain>
4011 struct __let_t;
4012 
4013 template <class _Set>
4014 inline constexpr __mstring __in_which_let_msg{
4015     "In stdexec::let_value(Sender, Function)..."};
4016 
4017 template <>
4018 inline constexpr __mstring __in_which_let_msg<set_error_t>{
4019     "In stdexec::let_error(Sender, Function)..."};
4020 
4021 template <>
4022 inline constexpr __mstring __in_which_let_msg<set_stopped_t>{
4023     "In stdexec::let_stopped(Sender, Function)..."};
4024 
4025 template <class _Set>
4026 using __on_not_callable = __callable_error<__in_which_let_msg<_Set>>;
4027 
4028 // FUTURE: when we have a scheduler query for "always completes inline",
4029 // then we can use that instead of hard-coding `__inln::__scheduler` here.
4030 template <class _Scheduler>
4031 concept __unknown_context =
4032     __one_of<_Scheduler, __none_such, __inln::__scheduler>;
4033 
4034 template <class _Receiver, class _Scheduler>
4035 struct __receiver_with_sched
4036 {
4037     using receiver_concept = receiver_t;
4038     _Receiver __rcvr_;
4039     _Scheduler __sched_;
4040 
4041     template <__completion_tag _Tag, same_as<__receiver_with_sched> _Self,
4042               class... _As>
tag_invoke(_Tag,_Self && __self,_As &&...__as)4043     friend void tag_invoke(_Tag, _Self&& __self, _As&&... __as) noexcept
4044     {
4045         _Tag()(static_cast<_Receiver&&>(__self.__rcvr_),
4046                static_cast<_As&&>(__as)...);
4047     }
4048 
4049     template <same_as<get_env_t> _Tag>
tag_invoke(_Tag,const __receiver_with_sched & __self)4050     friend auto tag_invoke(_Tag, const __receiver_with_sched& __self) noexcept
4051     {
4052         return __env::__join(
4053             __env::__with(__self.__sched_, get_scheduler),
4054             __env::__without(get_env(__self.__rcvr_), get_domain));
4055     }
4056 };
4057 
4058 template <class _Receiver, class _Scheduler>
4059 __receiver_with_sched(_Receiver, _Scheduler)
4060     -> __receiver_with_sched<_Receiver, _Scheduler>;
4061 
4062 // If the input sender knows its completion scheduler, make it the current
4063 // scheduler in the environment seen by the result sender.
4064 template <class _Env, class _Scheduler>
4065 using __result_env_t =
4066     __if_c<__unknown_context<_Scheduler>, _Env,
4067            __env::__join_t<__env::__with<_Scheduler, get_scheduler_t>,
4068                            __env::__without_t<_Env, get_domain_t>>>;
4069 
4070 template <class _Tp>
4071 using __decay_ref = __decay_t<_Tp>&;
4072 
4073 template <__mstring _Where, __mstring _What>
4074 struct _FUNCTION_MUST_RETURN_A_VALID_SENDER_IN_THE_CURRENT_ENVIRONMENT_
4075 {};
4076 
4077 #if STDEXEC_NVHPC()
4078 template <class _Sender, class _Env, class _Set>
4079 struct __bad_result_sender_
4080 {
4081     using __t = __mexception<
4082         _FUNCTION_MUST_RETURN_A_VALID_SENDER_IN_THE_CURRENT_ENVIRONMENT_<
4083             __in_which_let_msg<_Set>,
4084             "The function must return a valid sender for the current environment"_mstr>,
4085         _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
4086 };
4087 template <class _Sender, class _Env, class _Set>
4088 using __bad_result_sender = __t<__bad_result_sender_<_Sender, _Env, _Set>>;
4089 #else
4090 template <class _Sender, class _Env, class _Set>
4091 using __bad_result_sender = __mexception<
4092     _FUNCTION_MUST_RETURN_A_VALID_SENDER_IN_THE_CURRENT_ENVIRONMENT_<
4093         __in_which_let_msg<_Set>,
4094         "The function must return a valid sender for the current environment"_mstr>,
4095     _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
4096 #endif
4097 
4098 template <class _Sender, class _Env, class _Set>
4099 using __ensure_sender = //
4100     __minvoke_if_c<sender_in<_Sender, _Env>, __q<__midentity>,
4101                    __mbind_back_q<__bad_result_sender, _Env, _Set>, _Sender>;
4102 
4103 // A metafunction that computes the result sender type for a given set of
4104 // argument types
4105 template <class _Fun, class _Set, class _Env, class _Sched>
4106 using __result_sender_fn = //
4107     __mcompose<
4108         __mbind_back_q<__ensure_sender, __result_env_t<_Env, _Sched>, _Set>,
4109         __transform<__q<__decay_ref>,
4110                     __mbind_front<__mtry_catch_q<__call_result_t,
4111                                                  __on_not_callable<_Set>>,
4112                                   _Fun>>>;
4113 
4114 // The receiver that gets connected to the result sender is the input receiver,
4115 // possibly augmented with the input sender's completion scheduler (which is
4116 // where the result sender will be started).
4117 template <class _Receiver, class _Scheduler>
4118 using __result_receiver_t =
4119     __if_c<__unknown_context<_Scheduler>, _Receiver,
4120            __receiver_with_sched<_Receiver, _Scheduler>>;
4121 
4122 template <class _Receiver, class _Fun, class _Set, class _Sched>
4123 using __op_state_for = //
4124     __mcompose<__mbind_back_q<connect_result_t,
4125                               __result_receiver_t<_Receiver, _Sched>>,
4126                __result_sender_fn<_Fun, _Set, env_of_t<_Receiver>, _Sched>>;
4127 
4128 template <class _Set, class _Sig>
4129 struct __tfx_signal_fn
4130 {
4131     template <class, class, class>
4132     using __f = completion_signatures<_Sig>;
4133 };
4134 
4135 template <class _Set, class... _Args>
4136 struct __tfx_signal_fn<_Set, _Set(_Args...)>
4137 {
4138     template <class _Env, class _Fun, class _Sched>
4139     using __f = //
4140         __try_make_completion_signatures<
4141             __minvoke<__result_sender_fn<_Fun, _Set, _Env, _Sched>, _Args...>,
4142             __result_env_t<_Env, _Sched>,
4143             // because we don't know if connect-ing the result sender will
4144             // throw:
4145             completion_signatures<set_error_t(std::exception_ptr)>>;
4146 };
4147 
4148 // `_Sched` is the input sender's completion scheduler, or __none_such if it
4149 // doesn't have one.
4150 template <class _Env, class _Fun, class _Set, class _Sched, class _Sig>
4151 using __tfx_signal_t =
4152     __minvoke<__tfx_signal_fn<_Set, _Sig>, _Env, _Fun, _Sched>;
4153 
4154 template <class _Sender, class _Set>
4155 using __completion_sched = __query_result_or_t<get_completion_scheduler_t<_Set>,
4156                                                env_of_t<_Sender>, __none_such>;
4157 
4158 template <class _CvrefSender, class _Env, class _LetTag, class _Fun>
4159 using __completions = //
4160     __mapply<__transform<__mbind_front_q<
4161                              __tfx_signal_t, _Env, _Fun, __t<_LetTag>,
4162                              __completion_sched<_CvrefSender, __t<_LetTag>>>,
4163                          __q<__concat_completion_signatures_t>>,
4164              __completion_signatures_of_t<_CvrefSender, _Env>>;
4165 
4166 template <__mstring _Where, __mstring _What>
4167 struct _NO_COMMON_DOMAIN_
4168 {};
4169 
4170 template <class _Set>
4171 using __no_common_domain_t = //
4172     _NO_COMMON_DOMAIN_<
4173         __in_which_let_msg<_Set>,
4174         "The senders returned by Function do not all share a common domain"_mstr>;
4175 
4176 template <class _Set>
4177 using __try_common_domain_fn = //
4178     __mtry_catch_q<
4179         __domain::__common_domain_t,
4180         __mcompose<__mbind_front_q<__mexception, __no_common_domain_t<_Set>>,
4181                    __q<_WITH_SENDERS_>>>;
4182 
4183 // Compute all the domains of all the result senders and make sure they're all
4184 // the same
4185 template <class _Set, class _Child, class _Fun, class _Env, class _Sched>
4186 using __result_domain_t = //
4187     __gather_completions_for<_Set, _Child, _Env,
4188                              __result_sender_fn<_Fun, _Set, _Env, _Sched>,
4189                              __try_common_domain_fn<_Set>>;
4190 
4191 template <class _LetTag, class _Env>
__mk_transform_env_fn(const _Env & __env)4192 auto __mk_transform_env_fn(const _Env& __env) noexcept
4193 {
4194     using _Set = __t<_LetTag>;
4195     return [&]<class _Fun, class _Child>(__ignore, _Fun&&,
4196                                          _Child&& __child) -> decltype(auto) {
4197         using __completions_t = __completion_signatures_of_t<_Child, _Env>;
4198         if constexpr (__merror<__completions_t>)
4199         {
4200             return __completions_t();
4201         }
4202         else
4203         {
4204             using _Scheduler = __completion_sched<_Child, _Set>;
4205             if constexpr (__unknown_context<_Scheduler>)
4206             {
4207                 return (__env);
4208             }
4209             else
4210             {
4211                 return __env::__join(
4212                     __env::__with(get_completion_scheduler<_Set>(
4213                                       stdexec::get_env(__child)),
4214                                   get_scheduler),
4215                     __env::__without(__env, get_domain));
4216             }
4217         }
4218     };
4219 }
4220 
4221 template <class _LetTag, class _Env>
__mk_transform_sender_fn(const _Env &)4222 auto __mk_transform_sender_fn(const _Env&) noexcept
4223 {
4224     using _Set = __t<_LetTag>;
4225     return
4226         []<class _Fun, class _Child>(__ignore, _Fun&& __fun, _Child&& __child) {
4227         using __completions_t = __completion_signatures_of_t<_Child, _Env>;
4228         if constexpr (__merror<__completions_t>)
4229         {
4230             return __completions_t();
4231         }
4232         else
4233         {
4234             using _Sched = __completion_sched<_Child, _Set>;
4235             using _Domain = __result_domain_t<_Set, _Child, _Fun, _Env, _Sched>;
4236             if constexpr (__merror<_Domain>)
4237             {
4238                 return _Domain();
4239             }
4240             else if constexpr (same_as<_Domain, dependent_domain>)
4241             {
4242                 using _Domain2 = __late_domain_of_t<_Child, _Env>;
4243                 return __make_sexpr<__let_t<_Set, _Domain2>>(
4244                     static_cast<_Fun&&>(__fun), static_cast<_Child&&>(__child));
4245             }
4246             else
4247             {
4248                 static_assert(!same_as<_Domain, __none_such>);
4249                 return __make_sexpr<__let_t<_Set, _Domain>>(
4250                     static_cast<_Fun&&>(__fun), static_cast<_Child&&>(__child));
4251             }
4252         }
4253     };
4254 }
4255 
4256 template <class _Receiver, class _Fun, class _Set, class _Sched,
4257           class... _Tuples>
4258 struct __let_state
4259 {
4260     using __fun_t = _Fun;
4261     using __sched_t = _Sched;
4262 
4263     using __result_variant = std::variant<std::monostate, _Tuples...>;
4264 
4265     using __op_state_variant = //
4266         __minvoke<__transform<
4267                       __uncurry<__op_state_for<_Receiver, _Fun, _Set, _Sched>>,
4268                       __nullable_variant_t>,
4269                   _Tuples...>;
4270 
__get_result_receiverstdexec::__let::__let_state4271     auto __get_result_receiver(_Receiver&& __rcvr) -> decltype(auto)
4272     {
4273         if constexpr (__unknown_context<_Sched>)
4274         {
4275             return static_cast<_Receiver&&>(__rcvr);
4276         }
4277         else
4278         {
4279             return __receiver_with_sched{static_cast<_Receiver&&>(__rcvr),
4280                                          this->__sched_};
4281         }
4282     }
4283 
4284     STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Fun __fun_;
4285     STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Sched __sched_;
4286     __result_variant __args_;
4287     __op_state_variant __op_state3_;
4288 };
4289 
4290 template <class _Set, class _Domain>
4291 struct __let_t
4292 {
4293     using __domain_t = _Domain;
4294     using __t = _Set;
4295 
4296     template <sender _Sender, __movable_value _Fun>
operator ()stdexec::__let::__let_t4297     auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender
4298         auto
4299     {
4300         auto __domain = __get_early_domain(__sndr);
4301         return stdexec::transform_sender(
4302             __domain,
4303             __make_sexpr<__let_t<_Set>>(static_cast<_Fun&&>(__fun),
4304                                         static_cast<_Sender&&>(__sndr)));
4305     }
4306 
4307     template <class _Fun>
4308     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__let::__let_t4309     __binder_back<__let_t, _Fun> operator()(_Fun __fun) const
4310     {
4311         return {{}, {}, {static_cast<_Fun&&>(__fun)}};
4312     }
4313 
4314     using _Sender = __1;
4315     using _Function = __0;
4316     using __legacy_customizations_t =
4317         __types<tag_invoke_t(__let_t,
4318                              get_completion_scheduler_t<set_value_t>(
4319                                  get_env_t(const _Sender&)),
4320                              _Sender, _Function),
4321                 tag_invoke_t(__let_t, _Sender, _Function)>;
4322 
4323     template <sender_expr_for<__let_t<_Set>> _Sender, class _Env>
transform_envstdexec::__let::__let_t4324     static auto transform_env(_Sender&& __sndr, const _Env& __env)
4325         -> decltype(auto)
4326     {
4327         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
4328                              __mk_transform_env_fn<__let_t<_Set>>(__env));
4329     }
4330 
4331     template <sender_expr_for<__let_t<_Set>> _Sender, class _Env>
4332         requires same_as<__early_domain_of_t<_Sender>, dependent_domain>
transform_senderstdexec::__let::__let_t4333     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
4334         -> decltype(auto)
4335     {
4336         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
4337                              __mk_transform_sender_fn<__let_t<_Set>>(__env));
4338     }
4339 };
4340 
4341 template <class _Set, class _Domain>
4342 struct __let_impl : __sexpr_defaults
4343 {
4344     static constexpr auto get_attrs = //
4345         []<class _Child>(__ignore, const _Child& __child) noexcept {
4346         return __env::__join(__env::__with(_Domain(), get_domain),
4347                              stdexec::get_env(__child));
4348     };
4349 
4350     static constexpr auto get_completion_signatures = //
4351         []<class _Self, class _Env>(_Self&&, _Env&&) noexcept
4352         -> __completions<__child_of<_Self>, _Env, __let_t<_Set, _Domain>,
4353                          __data_of<_Self>> {
4354         static_assert(sender_expr_for<_Self, __let_t<_Set, _Domain>>);
4355         return {};
4356     };
4357 
4358     static constexpr auto get_state = //
4359         []<class _Sender, class _Receiver>(_Sender&& __sndr, _Receiver&) {
4360         static_assert(sender_expr_for<_Sender, __let_t<_Set, _Domain>>);
4361         using _Fun = __data_of<_Sender>;
4362         using _Sched = __completion_sched<_Sender, _Set>;
4363         using __mk_let_state =
4364             __mbind_front_q<__let_state, _Receiver, _Fun, _Set, _Sched>;
4365 
4366         using __let_state_t =
4367             __gather_completions_for<_Set, __child_of<_Sender>,
4368                                      env_of_t<_Receiver>, __q<__decayed_tuple>,
4369                                      __mk_let_state>;
4370 
4371         _Sched __sched = query_or(get_completion_scheduler<_Set>,
4372                                   stdexec::get_env(__sndr), __none_such());
4373         return __let_state_t{
4374             STDEXEC_CALL_EXPLICIT_THIS_MEMFN(static_cast<_Sender&&>(__sndr),
4375                                              apply)(__detail::__get_data()),
4376             __sched};
4377     };
4378 
4379     template <class _State, class _Receiver, class... _As>
__bindstdexec::__let::__let_impl4380     static void __bind(_State& __state, _Receiver& __rcvr,
4381                        _As&&... __as) noexcept
4382     {
4383         try
4384         {
4385             auto& __args =
4386                 __state.__args_.template emplace<__decayed_tuple<_As...>>(
4387                     static_cast<_As&&>(__as)...);
4388             auto __sndr2 = __apply(std::move(__state.__fun_), __args);
4389             auto __rcvr2 =
4390                 __state.__get_result_receiver(static_cast<_Receiver&&>(__rcvr));
4391             auto __mkop = [&] {
4392                 return stdexec::connect(std::move(__sndr2), std::move(__rcvr2));
4393             };
4394             auto& __op2 =
4395                 __state.__op_state3_.template emplace<decltype(__mkop())>(
4396                     __conv{__mkop});
4397             stdexec::start(__op2);
4398         }
4399         catch (...)
4400         {
4401             set_error(std::move(__rcvr), std::current_exception());
4402         }
4403     }
4404 
4405     static constexpr auto complete = //
4406         []<class _State, class _Receiver, class _Tag, class... _As>(
4407             __ignore, _State& __state, _Receiver& __rcvr, _Tag,
4408             _As&&... __as) noexcept -> void {
4409         if constexpr (std::same_as<_Tag, _Set>)
4410         {
4411             __bind(__state, __rcvr, static_cast<_As&&>(__as)...);
4412         }
4413         else
4414         {
4415             _Tag()(static_cast<_Receiver&&>(__rcvr),
4416                    static_cast<_As&&>(__as)...);
4417         }
4418     };
4419 };
4420 } // namespace __let
4421 
4422 using let_value_t = __let::__let_t<set_value_t>;
4423 inline constexpr let_value_t let_value{};
4424 
4425 using let_error_t = __let::__let_t<set_error_t>;
4426 inline constexpr let_error_t let_error{};
4427 
4428 using let_stopped_t = __let::__let_t<set_stopped_t>;
4429 inline constexpr let_stopped_t let_stopped{};
4430 
4431 template <class _Set, class _Domain>
4432 struct __sexpr_impl<__let::__let_t<_Set, _Domain>> :
4433     __let::__let_impl<_Set, _Domain>
4434 {};
4435 
4436 /////////////////////////////////////////////////////////////////////////////
4437 // [execution.senders.adaptors.stopped_as_optional]
4438 // [execution.senders.adaptors.stopped_as_error]
4439 namespace __stopped_as_xxx
4440 {
4441 struct stopped_as_optional_t
4442 {
4443     template <sender _Sender>
operator ()stdexec::__stopped_as_xxx::stopped_as_optional_t4444     auto operator()(_Sender&& __sndr) const
4445     {
4446         return __make_sexpr<stopped_as_optional_t>(
4447             __(), static_cast<_Sender&&>(__sndr));
4448     }
4449 
4450     STDEXEC_ATTRIBUTE((always_inline))
4451 
operator ()stdexec::__stopped_as_xxx::stopped_as_optional_t4452     __binder_back<stopped_as_optional_t> operator()() const noexcept
4453     {
4454         return {};
4455     }
4456 };
4457 
4458 struct __stopped_as_optional_impl : __sexpr_defaults
4459 {
4460     template <class... _Tys>
4461         requires(sizeof...(_Tys) == 1)
4462     using __set_value_t =
4463         completion_signatures<set_value_t(std::optional<__decay_t<_Tys>>...)>;
4464 
4465     template <class _Ty>
4466     using __set_error_t = completion_signatures<set_error_t(_Ty)>;
4467 
4468     static constexpr auto get_completion_signatures =         //
4469         []<class _Self, class _Env>(_Self&&, _Env&&) noexcept //
4470         -> make_completion_signatures<
4471             __child_of<_Self>, _Env,
4472             completion_signatures<set_error_t(std::exception_ptr)>,
4473             __set_value_t, __set_error_t, completion_signatures<>> {
4474         static_assert(sender_expr_for<_Self, stopped_as_optional_t>);
4475         return {};
4476     };
4477 
4478     static constexpr auto get_state = //
4479         []<class _Self, class _Receiver>(_Self&&, _Receiver&) noexcept
4480         requires __single_typed_sender<__child_of<_Self>, env_of_t<_Receiver>>
4481     {
4482         static_assert(sender_expr_for<_Self, stopped_as_optional_t>);
4483         using _Value = __decay_t<
4484             __single_sender_value_t<__child_of<_Self>, env_of_t<_Receiver>>>;
4485         return __mtype<_Value>();
4486     };
4487 
4488     static constexpr auto complete = //
4489         []<class _State, class _Receiver, __completion_tag _Tag,
4490            class... _Args>(__ignore, _State&, _Receiver& __rcvr, _Tag,
4491                            _Args&&... __args) noexcept -> void {
4492         if constexpr (same_as<_Tag, set_value_t>)
4493         {
4494             try
4495             {
4496                 static_assert(constructible_from<__t<_State>, _Args...>);
4497                 stdexec::set_value(static_cast<_Receiver&&>(__rcvr),
4498                                    std::optional<__t<_State>>{
4499                                        static_cast<_Args&&>(__args)...});
4500             }
4501             catch (...)
4502             {
4503                 stdexec::set_error(static_cast<_Receiver&&>(__rcvr),
4504                                    std::current_exception());
4505             }
4506         }
4507         else if constexpr (same_as<_Tag, set_error_t>)
4508         {
4509             stdexec::set_error(static_cast<_Receiver&&>(__rcvr),
4510                                static_cast<_Args&&>(__args)...);
4511         }
4512         else
4513         {
4514             stdexec::set_value(static_cast<_Receiver&&>(__rcvr),
4515                                std::optional<__t<_State>>{std::nullopt});
4516         }
4517     };
4518 };
4519 
4520 struct stopped_as_error_t
4521 {
4522     template <sender _Sender, __movable_value _Error>
operator ()stdexec::__stopped_as_xxx::stopped_as_error_t4523     auto operator()(_Sender&& __sndr, _Error __err) const
4524     {
4525         return static_cast<_Sender&&>(__sndr) |
4526                let_stopped(
4527                    [__err2 = static_cast<_Error&&>(__err)]() mutable //
4528                    noexcept(std::is_nothrow_move_constructible_v<_Error>) {
4529             return just_error(static_cast<_Error&&>(__err2));
4530         });
4531     }
4532 
4533     template <__movable_value _Error>
4534     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__stopped_as_xxx::stopped_as_error_t4535     auto operator()(_Error __err) const
4536         -> __binder_back<stopped_as_error_t, _Error>
4537     {
4538         return {{}, {}, {static_cast<_Error&&>(__err)}};
4539     }
4540 };
4541 } // namespace __stopped_as_xxx
4542 
4543 using __stopped_as_xxx::stopped_as_optional_t;
4544 inline constexpr stopped_as_optional_t stopped_as_optional{};
4545 using __stopped_as_xxx::stopped_as_error_t;
4546 inline constexpr stopped_as_error_t stopped_as_error{};
4547 
4548 template <>
4549 struct __sexpr_impl<stopped_as_optional_t> :
4550     __stopped_as_xxx::__stopped_as_optional_impl
4551 {};
4552 
4553 /////////////////////////////////////////////////////////////////////////////
4554 // run_loop
4555 namespace __loop
4556 {
4557 class run_loop;
4558 
4559 struct __task : __immovable
4560 {
4561     __task* __next_ = this;
4562 
4563     union
4564     {
4565         void (*__execute_)(__task*) noexcept;
4566         __task* __tail_;
4567     };
4568 
__executestdexec::__loop::__task4569     void __execute() noexcept
4570     {
4571         (*__execute_)(this);
4572     }
4573 };
4574 
4575 template <class _ReceiverId>
4576 struct __operation
4577 {
4578     using _Receiver = stdexec::__t<_ReceiverId>;
4579 
4580     struct __t : __task
4581     {
4582         using __id = __operation;
4583 
4584         run_loop* __loop_;
4585         STDEXEC_ATTRIBUTE((no_unique_address))
4586         _Receiver __rcvr_;
4587 
__execute_implstdexec::__loop::__operation::__t4588         static void __execute_impl(__task* __p) noexcept
4589         {
4590             auto& __rcvr = static_cast<__t*>(__p)->__rcvr_;
4591             try
4592             {
4593                 if (get_stop_token(get_env(__rcvr)).stop_requested())
4594                 {
4595                     set_stopped(static_cast<_Receiver&&>(__rcvr));
4596                 }
4597                 else
4598                 {
4599                     set_value(static_cast<_Receiver&&>(__rcvr));
4600                 }
4601             }
4602             catch (...)
4603             {
4604                 set_error(static_cast<_Receiver&&>(__rcvr),
4605                           std::current_exception());
4606             }
4607         }
4608 
__tstdexec::__loop::__operation::__t4609         explicit __t(__task* __tail) noexcept : __task{.__tail_ = __tail} {}
4610 
__tstdexec::__loop::__operation::__t4611         __t(__task* __next, run_loop* __loop, _Receiver __rcvr) :
4612             __task{{}, __next, {&__execute_impl}}, __loop_{__loop},
4613             __rcvr_{static_cast<_Receiver&&>(__rcvr)}
4614         {}
4615 
tag_invokestdexec::__loop::__operation4616         friend void tag_invoke(start_t, __t& __self) noexcept
4617         {
4618             __self.__start_();
4619         }
4620 
4621         void __start_() noexcept;
4622     };
4623 };
4624 
4625 class run_loop
4626 {
4627     template <class... Ts>
4628     using __completion_signatures_ = completion_signatures<Ts...>;
4629 
4630     template <class>
4631     friend struct __operation;
4632 
4633   public:
4634     struct __scheduler
4635     {
4636         using __t = __scheduler;
4637         using __id = __scheduler;
4638         auto operator==(const __scheduler&) const noexcept -> bool = default;
4639 
4640       private:
4641         struct __schedule_task
4642         {
4643             using __t = __schedule_task;
4644             using __id = __schedule_task;
4645             using sender_concept = sender_t;
4646             using completion_signatures = //
4647                 __completion_signatures_<set_value_t(),
4648                                          set_error_t(std::exception_ptr),
4649                                          set_stopped_t()>;
4650 
4651           private:
4652             friend __scheduler;
4653 
4654             template <class _Receiver>
4655             using __operation =
4656                 stdexec::__t<__operation<stdexec::__id<_Receiver>>>;
4657 
4658             template <class _Receiver>
tag_invokestdexec::__loop::run_loop::__scheduler4659             friend auto tag_invoke(connect_t, const __schedule_task& __self,
4660                                    _Receiver __rcvr) -> __operation<_Receiver>
4661             {
4662                 return __self.__connect_(static_cast<_Receiver&&>(__rcvr));
4663             }
4664 
4665             template <class _Receiver>
__connect_stdexec::__loop::run_loop::__scheduler::__schedule_task4666             auto __connect_(_Receiver&& __rcvr) const -> __operation<_Receiver>
4667             {
4668                 return {&__loop_->__head_, __loop_,
4669                         static_cast<_Receiver&&>(__rcvr)};
4670             }
4671 
4672             struct __env
4673             {
4674                 run_loop* __loop_;
4675 
4676                 template <class _CPO>
tag_invokestdexec::__loop::run_loop::__scheduler::__schedule_task4677                 friend auto tag_invoke(get_completion_scheduler_t<_CPO>,
4678                                        const __env& __self) noexcept
4679                     -> __scheduler
4680                 {
4681                     return __self.__loop_->get_scheduler();
4682                 }
4683             };
4684 
tag_invokestdexec::__loop::run_loop::__scheduler4685             friend auto tag_invoke(get_env_t,
4686                                    const __schedule_task& __self) noexcept
4687                 -> __env
4688             {
4689                 return __env{__self.__loop_};
4690             }
4691 
__schedule_taskstdexec::__loop::run_loop::__scheduler::__schedule_task4692             explicit __schedule_task(run_loop* __loop) noexcept :
4693                 __loop_(__loop)
4694             {}
4695 
4696             run_loop* const __loop_;
4697         };
4698 
4699         friend run_loop;
4700 
__schedulerstdexec::__loop::run_loop::__scheduler4701         explicit __scheduler(run_loop* __loop) noexcept : __loop_(__loop) {}
4702 
tag_invoke(schedule_t,const __scheduler & __self)4703         friend auto tag_invoke(schedule_t, const __scheduler& __self) noexcept
4704             -> __schedule_task
4705         {
4706             return __self.__schedule();
4707         }
4708 
tag_invoke(get_forward_progress_guarantee_t,const __scheduler &)4709         friend auto tag_invoke(get_forward_progress_guarantee_t,
4710                                const __scheduler&) noexcept
4711             -> stdexec::forward_progress_guarantee
4712         {
4713             return stdexec::forward_progress_guarantee::parallel;
4714         }
4715 
4716         // BUGBUG NOT TO SPEC
tag_invoke(execute_may_block_caller_t,const __scheduler &)4717         friend auto tag_invoke(execute_may_block_caller_t,
4718                                const __scheduler&) noexcept -> bool
4719         {
4720             return false;
4721         }
4722 
__schedulestdexec::__loop::run_loop::__scheduler4723         [[nodiscard]] auto __schedule() const noexcept -> __schedule_task
4724         {
4725             return __schedule_task{__loop_};
4726         }
4727 
4728         run_loop* __loop_;
4729     };
4730 
get_scheduler()4731     auto get_scheduler() noexcept -> __scheduler
4732     {
4733         return __scheduler{this};
4734     }
4735 
4736     void run();
4737 
4738     void finish();
4739 
4740   private:
4741     void __push_back_(__task* __task);
4742     auto __pop_front_() -> __task*;
4743 
4744     std::mutex __mutex_;
4745     std::condition_variable __cv_;
4746     __task __head_{.__tail_ = &__head_};
4747     bool __stop_ = false;
4748 };
4749 
4750 template <class _ReceiverId>
__start_()4751 inline void __operation<_ReceiverId>::__t::__start_() noexcept
4752 {
4753     try
4754     {
4755         __loop_->__push_back_(this);
4756     }
4757     catch (...)
4758     {
4759         set_error(static_cast<_Receiver&&>(__rcvr_), std::current_exception());
4760     }
4761 }
4762 
run()4763 inline void run_loop::run()
4764 {
4765     for (__task* __task; (__task = __pop_front_()) != &__head_;)
4766     {
4767         __task->__execute();
4768     }
4769 }
4770 
finish()4771 inline void run_loop::finish()
4772 {
4773     std::unique_lock __lock{__mutex_};
4774     __stop_ = true;
4775     __cv_.notify_all();
4776 }
4777 
__push_back_(__task * __task)4778 inline void run_loop::__push_back_(__task* __task)
4779 {
4780     std::unique_lock __lock{__mutex_};
4781     __task->__next_ = &__head_;
4782     __head_.__tail_ = __head_.__tail_->__next_ = __task;
4783     __cv_.notify_one();
4784 }
4785 
__pop_front_()4786 inline auto run_loop::__pop_front_() -> __task*
4787 {
4788     std::unique_lock __lock{__mutex_};
4789     __cv_.wait(__lock,
4790                [this] { return __head_.__next_ != &__head_ || __stop_; });
4791     if (__head_.__tail_ == __head_.__next_)
4792         __head_.__tail_ = &__head_;
4793     return std::exchange(__head_.__next_, __head_.__next_->__next_);
4794 }
4795 } // namespace __loop
4796 
4797 // NOT TO SPEC
4798 using run_loop = __loop::run_loop;
4799 
4800 /////////////////////////////////////////////////////////////////////////////
4801 // [execution.senders.adaptors.schedule_from]
4802 namespace __schedule_from
4803 {
4804 // Compute a variant type that is capable of storing the results of the
4805 // input sender when it completes. The variant has type:
4806 //   variant<
4807 //     monostate,
4808 //     tuple<set_stopped_t>,
4809 //     tuple<set_value_t, __decay_t<_Values1>...>,
4810 //     tuple<set_value_t, __decay_t<_Values2>...>,
4811 //        ...
4812 //     tuple<set_error_t, __decay_t<_Error1>>,
4813 //     tuple<set_error_t, __decay_t<_Error2>>,
4814 //        ...
4815 //   >
4816 template <class _CvrefSender, class _Env>
4817 using __variant_for_t = __compl_sigs::__maybe_for_all_sigs<
4818     __completion_signatures_of_t<_CvrefSender, _Env>, __q<__decayed_tuple>,
4819     __nullable_variant_t>;
4820 
4821 template <class _Tp>
4822 using __decay_rvalue_ref = __decay_t<_Tp>&&;
4823 
4824 template <class _Tag>
4825 using __decay_signature =
4826     __transform<__q<__decay_rvalue_ref>,
4827                 __mcompose<__q<completion_signatures>, __qf<_Tag>>>;
4828 
4829 template <class... _Ts>
4830 using __all_nothrow_decay_copyable_ =
4831     __mbool<(__nothrow_decay_copyable<_Ts> && ...)>;
4832 
4833 template <class _CvrefSender, class _Env>
4834 using __all_values_and_errors_nothrow_decay_copyable = //
4835     __compl_sigs::__maybe_for_all_sigs<
4836         __completion_signatures_of_t<_CvrefSender, _Env>,
4837         __q<__all_nothrow_decay_copyable_>, __q<__mand>>;
4838 
4839 template <class _CvrefSender, class _Env>
4840 using __with_error_t = //
4841     __if<__all_values_and_errors_nothrow_decay_copyable<_CvrefSender, _Env>,
4842          completion_signatures<>, __with_exception_ptr>;
4843 
4844 template <class _Scheduler, class _CvrefSender, class _Env>
4845 using __completions_t = //
4846     __try_make_completion_signatures<
4847         _CvrefSender, _Env,
4848         __try_make_completion_signatures<schedule_result_t<_Scheduler>, _Env,
4849                                          __with_error_t<_CvrefSender, _Env>,
4850                                          __mconst<completion_signatures<>>>,
4851         __decay_signature<set_value_t>, __decay_signature<set_error_t>>;
4852 
4853 template <class _SchedulerId>
4854 struct __environ
4855 {
4856     using _Scheduler = stdexec::__t<_SchedulerId>;
4857 
4858     struct __t :
4859         __env::__with<stdexec::__t<_SchedulerId>,
4860                       get_completion_scheduler_t<set_value_t>,
4861                       get_completion_scheduler_t<set_stopped_t>>
4862     {
4863         using __id = __environ;
4864 
__tstdexec::__schedule_from::__environ::__t4865         explicit __t(_Scheduler __sched) noexcept :
4866             __t::__with{std::move(__sched)}
4867         {}
4868 
4869         template <same_as<get_domain_t> _Key>
tag_invokestdexec::__schedule_from::__environ4870         friend auto tag_invoke(_Key, const __t& __self) noexcept
4871         {
4872             return query_or(get_domain, __self.__value_, default_domain());
4873         }
4874     };
4875 };
4876 
4877 template <class _Scheduler, class _Sexpr, class _Receiver>
4878 struct __state;
4879 
4880 // This receiver is to be completed on the execution context
4881 // associated with the scheduler. When the source sender
4882 // completes, the completion information is saved off in the
4883 // operation state so that when this receiver completes, it can
4884 // read the completion out of the operation state and forward it
4885 // to the output receiver after transitioning to the scheduler's
4886 // context.
4887 template <class _Scheduler, class _Sexpr, class _Receiver>
4888 struct __receiver2 :
4889     receiver_adaptor<__receiver2<_Scheduler, _Sexpr, _Receiver>>
4890 {
__receiver2stdexec::__schedule_from::__receiver24891     explicit __receiver2(
4892         __state<_Scheduler, _Sexpr, _Receiver>* __state) noexcept :
4893         __state_{__state}
4894     {}
4895 
basestdexec::__schedule_from::__receiver24896     auto base() && noexcept -> _Receiver&&
4897     {
4898         return std::move(__state_->__receiver());
4899     }
4900 
basestdexec::__schedule_from::__receiver24901     auto base() const& noexcept -> const _Receiver&
4902     {
4903         return __state_->__receiver();
4904     }
4905 
set_valuestdexec::__schedule_from::__receiver24906     void set_value() && noexcept
4907     {
4908         STDEXEC_ASSERT(!__state_->__data_.valueless_by_exception());
4909         std::visit(
4910             [__state = __state_]<class _Tup>(_Tup& __tupl) noexcept -> void {
4911             if constexpr (same_as<_Tup, std::monostate>)
4912             {
4913                 std::terminate(); // reaching this indicates a bug in
4914                                   // schedule_from
4915             }
4916             else
4917             {
4918                 __apply(
4919                     [&]<class... _Args>(auto __tag,
4920                                         _Args&... __args) noexcept -> void {
4921                     __tag(std::move(__state->__receiver()),
4922                           static_cast<_Args&&>(__args)...);
4923                 },
4924                     __tupl);
4925             }
4926         },
4927             __state_->__data_);
4928     }
4929 
4930     __state<_Scheduler, _Sexpr, _Receiver>* __state_;
4931 };
4932 
4933 template <class _Scheduler, class _Sexpr, class _Receiver>
4934 struct __state : __enable_receiver_from_this<_Sexpr, _Receiver>
4935 {
4936     using __variant_t =
4937         __variant_for_t<__child_of<_Sexpr>, env_of_t<_Receiver>>;
4938     using __receiver2_t = __receiver2<_Scheduler, _Sexpr, _Receiver>;
4939 
4940     __variant_t __data_;
4941     connect_result_t<schedule_result_t<_Scheduler>, __receiver2_t> __state2_;
4942 
__statestdexec::__schedule_from::__state4943     explicit __state(_Scheduler __sched) :
4944         __data_(), __state2_(connect(schedule(__sched), __receiver2_t{this}))
4945     {}
4946 };
4947 
4948 struct schedule_from_t
4949 {
4950     template <scheduler _Scheduler, sender _Sender>
operator ()stdexec::__schedule_from::schedule_from_t4951     auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const
4952         -> __well_formed_sender auto
4953     {
4954         using _Env = __t<__environ<__id<__decay_t<_Scheduler>>>>;
4955         auto __env = _Env{{static_cast<_Scheduler&&>(__sched)}};
4956         auto __domain = query_or(get_domain, __sched, default_domain());
4957         return stdexec::transform_sender(
4958             __domain, __make_sexpr<schedule_from_t>(
4959                           std::move(__env), static_cast<_Sender&&>(__sndr)));
4960     }
4961 
4962     using _Sender = __1;
4963     using _Env = __0;
4964     using __legacy_customizations_t = __types<tag_invoke_t(
4965         schedule_from_t, get_completion_scheduler_t<set_value_t>(_Env&),
4966         _Sender)>;
4967 };
4968 
4969 struct __schedule_from_impl : __sexpr_defaults
4970 {
4971     template <class _Sender>
4972     using __scheduler_t =
4973         __decay_t<__call_result_t<get_completion_scheduler_t<set_value_t>,
4974                                   env_of_t<_Sender>>>;
4975 
4976     static constexpr auto get_attrs = //
4977         []<class _Data, class _Child>(const _Data& __data,
4978                                       const _Child& __child) noexcept {
4979         return __env::__join(__data, stdexec::get_env(__child));
4980     };
4981 
4982     static constexpr auto get_completion_signatures = //
4983         []<class _Sender, class _Env>(_Sender&&, const _Env&) noexcept
4984         -> __completions_t<__scheduler_t<_Sender>, __child_of<_Sender>, _Env> {
4985         static_assert(sender_expr_for<_Sender, schedule_from_t>);
4986         return {};
4987     };
4988 
4989     static constexpr auto get_state =
4990         []<class _Sender, class _Receiver>(_Sender&& __sndr, _Receiver&) {
4991         static_assert(sender_expr_for<_Sender, schedule_from_t>);
4992         auto __sched =
4993             get_completion_scheduler<set_value_t>(stdexec::get_env(__sndr));
4994         using _Scheduler = decltype(__sched);
4995         return __state<_Scheduler, _Sender, _Receiver>{__sched};
4996     };
4997 
4998     static constexpr auto complete =
4999         []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
5000                                        _Tag,
5001                                        _Args&&... __args) noexcept -> void {
5002         // Write the tag and the args into the operation state so that
5003         // we can forward the completion from within the scheduler's
5004         // execution context.
5005         using __async_result = __decayed_tuple<_Tag, _Args...>;
5006         if constexpr (__nothrow_constructible_from<__async_result, _Tag,
5007                                                    _Args...>)
5008         {
5009             __state.__data_.template emplace<__async_result>(
5010                 _Tag(), static_cast<_Args&&>(__args)...);
5011         }
5012         else
5013         {
5014             try
5015             {
5016                 __state.__data_.template emplace<__async_result>(
5017                     _Tag(), static_cast<_Args&&>(__args)...);
5018             }
5019             catch (...)
5020             {
5021                 set_error(std::move(__rcvr), std::current_exception());
5022                 return;
5023             }
5024         }
5025         // Enqueue the schedule operation so the completion happens
5026         // on the scheduler's execution context.
5027         stdexec::start(__state.__state2_);
5028     };
5029 };
5030 } // namespace __schedule_from
5031 
5032 using __schedule_from::schedule_from_t;
5033 inline constexpr schedule_from_t schedule_from{};
5034 
5035 template <>
5036 struct __sexpr_impl<schedule_from_t> : __schedule_from::__schedule_from_impl
5037 {};
5038 
5039 /////////////////////////////////////////////////////////////////////////////
5040 // [execution.senders.adaptors.transfer]
5041 namespace __transfer
5042 {
5043 using __schedule_from::__environ;
5044 
5045 template <class _Env>
5046 using __scheduler_t = __result_of<get_completion_scheduler<set_value_t>, _Env>;
5047 
5048 template <class _Sender>
5049 using __lowered_t = //
5050     __result_of<schedule_from, __scheduler_t<__data_of<_Sender>>,
5051                 __child_of<_Sender>>;
5052 
5053 struct transfer_t
5054 {
5055     template <sender _Sender, scheduler _Scheduler>
operator ()stdexec::__transfer::transfer_t5056     auto operator()(_Sender&& __sndr, _Scheduler&& __sched) const
5057         -> __well_formed_sender auto
5058     {
5059         auto __domain = __get_early_domain(__sndr);
5060         using _Env = __t<__environ<__id<__decay_t<_Scheduler>>>>;
5061         return stdexec::transform_sender(
5062             __domain,
5063             __make_sexpr<transfer_t>(_Env{{static_cast<_Scheduler&&>(__sched)}},
5064                                      static_cast<_Sender&&>(__sndr)));
5065     }
5066 
5067     template <scheduler _Scheduler>
5068     STDEXEC_ATTRIBUTE((always_inline))
5069     __binder_back<transfer_t, __decay_t<_Scheduler>>
operator ()stdexec::__transfer::transfer_t5070         operator()(_Scheduler&& __sched) const
5071     {
5072         return {{}, {}, {static_cast<_Scheduler&&>(__sched)}};
5073     }
5074 
5075     //////////////////////////////////////////////////////////////////////////////////////////////
5076     using _Env = __0;
5077     using _Sender = __1;
5078     using __legacy_customizations_t = //
5079         __types<tag_invoke_t(transfer_t,
5080                              get_completion_scheduler_t<set_value_t>(
5081                                  get_env_t(const _Sender&)),
5082                              _Sender,
5083                              get_completion_scheduler_t<set_value_t>(_Env)),
5084                 tag_invoke_t(transfer_t, _Sender,
5085                              get_completion_scheduler_t<set_value_t>(_Env))>;
5086 
5087     template <class _Env>
__transform_sender_fnstdexec::__transfer::transfer_t5088     static auto __transform_sender_fn(const _Env&)
5089     {
5090         return [&]<class _Data, class _Child>(__ignore, _Data&& __data,
5091                                               _Child&& __child) {
5092             auto __sched = get_completion_scheduler<set_value_t>(__data);
5093             return schedule_from(std::move(__sched),
5094                                  static_cast<_Child&&>(__child));
5095         };
5096     }
5097 
5098     template <class _Sender, class _Env>
transform_senderstdexec::__transfer::transfer_t5099     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
5100     {
5101         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
5102                              __transform_sender_fn(__env));
5103     }
5104 };
5105 
5106 struct __transfer_impl : __sexpr_defaults
5107 {
5108     static constexpr auto get_attrs = //
5109         []<class _Data, class _Child>(
5110             const _Data& __data,
5111             const _Child& __child) noexcept -> decltype(auto) {
5112         return __env::__join(__data, stdexec::get_env(__child));
5113     };
5114 };
5115 } // namespace __transfer
5116 
5117 using __transfer::transfer_t;
5118 inline constexpr transfer_t transfer{};
5119 
5120 template <>
5121 struct __sexpr_impl<transfer_t> : __transfer::__transfer_impl
5122 {};
5123 
5124 /////////////////////////////////////////////////////////////////////////////
5125 // [execution.senders.transfer_just]
5126 namespace __transfer_just
5127 {
5128 // This is a helper for finding legacy cusutomizations of transfer_just.
__transfer_just_tag_invoke()5129 inline auto __transfer_just_tag_invoke()
5130 {
5131     return []<class... _Ts>(
5132                _Ts&&... __ts) -> tag_invoke_result_t<transfer_just_t, _Ts...> {
5133         return tag_invoke(transfer_just, static_cast<_Ts&&>(__ts)...);
5134     };
5135 }
5136 
5137 template <class _Env>
__make_transform_fn(const _Env & __env)5138 auto __make_transform_fn(const _Env& __env)
5139 {
5140     return [&]<class _Scheduler, class... _Values>(_Scheduler&& __sched,
5141                                                    _Values&&... __vals) {
5142         return transfer(just(static_cast<_Values&&>(__vals)...),
5143                         static_cast<_Scheduler&&>(__sched));
5144     };
5145 }
5146 
5147 template <class _Env>
__transform_sender_fn(const _Env & __env)5148 auto __transform_sender_fn(const _Env& __env)
5149 {
5150     return [&]<class _Data>(__ignore, _Data&& __data) {
5151         return __apply(__make_transform_fn(__env),
5152                        static_cast<_Data&&>(__data));
5153     };
5154 }
5155 
5156 struct transfer_just_t
5157 {
5158     using _Data = __0;
5159     using __legacy_customizations_t = //
5160         __types<__apply_t(decltype(__transfer_just_tag_invoke()), _Data)>;
5161 
5162     template <scheduler _Scheduler, __movable_value... _Values>
operator ()stdexec::__transfer_just::transfer_just_t5163     auto operator()(_Scheduler&& __sched, _Values&&... __vals) const
5164         -> __well_formed_sender auto
5165     {
5166         auto __domain = query_or(get_domain, __sched, default_domain());
5167         return stdexec::transform_sender(
5168             __domain, __make_sexpr<transfer_just_t>(
5169                           std::tuple{static_cast<_Scheduler&&>(__sched),
5170                                      static_cast<_Values&&>(__vals)...}));
5171     }
5172 
5173     template <class _Sender, class _Env>
transform_senderstdexec::__transfer_just::transfer_just_t5174     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
5175     {
5176         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
5177                              __transform_sender_fn(__env));
5178     }
5179 };
5180 
__make_env_fn()5181 inline auto __make_env_fn() noexcept
5182 {
5183     return []<class _Scheduler>(const _Scheduler& __sched,
5184                                 const auto&...) noexcept {
5185         using _Env = __t<__schedule_from::__environ<__id<_Scheduler>>>;
5186         return _Env{__sched};
5187     };
5188 }
5189 
5190 struct __transfer_just_impl : __sexpr_defaults
5191 {
5192     static constexpr auto get_attrs = //
5193         []<class _Data>(const _Data& __data) noexcept {
5194         return __apply(__make_env_fn(), __data);
5195     };
5196 };
5197 } // namespace __transfer_just
5198 
5199 using __transfer_just::transfer_just_t;
5200 inline constexpr transfer_just_t transfer_just{};
5201 
5202 template <>
5203 struct __sexpr_impl<transfer_just_t> : __transfer_just::__transfer_just_impl
5204 {};
5205 
5206 //////////////////////////////////////////////////////////////////////////////////////////////////
5207 // __write adaptor
5208 namespace __write_
5209 {
5210 struct __write_t
5211 {
5212     template <sender _Sender, class... _Envs>
operator ()stdexec::__write_::__write_t5213     auto operator()(_Sender&& __sndr, _Envs... __envs) const
5214     {
5215         return __make_sexpr<__write_t>(__env::__join(std::move(__envs)...),
5216                                        static_cast<_Sender&&>(__sndr));
5217     }
5218 
5219     template <class... _Envs>
5220     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__write_::__write_t5221     auto operator()(_Envs... __envs) const -> __binder_back<__write_t, _Envs...>
5222     {
5223         return {{}, {}, {std::move(__envs)...}};
5224     }
5225 
5226     template <class _Env>
5227     STDEXEC_ATTRIBUTE((always_inline))
__transform_env_fnstdexec::__write_::__write_t5228     static auto __transform_env_fn(_Env&& __env) noexcept
5229     {
5230         return [&](__ignore, const auto& __state, __ignore) noexcept {
5231             return __env::__join(__state, static_cast<_Env&&>(__env));
5232         };
5233     }
5234 
5235     template <sender_expr_for<__write_t> _Self, class _Env>
transform_envstdexec::__write_::__write_t5236     static auto transform_env(const _Self& __self, _Env&& __env) noexcept
5237     {
5238         return __sexpr_apply(__self,
5239                              __transform_env_fn(static_cast<_Env&&>(__env)));
5240     }
5241 };
5242 
5243 struct __write_impl : __sexpr_defaults
5244 {
5245     static constexpr auto get_env = //
__anon996f5b230e02stdexec::__write_::__write_impl5246         [](__ignore, const auto& __state, const auto& __rcvr) noexcept {
5247         return __env::__join(__state, stdexec::get_env(__rcvr));
5248     };
5249 
5250     static constexpr auto get_completion_signatures = //
5251         []<class _Self, class _Env>(_Self&&, _Env&&) noexcept
5252         -> stdexec::__completion_signatures_of_t<
5253             __child_of<_Self>,
5254             __env::__join_t<const __decay_t<__data_of<_Self>>&, _Env>> {
5255         static_assert(sender_expr_for<_Self, __write_t>);
5256         return {};
5257     };
5258 };
5259 } // namespace __write_
5260 
5261 using __write_::__write_t;
5262 inline constexpr __write_t __write{};
5263 
5264 template <>
5265 struct __sexpr_impl<__write_t> : __write_::__write_impl
5266 {};
5267 
5268 namespace __detail
5269 {
5270 template <class _Env, class _Scheduler>
5271 STDEXEC_ATTRIBUTE((always_inline))
__mkenv_sched(_Env && __env,_Scheduler __sched)5272 auto __mkenv_sched(_Env&& __env, _Scheduler __sched)
5273 {
5274     auto __env2 =
5275         __env::__join(__env::__with(__sched, get_scheduler),
5276                       __env::__without(static_cast<_Env&&>(__env), get_domain));
5277     using _Env2 = decltype(__env2);
5278 
5279     struct __env_t : _Env2
5280     {};
5281 
5282     return __env_t{static_cast<_Env2&&>(__env2)};
5283 }
5284 
5285 template <class _Ty, class = __name_of<__decay_t<_Ty>>>
5286 struct __always
5287 {
5288     _Ty __val_;
5289 
operator ()stdexec::__detail::__always5290     auto operator()() noexcept -> _Ty
5291     {
5292         return static_cast<_Ty&&>(__val_);
5293     }
5294 };
5295 
5296 template <class _Ty>
5297 __always(_Ty) -> __always<_Ty>;
5298 } // namespace __detail
5299 
5300 /////////////////////////////////////////////////////////////////////////////
5301 // [execution.senders.adaptors.on]
5302 namespace __on
5303 {
5304 struct on_t
5305 {
5306     using _Sender = __1;
5307     using _Scheduler = __0;
5308     using __legacy_customizations_t =
5309         __types<tag_invoke_t(on_t, _Scheduler, _Sender)>;
5310 
5311     template <scheduler _Scheduler, sender _Sender>
operator ()stdexec::__on::on_t5312     auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const
5313         -> __well_formed_sender auto
5314     {
5315         auto __domain = query_or(get_domain, __sched, default_domain());
5316         return stdexec::transform_sender(
5317             __domain, __make_sexpr<on_t>(static_cast<_Scheduler&&>(__sched),
5318                                          static_cast<_Sender&&>(__sndr)));
5319     }
5320 
5321     template <class _Env>
5322     STDEXEC_ATTRIBUTE((always_inline))
__transform_env_fnstdexec::__on::on_t5323     static auto __transform_env_fn(_Env&& __env) noexcept
5324     {
5325         return [&](__ignore, auto __sched, __ignore) noexcept {
5326             return __detail::__mkenv_sched(static_cast<_Env&&>(__env), __sched);
5327         };
5328     }
5329 
5330     template <class _Sender, class _Env>
transform_envstdexec::__on::on_t5331     static auto transform_env(const _Sender& __sndr, _Env&& __env) noexcept
5332     {
5333         return __sexpr_apply(__sndr,
5334                              __transform_env_fn(static_cast<_Env&&>(__env)));
5335     }
5336 
5337     template <class _Sender, class _Env>
transform_senderstdexec::__on::on_t5338     static auto transform_sender(_Sender&& __sndr, const _Env&)
5339     {
5340         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
5341                              []<class _Data, class _Child>(
5342                                  __ignore, _Data&& __data, _Child&& __child) {
5343             return let_value(
5344                 schedule(__data),
5345                 __detail::__always{static_cast<_Child&&>(__child)});
5346         });
5347     }
5348 };
5349 } // namespace __on
5350 
5351 using __on::on_t;
5352 inline constexpr on_t on{};
5353 
5354 /////////////////////////////////////////////////////////////////////////////
5355 // [execution.senders.adaptors.into_variant]
5356 namespace __into_variant
5357 {
5358 template <class _Sender, class _Env>
5359     requires sender_in<_Sender, _Env>
5360 using __into_variant_result_t = value_types_of_t<_Sender, _Env>;
5361 
5362 template <class _Sender, class _Env>
5363 using __variant_t = __try_value_types_of_t<_Sender, _Env>;
5364 
5365 template <class _Variant>
5366 using __variant_completions =
5367     completion_signatures<set_value_t(_Variant),
5368                           set_error_t(std::exception_ptr)>;
5369 
5370 template <class _Sender, class _Env>
5371 using __compl_sigs = //
5372     __try_make_completion_signatures<
5373         _Sender, _Env,
5374         __meval<__variant_completions, __variant_t<_Sender, _Env>>,
5375         __mconst<completion_signatures<>>>;
5376 
5377 struct into_variant_t
5378 {
5379     template <sender _Sender>
operator ()stdexec::__into_variant::into_variant_t5380     auto operator()(_Sender&& __sndr) const -> __well_formed_sender auto
5381     {
5382         auto __domain = __get_early_domain(__sndr);
5383         return stdexec::transform_sender(
5384             __domain,
5385             __make_sexpr<into_variant_t>(__(), std::forward<_Sender>(__sndr)));
5386     }
5387 
5388     STDEXEC_ATTRIBUTE((always_inline))
5389 
operator ()stdexec::__into_variant::into_variant_t5390     auto operator()() const noexcept
5391     {
5392         return __binder_back<into_variant_t>{};
5393     }
5394 };
5395 
5396 struct __into_variant_impl : __sexpr_defaults
5397 {
5398     static constexpr auto get_state = //
5399         []<class _Self, class _Receiver>(_Self&&, _Receiver&) noexcept {
5400         using __variant_t =
5401             value_types_of_t<__child_of<_Self>, env_of_t<_Receiver>>;
5402         return __mtype<__variant_t>();
5403     };
5404 
5405     static constexpr auto complete = //
5406         []<class _State, class _Receiver, class _Tag, class... _Args>(
5407             __ignore, _State, _Receiver& __rcvr, _Tag,
5408             _Args&&... __args) noexcept -> void {
5409         if constexpr (same_as<_Tag, set_value_t>)
5410         {
5411             using __variant_t = __t<_State>;
5412             try
5413             {
5414                 set_value(static_cast<_Receiver&&>(__rcvr),
5415                           __variant_t{std::tuple<_Args&&...>{
5416                               static_cast<_Args&&>(__args)...}});
5417             }
5418             catch (...)
5419             {
5420                 set_error(static_cast<_Receiver&&>(__rcvr),
5421                           std::current_exception());
5422             }
5423         }
5424         else
5425         {
5426             _Tag()(static_cast<_Receiver&&>(__rcvr),
5427                    static_cast<_Args&&>(__args)...);
5428         }
5429     };
5430 
5431     static constexpr auto get_completion_signatures =         //
5432         []<class _Self, class _Env>(_Self&&, _Env&&) noexcept //
5433         -> __compl_sigs<__child_of<_Self>, _Env> {
5434         static_assert(sender_expr_for<_Self, into_variant_t>);
5435         return {};
5436     };
5437 };
5438 } // namespace __into_variant
5439 
5440 using __into_variant::into_variant_t;
5441 inline constexpr into_variant_t into_variant{};
5442 
5443 template <>
5444 struct __sexpr_impl<into_variant_t> : __into_variant::__into_variant_impl
5445 {};
5446 
5447 /////////////////////////////////////////////////////////////////////////////
5448 // [execution.senders.adaptors.when_all]
5449 // [execution.senders.adaptors.when_all_with_variant]
5450 namespace __when_all
5451 {
5452 enum __state_t
5453 {
5454     __started,
5455     __error,
5456     __stopped
5457 };
5458 
5459 struct __on_stop_request
5460 {
5461     in_place_stop_source& __stop_source_;
5462 
operator ()stdexec::__when_all::__on_stop_request5463     void operator()() noexcept
5464     {
5465         __stop_source_.request_stop();
5466     }
5467 };
5468 
5469 template <class _Env>
__mkenv(_Env && __env,in_place_stop_source & __stop_source)5470 auto __mkenv(_Env&& __env, in_place_stop_source& __stop_source) noexcept
5471 {
5472     return __env::__join(
5473         __env::__with(__stop_source.get_token(), get_stop_token),
5474         static_cast<_Env&&>(__env));
5475 }
5476 
5477 template <class _Env>
5478 using __env_t = //
5479     decltype(__mkenv(__declval<_Env>(), __declval<in_place_stop_source&>()));
5480 
5481 template <class _Tp>
5482 using __decay_rvalue_ref = __decay_t<_Tp>&&;
5483 
5484 template <class _Sender, class _Env>
5485 concept __max1_sender = sender_in<_Sender, _Env> &&
5486                         __mvalid<__value_types_of_t, _Sender, _Env,
5487                                  __mconst<int>, __msingle_or<void>>;
5488 
5489 template <
5490     __mstring _Context = "In stdexec::when_all()..."_mstr,
5491     __mstring _Diagnostic =
5492         "The given sender can complete successfully in more that one way. "
5493         "Use stdexec::when_all_with_variant() instead."_mstr>
5494 struct _INVALID_WHEN_ALL_ARGUMENT_;
5495 
5496 template <class _Sender, class _Env>
5497 using __too_many_value_completions_error =
5498     __mexception<_INVALID_WHEN_ALL_ARGUMENT_<>, _WITH_SENDER_<_Sender>,
5499                  _WITH_ENVIRONMENT_<_Env>>;
5500 
5501 template <class _Sender, class _Env, class _ValueTuple, class... _Rest>
5502 using __value_tuple_t =
5503     __minvoke<__if_c<(0 == sizeof...(_Rest)), __mconst<_ValueTuple>,
5504                      __q<__too_many_value_completions_error>>,
5505               _Sender, _Env>;
5506 
5507 template <class _Env, class _Sender>
5508 using __single_values_of_t = //
5509     __try_value_types_of_t<_Sender, _Env,
5510                            __transform<__q<__decay_rvalue_ref>, __q<__types>>,
5511                            __mbind_front_q<__value_tuple_t, _Sender, _Env>>;
5512 
5513 template <class _Env, class... _Senders>
5514 using __set_values_sig_t = //
5515     __meval<completion_signatures,
5516             __minvoke<__mconcat<__qf<set_value_t>>,
5517                       __single_values_of_t<_Env, _Senders>...>>;
5518 
5519 template <class... _Args>
5520 using __all_nothrow_decay_copyable_ =
5521     __mbool<(__nothrow_decay_copyable<_Args> && ...)>;
5522 
5523 template <class _Env, class... _Senders>
5524 using __all_nothrow_decay_copyable = //
5525     __mand<__compl_sigs::__maybe_for_all_sigs<
5526         __completion_signatures_of_t<_Senders, _Env>,
5527         __q<__all_nothrow_decay_copyable_>, __q<__mand>>...>;
5528 
5529 template <class _Env, class... _Senders>
5530 using __completions_t = //
5531     __concat_completion_signatures_t<
5532         __if<__all_nothrow_decay_copyable<_Env, _Senders...>,
5533              completion_signatures<set_stopped_t()>,
5534              completion_signatures<set_stopped_t(),
5535                                    set_error_t(std::exception_ptr&&)>>,
5536         __minvoke<__with_default<__mbind_front_q<__set_values_sig_t, _Env>,
5537                                  completion_signatures<>>,
5538                   _Senders...>,
5539         __try_make_completion_signatures<
5540             _Senders, _Env, completion_signatures<>,
5541             __mconst<completion_signatures<>>,
5542             __mcompose<__q<completion_signatures>, __qf<set_error_t>,
5543                        __q<__decay_rvalue_ref>>>...>;
5544 
5545 struct __not_an_error
5546 {};
5547 
5548 struct __tie_fn
5549 {
5550     template <class... _Ty>
operator ()stdexec::__when_all::__tie_fn5551     auto operator()(_Ty&... __vals) noexcept -> std::tuple<_Ty&...>
5552     {
5553         return std::tuple<_Ty&...>{__vals...};
5554     }
5555 };
5556 
5557 template <class _Tag, class _Receiver>
__complete_fn(_Tag,_Receiver & __rcvr)5558 auto __complete_fn(_Tag, _Receiver& __rcvr) noexcept
5559 {
5560     return [&]<class... _Ts>(_Ts&... __ts) noexcept {
5561         if constexpr (!same_as<__types<_Ts...>, __types<__not_an_error>>)
5562         {
5563             _Tag()(static_cast<_Receiver&&>(__rcvr),
5564                    static_cast<_Ts&&>(__ts)...);
5565         }
5566     };
5567 }
5568 
5569 template <class _Receiver, class _ValuesTuple>
__set_values(_Receiver & __rcvr,_ValuesTuple & __values)5570 void __set_values(_Receiver& __rcvr, _ValuesTuple& __values) noexcept
5571 {
5572     __tup::__apply(
5573         [&](auto&... __opt_vals) noexcept -> void {
5574         __apply(__complete_fn(set_value, __rcvr), //
5575                 std::tuple_cat(__tup::__apply(__tie_fn{}, *__opt_vals)...));
5576     },
5577         __values);
5578 }
5579 
5580 template <class... Ts>
5581 using __decayed_custom_tuple = __tup::__tuple_for<__decay_t<Ts>...>;
5582 
5583 template <class _Env, class _Sender>
5584 using __values_opt_tuple_t = //
5585     value_types_of_t<_Sender, __env_t<_Env>, __decayed_custom_tuple,
5586                      std::optional>;
5587 
5588 template <class _Env, __max1_sender<__env_t<_Env>>... _Senders>
5589 struct __traits
5590 {
5591     // tuple<optional<tuple<Vs1...>>, optional<tuple<Vs2...>>, ...>
5592     using __values_tuple = //
5593         __minvoke<__with_default<
5594                       __transform<__mbind_front_q<__values_opt_tuple_t, _Env>,
5595                                   __q<__tup::__tuple_for>>,
5596                       __ignore>,
5597                   _Senders...>;
5598 
5599     using __nullable_variant_t_ =
5600         __munique<__mbind_front_q<std::variant, __not_an_error>>;
5601 
5602     using __error_types = //
5603         __minvoke<__mconcat<__transform<__q<__decay_t>, __nullable_variant_t_>>,
5604                   error_types_of_t<_Senders, __env_t<_Env>, __types>...>;
5605 
5606     using __errors_variant = //
5607         __if<__all_nothrow_decay_copyable<_Env, _Senders...>, __error_types,
5608              __minvoke<__push_back_unique<__q<std::variant>>, __error_types,
5609                        std::exception_ptr>>;
5610 };
5611 
5612 struct _INVALID_ARGUMENTS_TO_WHEN_ALL_
5613 {};
5614 
5615 template <class _ErrorsVariant, class _ValuesTuple, class _StopToken>
5616 struct __when_all_state
5617 {
5618     using __stop_callback_t =
5619         typename _StopToken::template callback_type<__on_stop_request>;
5620 
5621     template <class _Receiver>
__arrivestdexec::__when_all::__when_all_state5622     void __arrive(_Receiver& __rcvr) noexcept
5623     {
5624         if (0 == --__count_)
5625         {
5626             __complete(__rcvr);
5627         }
5628     }
5629 
5630     template <class _Receiver>
__completestdexec::__when_all::__when_all_state5631     void __complete(_Receiver& __rcvr) noexcept
5632     {
5633         // Stop callback is no longer needed. Destroy it.
5634         __on_stop_.reset();
5635         // All child operations have completed and arrived at the barrier.
5636         switch (__state_.load(std::memory_order_relaxed))
5637         {
5638             case __started:
5639                 if constexpr (!same_as<_ValuesTuple, __ignore>)
5640                 {
5641                     // All child operations completed successfully:
5642                     __when_all::__set_values(__rcvr, __values_);
5643                 }
5644                 break;
5645             case __error:
5646                 if constexpr (!same_as<_ErrorsVariant,
5647                                        std::variant<std::monostate>>)
5648                 {
5649                     // One or more child operations completed with an error:
5650                     std::visit(__complete_fn(set_error, __rcvr), __errors_);
5651                 }
5652                 break;
5653             case __stopped:
5654                 stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr));
5655                 break;
5656             default:;
5657         }
5658     }
5659 
5660     std::atomic<std::size_t> __count_;
5661     in_place_stop_source __stop_source_{};
5662     // Could be non-atomic here and atomic_ref everywhere except __completion_fn
5663     std::atomic<__state_t> __state_{__started};
5664     _ErrorsVariant __errors_{};
5665     STDEXEC_ATTRIBUTE((no_unique_address))
5666     _ValuesTuple __values_{};
5667     std::optional<__stop_callback_t> __on_stop_{};
5668 };
5669 
5670 template <class _Env>
__mk_state_fn(const _Env & __env)5671 static auto __mk_state_fn(const _Env& __env) noexcept
5672 {
5673     return [&]<__max1_sender<__env_t<_Env>>... _Child>(__ignore, __ignore,
5674                                                        _Child&&...) {
5675         using _Traits = __traits<_Env, _Child...>;
5676         using _ErrorsVariant = typename _Traits::__errors_variant;
5677         using _ValuesTuple = typename _Traits::__values_tuple;
5678         using _State = __when_all_state<_ErrorsVariant, _ValuesTuple,
5679                                         stop_token_of_t<_Env>>;
5680         return _State{sizeof...(_Child), in_place_stop_source{}, __started,
5681                       _ErrorsVariant{},  _ValuesTuple{},         std::nullopt};
5682     };
5683 }
5684 
5685 template <class _Env>
5686 using __mk_state_fn_t = decltype(__when_all::__mk_state_fn(__declval<_Env>()));
5687 
5688 struct when_all_t
5689 {
5690     // Used by the default_domain to find legacy customizations:
5691     using _Sender = __1;
5692     using __legacy_customizations_t = //
5693         __types<tag_invoke_t(when_all_t, _Sender...)>;
5694 
5695     template <sender... _Senders>
5696         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::when_all_t5697     auto operator()(_Senders&&... __sndrs) const -> __well_formed_sender auto
5698     {
5699         auto __domain = __domain::__common_domain_t<_Senders...>();
5700         return stdexec::transform_sender(
5701             __domain, __make_sexpr<when_all_t>(
5702                           __(), static_cast<_Senders&&>(__sndrs)...));
5703     }
5704 };
5705 
5706 struct __when_all_impl : __sexpr_defaults
5707 {
5708     template <class _Self, class _Env>
5709     using __error_t = __mexception<_INVALID_ARGUMENTS_TO_WHEN_ALL_,
5710                                    __children_of<_Self, __q<_WITH_SENDERS_>>,
5711                                    _WITH_ENVIRONMENT_<_Env>>;
5712 
5713     template <class _Self, class _Env>
5714     using __completions = //
5715         __children_of<_Self, __mbind_front_q<__completions_t, __env_t<_Env>>>;
5716 
5717     static constexpr auto get_attrs = //
5718         []<class... _Child>(__ignore, const _Child&...) noexcept {
5719         using _Domain = __domain::__common_domain_t<_Child...>;
5720         if constexpr (same_as<_Domain, default_domain>)
5721         {
5722             return empty_env();
5723         }
5724         else
5725         {
5726             return __env::__with(_Domain(), get_domain);
5727         }
5728     };
5729 
5730     static constexpr auto get_completion_signatures = //
5731         []<class _Self, class _Env>(_Self&&, _Env&&) noexcept {
5732         static_assert(sender_expr_for<_Self, when_all_t>);
5733         return __minvoke<__mtry_catch<__q<__completions>, __q<__error_t>>,
5734                          _Self, _Env>();
5735     };
5736 
5737     static constexpr auto get_env =                                         //
5738         []<class _State, class _Receiver>(__ignore, _State& __state,
5739                                           const _Receiver& __rcvr) noexcept //
5740         -> __env_t<env_of_t<const _Receiver&>> {
5741         return __mkenv(stdexec::get_env(__rcvr), __state.__stop_source_);
5742     };
5743 
5744     static constexpr auto get_state = //
5745         []<class _Self, class _Receiver>(_Self&& __self, _Receiver& __rcvr)
5746         -> __sexpr_apply_result_t<_Self, __mk_state_fn_t<env_of_t<_Receiver>>> {
5747         return __sexpr_apply(
5748             static_cast<_Self&&>(__self),
5749             __when_all::__mk_state_fn(stdexec::get_env(__rcvr)));
5750     };
5751 
5752     static constexpr auto start = //
5753         []<class _State, class _Receiver, class... _Operations>(
5754             _State& __state, _Receiver& __rcvr,
5755             _Operations&... __child_ops) noexcept -> void {
5756         // register stop callback:
5757         __state.__on_stop_.emplace(get_stop_token(stdexec::get_env(__rcvr)),
5758                                    __on_stop_request{__state.__stop_source_});
5759         if (__state.__stop_source_.stop_requested())
5760         {
5761             // Stop has already been requested. Don't bother starting
5762             // the child operations.
5763             stdexec::set_stopped(std::move(__rcvr));
5764         }
5765         else
5766         {
5767             (stdexec::start(__child_ops), ...);
5768             if constexpr (sizeof...(__child_ops) == 0)
5769             {
5770                 __state.__complete(__rcvr);
5771             }
5772         }
5773     };
5774 
5775     template <class _State, class _Receiver, class _Error>
__set_errorstdexec::__when_all::__when_all_impl5776     static void __set_error(_State& __state, _Receiver& __rcvr,
5777                             _Error&& __err) noexcept
5778     {
5779         // TODO: What memory orderings are actually needed here?
5780         if (__error != __state.__state_.exchange(__error))
5781         {
5782             __state.__stop_source_.request_stop();
5783             // We won the race, free to write the error into the operation
5784             // state without worry.
5785             if constexpr (__nothrow_decay_copyable<_Error>)
5786             {
5787                 __state.__errors_.template emplace<__decay_t<_Error>>(
5788                     static_cast<_Error&&>(__err));
5789             }
5790             else
5791             {
5792                 try
5793                 {
5794                     __state.__errors_.template emplace<__decay_t<_Error>>(
5795                         static_cast<_Error&&>(__err));
5796                 }
5797                 catch (...)
5798                 {
5799                     __state.__errors_.template emplace<std::exception_ptr>(
5800                         std::current_exception());
5801                 }
5802             }
5803         }
5804     }
5805 
5806     static constexpr auto complete = //
5807         []<class _Index, class _State, class _Receiver, class _Set,
5808            class... _Args>(_Index, _State& __state, _Receiver& __rcvr, _Set,
5809                            _Args&&... __args) noexcept -> void {
5810         if constexpr (same_as<_Set, set_error_t>)
5811         {
5812             __set_error(__state, __rcvr, static_cast<_Args&&>(__args)...);
5813         }
5814         else if constexpr (same_as<_Set, set_stopped_t>)
5815         {
5816             __state_t __expected = __started;
5817             // Transition to the "stopped" state if and only if we're in the
5818             // "started" state. (If this fails, it's because we're in an
5819             // error state, which trumps cancellation.)
5820             if (__state.__state_.compare_exchange_strong(__expected, __stopped))
5821             {
5822                 __state.__stop_source_.request_stop();
5823             }
5824         }
5825         else if constexpr (!same_as<decltype(_State::__values_), __ignore>)
5826         {
5827             // We only need to bother recording the completion values
5828             // if we're not already in the "error" or "stopped" state.
5829             if (__state.__state_ == __started)
5830             {
5831                 auto& __opt_values =
5832                     __tup::__get<__v<_Index>>(__state.__values_);
5833                 using _Tuple = __decayed_custom_tuple<_Args...>;
5834                 static_assert(
5835                     same_as<decltype(*__opt_values), _Tuple&>,
5836                     "One of the senders in this when_all() is fibbing about what types it sends");
5837                 if constexpr ((__nothrow_decay_copyable<_Args> && ...))
5838                 {
5839                     __opt_values.emplace(
5840                         _Tuple{{static_cast<_Args&&>(__args)}...});
5841                 }
5842                 else
5843                 {
5844                     try
5845                     {
5846                         __opt_values.emplace(
5847                             _Tuple{{static_cast<_Args&&>(__args)}...});
5848                     }
5849                     catch (...)
5850                     {
5851                         __set_error(__state, __rcvr, std::current_exception());
5852                     }
5853                 }
5854             }
5855         }
5856 
5857         __state.__arrive(__rcvr);
5858     };
5859 };
5860 
5861 struct when_all_with_variant_t
5862 {
5863     using _Sender = __1;
5864     using __legacy_customizations_t = //
5865         __types<tag_invoke_t(when_all_with_variant_t, _Sender...)>;
5866 
5867     template <sender... _Senders>
5868         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::when_all_with_variant_t5869     auto operator()(_Senders&&... __sndrs) const -> __well_formed_sender auto
5870     {
5871         auto __domain = __domain::__common_domain_t<_Senders...>();
5872         return stdexec::transform_sender(
5873             __domain, __make_sexpr<when_all_with_variant_t>(
5874                           __(), static_cast<_Senders&&>(__sndrs)...));
5875     }
5876 
5877     template <class _Sender, class _Env>
transform_senderstdexec::__when_all::when_all_with_variant_t5878     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
5879     {
5880         // transform the when_all_with_variant into a regular when_all (looking
5881         // for early when_all customizations), then transform it again to look
5882         // for late customizations.
5883         return __sexpr_apply(
5884             static_cast<_Sender&&>(__sndr),
5885             [&]<class... _Child>(__ignore, __ignore, _Child&&... __child) {
5886             return when_all_t()(
5887                 into_variant(static_cast<_Child&&>(__child))...);
5888         });
5889     }
5890 };
5891 
5892 struct __when_all_with_variant_impl : __sexpr_defaults
5893 {
5894     static constexpr auto get_attrs = //
5895         []<class... _Child>(__ignore, const _Child&...) noexcept {
5896         using _Domain = __domain::__common_domain_t<_Child...>;
5897         if constexpr (same_as<_Domain, default_domain>)
5898         {
5899             return empty_env();
5900         }
5901         else
5902         {
5903             return __env::__with(_Domain(), get_domain);
5904         }
5905     };
5906 };
5907 
5908 struct transfer_when_all_t
5909 {
5910     using _Env = __0;
5911     using _Sender = __1;
5912     using __legacy_customizations_t = //
5913         __types<tag_invoke_t(
5914             transfer_when_all_t,
5915             get_completion_scheduler_t<set_value_t>(const _Env&), _Sender...)>;
5916 
5917     template <scheduler _Scheduler, sender... _Senders>
5918         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::transfer_when_all_t5919     auto operator()(_Scheduler&& __sched, _Senders&&... __sndrs) const
5920         -> __well_formed_sender auto
5921     {
5922         using _Env =
5923             __t<__schedule_from::__environ<__id<__decay_t<_Scheduler>>>>;
5924         auto __domain = query_or(get_domain, __sched, default_domain());
5925         return stdexec::transform_sender(
5926             __domain, __make_sexpr<transfer_when_all_t>(
5927                           _Env{static_cast<_Scheduler&&>(__sched)},
5928                           static_cast<_Senders&&>(__sndrs)...));
5929     }
5930 
5931     template <class _Sender, class _Env>
transform_senderstdexec::__when_all::transfer_when_all_t5932     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
5933     {
5934         // transform the transfer_when_all into a regular transform | when_all
5935         // (looking for early customizations), then transform it again to look
5936         // for late customizations.
5937         return __sexpr_apply(
5938             static_cast<_Sender&&>(__sndr),
5939             [&]<class _Data, class... _Child>(__ignore, _Data&& __data,
5940                                               _Child&&... __child) {
5941             return transfer(when_all_t()(static_cast<_Child&&>(__child)...),
5942                             get_completion_scheduler<set_value_t>(__data));
5943         });
5944     }
5945 };
5946 
5947 struct __transfer_when_all_impl : __sexpr_defaults
5948 {
5949     static constexpr auto get_attrs = //
5950         []<class _Data>(const _Data& __data,
5951                         const auto&...) noexcept -> const _Data& {
5952         return __data;
5953     };
5954 };
5955 
5956 struct transfer_when_all_with_variant_t
5957 {
5958     using _Env = __0;
5959     using _Sender = __1;
5960     using __legacy_customizations_t = //
5961         __types<tag_invoke_t(
5962             transfer_when_all_with_variant_t,
5963             get_completion_scheduler_t<set_value_t>(const _Env&), _Sender...)>;
5964 
5965     template <scheduler _Scheduler, sender... _Senders>
5966         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::transfer_when_all_with_variant_t5967     auto operator()(_Scheduler&& __sched, _Senders&&... __sndrs) const
5968         -> __well_formed_sender auto
5969     {
5970         using _Env =
5971             __t<__schedule_from::__environ<__id<__decay_t<_Scheduler>>>>;
5972         auto __domain = query_or(get_domain, __sched, default_domain());
5973         return stdexec::transform_sender(
5974             __domain, __make_sexpr<transfer_when_all_with_variant_t>(
5975                           _Env{{static_cast<_Scheduler&&>(__sched)}},
5976                           static_cast<_Senders&&>(__sndrs)...));
5977     }
5978 
5979     template <class _Sender, class _Env>
transform_senderstdexec::__when_all::transfer_when_all_with_variant_t5980     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
5981     {
5982         // transform the transfer_when_all_with_variant into regular
5983         // transform_when_all and into_variant calls/ (looking for early
5984         // customizations), then transform it again to look for late
5985         // customizations.
5986         return __sexpr_apply(
5987             static_cast<_Sender&&>(__sndr),
5988             [&]<class _Data, class... _Child>(__ignore, _Data&& __data,
5989                                               _Child&&... __child) {
5990             return transfer_when_all_t()(
5991                 get_completion_scheduler<set_value_t>(
5992                     static_cast<_Data&&>(__data)),
5993                 into_variant(static_cast<_Child&&>(__child))...);
5994         });
5995     }
5996 };
5997 
5998 struct __transfer_when_all_with_variant_impl : __sexpr_defaults
5999 {
6000     static constexpr auto get_attrs = //
6001         []<class _Data>(const _Data& __data,
6002                         const auto&...) noexcept -> const _Data& {
6003         return __data;
6004     };
6005 };
6006 } // namespace __when_all
6007 
6008 using __when_all::when_all_t;
6009 inline constexpr when_all_t when_all{};
6010 
6011 using __when_all::when_all_with_variant_t;
6012 inline constexpr when_all_with_variant_t when_all_with_variant{};
6013 
6014 using __when_all::transfer_when_all_t;
6015 inline constexpr transfer_when_all_t transfer_when_all{};
6016 
6017 using __when_all::transfer_when_all_with_variant_t;
6018 inline constexpr transfer_when_all_with_variant_t
6019     transfer_when_all_with_variant{};
6020 
6021 template <>
6022 struct __sexpr_impl<when_all_t> : __when_all::__when_all_impl
6023 {};
6024 
6025 template <>
6026 struct __sexpr_impl<when_all_with_variant_t> :
6027     __when_all::__when_all_with_variant_impl
6028 {};
6029 
6030 template <>
6031 struct __sexpr_impl<transfer_when_all_t> : __when_all::__transfer_when_all_impl
6032 {};
6033 
6034 template <>
6035 struct __sexpr_impl<transfer_when_all_with_variant_t> :
6036     __when_all::__transfer_when_all_with_variant_impl
6037 {};
6038 
6039 namespace __read
6040 {
6041 template <class _Tag, class _ReceiverId>
6042 using __result_t = __call_result_t<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
6043 
6044 template <class _Tag, class _ReceiverId>
6045 concept __nothrow_t =
6046     __nothrow_callable<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
6047 
6048 inline constexpr __mstring __query_failed_diag =
6049     "The current execution environment doesn't have a value for the given query."_mstr;
6050 
6051 template <class _Tag>
6052 struct _WITH_QUERY_;
6053 
6054 template <class _Tag, class _Env>
6055 using __query_failed_error = //
6056     __mexception<            //
6057         _NOT_CALLABLE_<"In stdexec::read()..."_mstr, __query_failed_diag>,
6058         _WITH_QUERY_<_Tag>, _WITH_ENVIRONMENT_<_Env>>;
6059 
6060 template <class _Tag, class _Env>
6061     requires __callable<_Tag, _Env>
6062 using __completions_t = //
6063     __if_c<__nothrow_callable<_Tag, _Env>,
6064            completion_signatures<set_value_t(__call_result_t<_Tag, _Env>)>,
6065            completion_signatures<set_value_t(__call_result_t<_Tag, _Env>),
6066                                  set_error_t(std::exception_ptr)>>;
6067 
6068 template <class _Tag, class _Ty>
6069 struct __state
6070 {
6071     using __query = _Tag;
6072     using __result = _Ty;
6073     std::optional<_Ty> __result_;
6074 };
6075 
6076 template <class _Tag, class _Ty>
6077     requires same_as<_Ty, _Ty&&>
6078 struct __state<_Tag, _Ty>
6079 {
6080     using __query = _Tag;
6081     using __result = _Ty;
6082 };
6083 
6084 struct __read_t
6085 {
6086     template <class _Tag>
operator ()stdexec::__read::__read_t6087     constexpr auto operator()(_Tag) const noexcept
6088     {
6089         return __make_sexpr<__read_t>(_Tag());
6090     }
6091 };
6092 
6093 struct __read_impl : __sexpr_defaults
6094 {
6095     using is_dependent = void;
6096 
6097     template <class _Tag, class _Env>
6098     using __completions_t = __minvoke<
6099         __mtry_catch_q<__read::__completions_t, __q<__query_failed_error>>,
6100         _Tag, _Env>;
6101 
6102     static constexpr auto get_completion_signatures =              //
6103         []<class _Self, class _Env>(const _Self&, _Env&&) noexcept //
6104         -> __completions_t<__data_of<_Self>, _Env> {
6105         static_assert(sender_expr_for<_Self, __read_t>);
6106         return {};
6107     };
6108 
6109     static constexpr auto get_state = //
6110         []<class _Self, class _Receiver>(const _Self&,
6111                                          _Receiver& __rcvr) noexcept {
6112         using __query = __data_of<_Self>;
6113         using __result = __call_result_t<__query, env_of_t<_Receiver>>;
6114         return __state<__query, __result>();
6115     };
6116 
6117     static constexpr auto start = //
6118         []<class _State, class _Receiver>(_State& __state,
6119                                           _Receiver& __rcvr) noexcept -> void {
6120         using __query = typename _State::__query;
6121         using __result = typename _State::__result;
6122         if constexpr (same_as<__result, __result&&>)
6123         {
6124             // The query returns a reference type; pass it straight through to
6125             // the receiver.
6126             stdexec::__set_value_invoke(std::move(__rcvr), __query(),
6127                                         stdexec::get_env(__rcvr));
6128         }
6129         else
6130         {
6131             constexpr bool _Nothrow =
6132                 __nothrow_callable<__query, env_of_t<_Receiver>>;
__anon996f5b231102stdexec::__read::__read_impl6133             auto __query_fn = [&]() noexcept(_Nothrow) -> __result&& {
6134                 __state.__result_.emplace(__conv{[&]() noexcept(_Nothrow) {
6135                     return __query()(stdexec::get_env(__rcvr));
6136                 }});
6137                 return std::move(*__state.__result_);
6138             };
6139             stdexec::__set_value_invoke(std::move(__rcvr), __query_fn);
6140         }
6141     };
6142 };
6143 } // namespace __read
6144 
6145 inline constexpr __read::__read_t read{};
6146 
6147 template <>
6148 struct __sexpr_impl<__read::__read_t> : __read::__read_impl
6149 {};
6150 
6151 namespace __queries
6152 {
6153 template <class _Tag>
operator ()() const6154 inline auto get_scheduler_t::operator()() const noexcept
6155 {
6156     return read(get_scheduler);
6157 }
6158 
6159 template <class _Env>
6160     requires tag_invocable<get_scheduler_t, const _Env&>
operator ()(const _Env & __env) const6161 inline auto get_scheduler_t::operator()(const _Env& __env) const noexcept
6162     -> tag_invoke_result_t<get_scheduler_t, const _Env&>
6163 {
6164     static_assert(nothrow_tag_invocable<get_scheduler_t, const _Env&>);
6165     static_assert(scheduler<tag_invoke_result_t<get_scheduler_t, const _Env&>>);
6166     return tag_invoke(get_scheduler_t{}, __env);
6167 }
6168 
6169 template <class _Tag>
operator ()() const6170 inline auto get_delegatee_scheduler_t::operator()() const noexcept
6171 {
6172     return read(get_delegatee_scheduler);
6173 }
6174 
6175 template <class _Env>
6176     requires tag_invocable<get_delegatee_scheduler_t, const _Env&>
6177 inline auto
operator ()(const _Env & __t) const6178     get_delegatee_scheduler_t::operator()(const _Env& __t) const noexcept
6179     -> tag_invoke_result_t<get_delegatee_scheduler_t, const _Env&>
6180 {
6181     static_assert(
6182         nothrow_tag_invocable<get_delegatee_scheduler_t, const _Env&>);
6183     static_assert(
6184         scheduler<tag_invoke_result_t<get_delegatee_scheduler_t, const _Env&>>);
6185     return tag_invoke(get_delegatee_scheduler_t{}, std::as_const(__t));
6186 }
6187 
6188 template <class _Tag>
operator ()() const6189 inline auto get_allocator_t::operator()() const noexcept
6190 {
6191     return read(get_allocator);
6192 }
6193 
6194 template <class _Tag>
operator ()() const6195 inline auto get_stop_token_t::operator()() const noexcept
6196 {
6197     return read(get_stop_token);
6198 }
6199 
6200 template <__completion_tag _CPO>
6201 template <__has_completion_scheduler_for<_CPO> _Queryable>
operator ()(const _Queryable & __queryable) const6202 auto get_completion_scheduler_t<_CPO>::operator()(
6203     const _Queryable& __queryable) const noexcept
6204     -> tag_invoke_result_t<get_completion_scheduler_t<_CPO>, const _Queryable&>
6205 {
6206     static_assert(nothrow_tag_invocable<get_completion_scheduler_t<_CPO>,
6207                                         const _Queryable&>,
6208                   "get_completion_scheduler<_CPO> should be noexcept");
6209     static_assert(
6210         scheduler<tag_invoke_result_t<get_completion_scheduler_t<_CPO>,
6211                                       const _Queryable&>>);
6212     return tag_invoke(*this, __queryable);
6213 }
6214 } // namespace __queries
6215 
6216 /////////////////////////////////////////////////////////////////////////////
6217 // [execution.senders.adaptors.on]
6218 namespace __on_v2
6219 {
6220 inline constexpr __mstring __on_context =
6221     "In stdexec::on(Scheduler, Sender)..."_mstr;
6222 inline constexpr __mstring __no_scheduler_diag =
6223     "stdexec::on() requires a scheduler to transition back to."_mstr;
6224 inline constexpr __mstring __no_scheduler_details =
6225     "The provided environment lacks a value for the get_scheduler() query."_mstr;
6226 
6227 template <__mstring _Context = __on_context,
6228           __mstring _Diagnostic = __no_scheduler_diag,
6229           __mstring _Details = __no_scheduler_details>
6230 struct _CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_
6231 {};
6232 
6233 struct on_t;
6234 
6235 STDEXEC_PRAGMA_PUSH()
6236 STDEXEC_PRAGMA_IGNORE_GNU("-Wunused-local-typedefs")
6237 
6238 struct __no_scheduler_in_environment
6239 {
6240     // Issue a custom diagnostic if the environment doesn't provide a scheduler.
6241     template <class _Sender, class _Env>
transform_senderstdexec::__on_v2::__no_scheduler_in_environment6242     static auto transform_sender(_Sender&&, const _Env&)
6243     {
6244         struct __no_scheduler_in_environment
6245         {
6246             using sender_concept = sender_t;
6247             using completion_signatures = //
6248                 __mexception<_CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_<>,
6249                              _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
6250         };
6251 
6252         return __no_scheduler_in_environment{};
6253     }
6254 };
6255 
6256 STDEXEC_PRAGMA_POP()
6257 
6258 struct on_t : __no_scheduler_in_environment
6259 {
6260     template <scheduler _Scheduler, sender _Sender>
operator ()stdexec::__on_v2::on_t6261     auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const
6262         -> __well_formed_sender auto
6263     {
6264         // BUGBUG __get_early_domain, or get_domain(__sched), or ...?
6265         auto __domain = __get_early_domain(__sndr);
6266         return stdexec::transform_sender(
6267             __domain, __make_sexpr<on_t>(static_cast<_Scheduler&&>(__sched),
6268                                          static_cast<_Sender&&>(__sndr)));
6269     }
6270 
6271     template <class _Env>
6272     STDEXEC_ATTRIBUTE((always_inline))
__transform_env_fnstdexec::__on_v2::on_t6273     static auto __transform_env_fn(_Env&& __env) noexcept
6274     {
6275         return [&](__ignore, auto __sched, __ignore) noexcept {
6276             return __detail::__mkenv_sched(static_cast<_Env&&>(__env), __sched);
6277         };
6278     }
6279 
6280     template <class _Sender, class _Env>
transform_envstdexec::__on_v2::on_t6281     static auto transform_env(const _Sender& __sndr, _Env&& __env) noexcept
6282     {
6283         return __sexpr_apply(__sndr,
6284                              __transform_env_fn(static_cast<_Env&&>(__env)));
6285     }
6286 
6287     using __no_scheduler_in_environment::transform_sender;
6288 
6289     template <class _Sender, class _Env>
6290         requires __callable<get_scheduler_t, const _Env&>
transform_senderstdexec::__on_v2::on_t6291     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
6292     {
6293         return __sexpr_apply(
6294             static_cast<_Sender&&>(__sndr),
6295             [&]<class _Scheduler, class _Child>(__ignore, _Scheduler __sched,
6296                                                 _Child&& __child) {
6297             auto __old = get_scheduler(__env);
6298             return transfer(
6299                 let_value(transfer_just(std::move(__sched)),
6300                           __detail::__always{static_cast<_Child&&>(__child)}),
6301                 std::move(__old));
6302         });
6303     }
6304 };
6305 
6306 template <class _Scheduler, class _Closure>
6307 struct __continue_on_data
6308 {
6309     _Scheduler __sched_;
6310     _Closure __clsur_;
6311 };
6312 template <class _Scheduler, class _Closure>
6313 __continue_on_data(_Scheduler, _Closure)
6314     -> __continue_on_data<_Scheduler, _Closure>;
6315 
6316 template <class _Scheduler>
6317 struct __with_sched
6318 {
6319     _Scheduler __sched_;
6320 
tag_invoke(get_scheduler_t,const __with_sched & __self)6321     friend auto tag_invoke(get_scheduler_t, const __with_sched& __self) noexcept
6322         -> _Scheduler
6323     {
6324         return __self.__sched_;
6325     }
6326 
tag_invoke(get_domain_t,const __with_sched & __self)6327     friend auto tag_invoke(get_domain_t, const __with_sched& __self) noexcept
6328     {
6329         return query_or(get_domain, __self.__sched_, default_domain());
6330     }
6331 };
6332 
6333 template <class _Scheduler>
6334 __with_sched(_Scheduler) -> __with_sched<_Scheduler>;
6335 
6336 struct continue_on_t : __no_scheduler_in_environment
6337 {
6338     template <sender _Sender, scheduler _Scheduler,
6339               __sender_adaptor_closure_for<_Sender> _Closure>
operator ()stdexec::__on_v2::continue_on_t6340     auto operator()(_Sender&& __sndr, _Scheduler&& __sched,
6341                     _Closure&& __clsur) const -> __well_formed_sender auto
6342     {
6343         auto __domain = __get_early_domain(__sndr);
6344         return stdexec::transform_sender(
6345             __domain, __make_sexpr<continue_on_t>(
6346                           __continue_on_data{static_cast<_Scheduler&&>(__sched),
6347                                              static_cast<_Closure&&>(__clsur)},
6348                           static_cast<_Sender&&>(__sndr)));
6349     }
6350 
6351     template <scheduler _Scheduler, __sender_adaptor_closure _Closure>
6352     STDEXEC_ATTRIBUTE((always_inline))
operator ()stdexec::__on_v2::continue_on_t6353     auto operator()(_Scheduler&& __sched, _Closure&& __clsur) const
6354         -> __binder_back<continue_on_t, __decay_t<_Scheduler>,
6355                          __decay_t<_Closure>>
6356     {
6357         return {{},
6358                 {},
6359                 {static_cast<_Scheduler&&>(__sched),
6360                  static_cast<_Closure&&>(__clsur)}};
6361     }
6362 
6363     using __no_scheduler_in_environment::transform_sender;
6364 
6365     template <class _Sender, class _Env>
6366         requires __callable<get_scheduler_t, const _Env&>
transform_senderstdexec::__on_v2::continue_on_t6367     static auto transform_sender(_Sender&& __sndr, const _Env& __env)
6368     {
6369         auto __old = get_scheduler(__env);
6370         return __sexpr_apply(static_cast<_Sender&&>(__sndr),
6371                              [&]<class _Data, class _Child>(
6372                                  __ignore, _Data&& __data, _Child&& __child) {
6373             auto&& [__sched, __clsur] = static_cast<_Data&&>(__data);
6374             using _Closure = decltype(__clsur);
6375             return __write(transfer(static_cast<_Closure&&>(__clsur)(transfer(
6376                                         __write(static_cast<_Child&&>(__child),
6377                                                 __with_sched{__old}),
6378                                         __sched)),
6379                                     __old),
6380                            __with_sched{__sched});
6381         });
6382     }
6383 };
6384 } // namespace __on_v2
6385 
6386 namespace v2
6387 {
6388 using __on_v2::on_t;
6389 inline constexpr on_t on{};
6390 
6391 using __on_v2::continue_on_t;
6392 inline constexpr continue_on_t continue_on{};
6393 } // namespace v2
6394 
6395 template <>
6396 struct __sexpr_impl<v2::on_t> : __sexpr_defaults
6397 {
6398     using is_dependent = void;
6399 };
6400 
6401 template <>
6402 struct __sexpr_impl<v2::continue_on_t> : __sexpr_defaults
6403 {
6404     using is_dependent = void;
6405 };
6406 
6407 /////////////////////////////////////////////////////////////////////////////
6408 // [execution.senders.consumers.sync_wait]
6409 // [execution.senders.consumers.sync_wait_with_variant]
6410 namespace __sync_wait
6411 {
__make_env(run_loop & __loop)6412 inline auto __make_env(run_loop& __loop) noexcept
6413 {
6414     return __env::__with(__loop.get_scheduler(), get_scheduler,
6415                          get_delegatee_scheduler);
6416 }
6417 
6418 struct __env : __result_of<__make_env, run_loop&>
6419 {
6420     __env();
6421 
__envstdexec::__sync_wait::__env6422     explicit __env(run_loop& __loop) noexcept :
6423         __result_of<__make_env, run_loop&>{__sync_wait::__make_env(__loop)}
6424     {}
6425 };
6426 
6427 // What should sync_wait(just_stopped()) return?
6428 template <class _Sender, class _Continuation>
6429 using __sync_wait_result_impl = //
6430     __try_value_types_of_t<_Sender, __env,
6431                            __transform<__q<__decay_t>, _Continuation>,
6432                            __q<__msingle>>;
6433 
6434 template <class _Sender>
6435 using __sync_wait_result_t =
6436     __mtry_eval<__sync_wait_result_impl, _Sender, __q<std::tuple>>;
6437 
6438 template <class _Sender>
6439 using __sync_wait_with_variant_result_t =
6440     __mtry_eval<__sync_wait_result_impl, __result_of<into_variant, _Sender>,
6441                 __q<__midentity>>;
6442 
6443 template <class... _Values>
6444 struct __state
6445 {
6446     using _Tuple = std::tuple<_Values...>;
6447     std::variant<std::monostate, _Tuple, std::exception_ptr, set_stopped_t>
6448         __data_{};
6449 };
6450 
6451 template <class... _Values>
6452 struct __receiver
6453 {
6454     struct __t
6455     {
6456         using receiver_concept = receiver_t;
6457         using __id = __receiver;
6458         __state<_Values...>* __state_;
6459         run_loop* __loop_;
6460 
6461         template <class _Error>
__set_errorstdexec::__sync_wait::__receiver::__t6462         void __set_error(_Error __err) noexcept
6463         {
6464             if constexpr (__decays_to<_Error, std::exception_ptr>)
6465                 __state_->__data_.template emplace<2>(
6466                     static_cast<_Error&&>(__err));
6467             else if constexpr (__decays_to<_Error, std::error_code>)
6468                 __state_->__data_.template emplace<2>(
6469                     std::make_exception_ptr(std::system_error(__err)));
6470             else
6471                 __state_->__data_.template emplace<2>(
6472                     std::make_exception_ptr(static_cast<_Error&&>(__err)));
6473             __loop_->finish();
6474         }
6475 
6476         template <same_as<set_value_t> _Tag, class... _As>
6477             requires constructible_from<std::tuple<_Values...>, _As...>
tag_invokestdexec::__sync_wait::__receiver6478         friend void tag_invoke(_Tag, __t&& __rcvr, _As&&... __as) noexcept
6479         {
6480             try
6481             {
6482                 __rcvr.__state_->__data_.template emplace<1>(
6483                     static_cast<_As&&>(__as)...);
6484                 __rcvr.__loop_->finish();
6485             }
6486             catch (...)
6487             {
6488                 __rcvr.__set_error(std::current_exception());
6489             }
6490         }
6491 
6492         template <same_as<set_error_t> _Tag, class _Error>
tag_invokestdexec::__sync_wait::__receiver6493         friend void tag_invoke(_Tag, __t&& __rcvr, _Error __err) noexcept
6494         {
6495             __rcvr.__set_error(static_cast<_Error&&>(__err));
6496         }
6497 
tag_invokestdexec::__sync_wait::__receiver6498         friend void tag_invoke(set_stopped_t __d, __t&& __rcvr) noexcept
6499         {
6500             __rcvr.__state_->__data_.template emplace<3>(__d);
6501             __rcvr.__loop_->finish();
6502         }
6503 
tag_invokestdexec::__sync_wait::__receiver6504         friend auto tag_invoke(get_env_t, const __t& __rcvr) noexcept -> __env
6505         {
6506             return __env(*__rcvr.__loop_);
6507         }
6508     };
6509 };
6510 
6511 template <class _Sender>
6512 using __receiver_t = __t<__sync_wait_result_impl<_Sender, __q<__receiver>>>;
6513 
6514 // These are for hiding the metaprogramming in diagnostics
6515 template <class _Sender>
6516 struct __sync_receiver_for
6517 {
6518     using __t = __receiver_t<_Sender>;
6519 };
6520 template <class _Sender>
6521 using __sync_receiver_for_t = __t<__sync_receiver_for<_Sender>>;
6522 
6523 template <class _Sender>
6524 struct __value_tuple_for
6525 {
6526     using __t = __sync_wait_result_t<_Sender>;
6527 };
6528 template <class _Sender>
6529 using __value_tuple_for_t = __t<__value_tuple_for<_Sender>>;
6530 
6531 template <class _Sender>
6532 struct __variant_for
6533 {
6534     using __t = __sync_wait_with_variant_result_t<_Sender>;
6535 };
6536 template <class _Sender>
6537 using __variant_for_t = __t<__variant_for<_Sender>>;
6538 
6539 inline constexpr __mstring __sync_wait_context_diag = //
6540     "In stdexec::sync_wait()..."_mstr;
6541 inline constexpr __mstring __too_many_successful_completions_diag =
6542     "The argument to stdexec::sync_wait() is a sender that can complete successfully in more "
6543     "than one way. Use stdexec::sync_wait_with_variant() instead."_mstr;
6544 
6545 template <__mstring _Context, __mstring _Diagnostic>
6546 struct _INVALID_ARGUMENT_TO_SYNC_WAIT_;
6547 
6548 template <__mstring _Diagnostic>
6549 using __invalid_argument_to_sync_wait =
6550     _INVALID_ARGUMENT_TO_SYNC_WAIT_<__sync_wait_context_diag, _Diagnostic>;
6551 
6552 template <__mstring _Diagnostic, class _Sender, class _Env = __env>
6553 using __sync_wait_error =
6554     __mexception<__invalid_argument_to_sync_wait<_Diagnostic>,
6555                  _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
6556 
6557 template <class _Sender, class>
6558 using __too_many_successful_completions_error =
6559     __sync_wait_error<__too_many_successful_completions_diag, _Sender>;
6560 
6561 template <class _Sender>
6562 concept __valid_sync_wait_argument =
6563     __ok<__minvoke<__mtry_catch_q<__single_value_variant_sender_t,
6564                                   __q<__too_many_successful_completions_error>>,
6565                    _Sender, __env>>;
6566 
6567 #if STDEXEC_NVHPC()
6568 // It requires some hoop-jumping to get the NVHPC compiler to report a
6569 // meaningful diagnostic for SFINAE failures.
6570 template <class _Sender>
__diagnose_error()6571 auto __diagnose_error()
6572 {
6573     if constexpr (!sender_in<_Sender, __env>)
6574     {
6575         using _Completions = __completion_signatures_of_t<_Sender, __env>;
6576         if constexpr (__merror<_Completions>)
6577         {
6578             return _Completions();
6579         }
6580         else
6581         {
6582             constexpr __mstring __diag =
6583                 "The stdexec::sender_in<Sender, Environment> concept check has failed."_mstr;
6584             return __sync_wait_error<__diag, _Sender>();
6585         }
6586     }
6587     else if constexpr (!__valid_sync_wait_argument<_Sender>)
6588     {
6589         return __sync_wait_error<__too_many_successful_completions_diag,
6590                                  _Sender>();
6591     }
6592     else if constexpr (!sender_to<_Sender, __sync_receiver_for_t<_Sender>>)
6593     {
6594         constexpr __mstring __diag =
6595             "Failed to connect the given sender to sync_wait's internal receiver. "
6596             "The stdexec::connect(Sender, Receiver) expression is ill-formed."_mstr;
6597         return __sync_wait_error<__diag, _Sender>();
6598     }
6599     else
6600     {
6601         constexpr __mstring __diag = "Unknown concept check failure."_mstr;
6602         return __sync_wait_error<__diag, _Sender>();
6603     }
6604 }
6605 
6606 template <class _Sender>
6607 using __error_description_t =
6608     decltype(__sync_wait::__diagnose_error<_Sender>());
6609 #endif
6610 
6611 ////////////////////////////////////////////////////////////////////////////
6612 // [execution.senders.consumers.sync_wait]
6613 struct sync_wait_t
6614 {
6615     template <sender_in<__env> _Sender>
6616         requires __valid_sync_wait_argument<_Sender> &&
6617                  __has_implementation_for<sync_wait_t,
6618                                           __early_domain_of_t<_Sender>, _Sender>
operator ()stdexec::__sync_wait::sync_wait_t6619     auto operator()(_Sender&& __sndr) const
6620         -> std::optional<__value_tuple_for_t<_Sender>>
6621     {
6622         auto __domain = __get_early_domain(__sndr);
6623         return stdexec::apply_sender(__domain, *this,
6624                                      static_cast<_Sender&&>(__sndr));
6625     }
6626 
6627 #if STDEXEC_NVHPC()
6628     // This is needed to get sensible diagnostics from nvc++
6629     template <class _Sender, class _Error = __error_description_t<_Sender>>
6630     auto operator()(_Sender&&, [[maybe_unused]] _Error __diagnostic = {}) const
6631         -> std::optional<std::tuple<int>> = delete;
6632 #endif
6633 
6634     using _Sender = __0;
6635     using __legacy_customizations_t = __types<
6636         // For legacy reasons:
6637         tag_invoke_t(
6638             sync_wait_t,
6639             get_completion_scheduler_t<set_value_t>(get_env_t(const _Sender&)),
6640             _Sender),
6641         tag_invoke_t(sync_wait_t, _Sender)>;
6642 
6643     // The default implementation goes here:
6644     template <class _Sender>
6645         requires sender_to<_Sender, __sync_receiver_for_t<_Sender>>
apply_senderstdexec::__sync_wait::sync_wait_t6646     auto apply_sender(_Sender&& __sndr) const
6647         -> std::optional<__sync_wait_result_t<_Sender>>
6648     {
6649         using state_t = __sync_wait_result_impl<_Sender, __q<__state>>;
6650         state_t __state{};
6651         run_loop __loop;
6652 
6653         // Launch the sender with a continuation that will fill in a variant
6654         // and notify a condition variable.
6655         auto __op_state = connect(static_cast<_Sender&&>(__sndr),
6656                                   __receiver_t<_Sender>{&__state, &__loop});
6657         start(__op_state);
6658 
6659         // Wait for the variant to be filled in.
6660         __loop.run();
6661 
6662         if (__state.__data_.index() == 2)
6663             std::rethrow_exception(std::get<2>(__state.__data_));
6664 
6665         if (__state.__data_.index() == 3)
6666             return std::nullopt;
6667 
6668         return std::move(std::get<1>(__state.__data_));
6669     }
6670 };
6671 
6672 ////////////////////////////////////////////////////////////////////////////
6673 // [execution.senders.consumers.sync_wait_with_variant]
6674 struct sync_wait_with_variant_t
6675 {
6676     struct __impl;
6677 
6678     template <sender_in<__env> _Sender>
6679         requires __callable<apply_sender_t, __early_domain_of_t<_Sender>,
6680                             sync_wait_with_variant_t, _Sender>
operator ()stdexec::__sync_wait::sync_wait_with_variant_t6681     auto operator()(_Sender&& __sndr) const
6682         -> std::optional<__variant_for_t<_Sender>>
6683     {
6684         auto __domain = __get_early_domain(__sndr);
6685         return stdexec::apply_sender(__domain, *this,
6686                                      static_cast<_Sender&&>(__sndr));
6687     }
6688 
6689 #if STDEXEC_NVHPC()
6690     template <class _Sender, class _Error = __error_description_t<
6691                                  __result_of<into_variant, _Sender>>>
6692     auto operator()(_Sender&&, [[maybe_unused]] _Error __diagnostic = {}) const
6693         -> std::optional<std::tuple<std::variant<std::tuple<>>>> = delete;
6694 #endif
6695 
6696     using _Sender = __0;
6697     using __legacy_customizations_t = __types<
6698         // For legacy reasons:
6699         tag_invoke_t(
6700             sync_wait_with_variant_t,
6701             get_completion_scheduler_t<set_value_t>(get_env_t(const _Sender&)),
6702             _Sender),
6703         tag_invoke_t(sync_wait_with_variant_t, _Sender)>;
6704 
6705     template <class _Sender>
6706         requires __callable<sync_wait_t, __result_of<into_variant, _Sender>>
apply_senderstdexec::__sync_wait::sync_wait_with_variant_t6707     auto apply_sender(_Sender&& __sndr) const
6708         -> std::optional<__variant_for_t<_Sender>>
6709     {
6710         if (auto __opt_values =
6711                 sync_wait_t()(into_variant(static_cast<_Sender&&>(__sndr))))
6712         {
6713             return std::move(std::get<0>(*__opt_values));
6714         }
6715         return std::nullopt;
6716     }
6717 };
6718 } // namespace __sync_wait
6719 
6720 using __sync_wait::sync_wait_t;
6721 inline constexpr sync_wait_t sync_wait{};
6722 
6723 using __sync_wait::sync_wait_with_variant_t;
6724 inline constexpr sync_wait_with_variant_t sync_wait_with_variant{};
6725 
6726 //////////////////////////////////////////////////////////////////////////////////////////////////
6727 struct __ignore_sender
6728 {
6729     using sender_concept = sender_t;
6730 
6731     template <sender _Sender>
__ignore_senderstdexec::__ignore_sender6732     constexpr __ignore_sender(_Sender&&) noexcept
6733     {}
6734 };
6735 
6736 template <auto _Reason = "You cannot pipe one sender into another."_mstr>
6737 struct _CANNOT_PIPE_INTO_A_SENDER_
6738 {};
6739 
6740 template <class _Sender>
6741 using __bad_pipe_sink_t =
6742     __mexception<_CANNOT_PIPE_INTO_A_SENDER_<>, _WITH_SENDER_<_Sender>>;
6743 } // namespace stdexec
6744 
6745 #if STDEXEC_MSVC()
6746 namespace stdexec
6747 {
6748 // MSVCBUG
6749 // https://developercommunity.visualstudio.com/t/Incorrect-codegen-in-await_suspend-aroun/10454102
6750 
6751 // MSVC incorrectly allocates the return buffer for await_suspend calls within
6752 // the suspended coroutine frame. When the suspended coroutine is destroyed
6753 // within await_suspend, the continuation coroutine handle is not only used
6754 // after free, but also overwritten by the debug malloc implementation when NRVO
6755 // is in play.
6756 
6757 // This workaround delays the destruction of the suspended coroutine by wrapping
6758 // the continuation in another coroutine which destroys the former and transfers
6759 // execution to the original continuation.
6760 
6761 // The wrapping coroutine is thread-local and is reused within the thread for
6762 // each destroy-and-continue sequence. The wrapping coroutine itself is
6763 // destroyed at thread exit.
6764 
6765 namespace __destroy_and_continue_msvc
6766 {
6767 struct __task
6768 {
6769     struct promise_type
6770     {
get_return_objectstdexec::__destroy_and_continue_msvc::__task::promise_type6771         __task get_return_object() noexcept
6772         {
6773             return {
6774                 __coro::coroutine_handle<promise_type>::from_promise(*this)};
6775         }
6776 
initial_suspendstdexec::__destroy_and_continue_msvc::__task::promise_type6777         static std::suspend_never initial_suspend() noexcept
6778         {
6779             return {};
6780         }
6781 
final_suspendstdexec::__destroy_and_continue_msvc::__task::promise_type6782         static std::suspend_never final_suspend() noexcept
6783         {
6784             STDEXEC_ASSERT(!"Should never get here");
6785             return {};
6786         }
6787 
return_voidstdexec::__destroy_and_continue_msvc::__task::promise_type6788         static void return_void() noexcept
6789         {
6790             STDEXEC_ASSERT(!"Should never get here");
6791         }
6792 
unhandled_exceptionstdexec::__destroy_and_continue_msvc::__task::promise_type6793         static void unhandled_exception() noexcept
6794         {
6795             STDEXEC_ASSERT(!"Should never get here");
6796         }
6797     };
6798 
6799     __coro::coroutine_handle<> __coro_;
6800 };
6801 
6802 struct __continue_t
6803 {
await_readystdexec::__destroy_and_continue_msvc::__continue_t6804     static constexpr bool await_ready() noexcept
6805     {
6806         return false;
6807     }
6808 
6809     __coro::coroutine_handle<>
await_suspendstdexec::__destroy_and_continue_msvc::__continue_t6810         await_suspend(__coro::coroutine_handle<>) noexcept
6811     {
6812         return __continue_;
6813     }
6814 
await_resumestdexec::__destroy_and_continue_msvc::__continue_t6815     static void await_resume() noexcept {}
6816 
6817     __coro::coroutine_handle<> __continue_;
6818 };
6819 
6820 struct __context
6821 {
6822     __coro::coroutine_handle<> __destroy_;
6823     __coro::coroutine_handle<> __continue_;
6824 };
6825 
__co_impl(__context & __c)6826 inline __task __co_impl(__context& __c)
6827 {
6828     while (true)
6829     {
6830         co_await __continue_t{__c.__continue_};
6831         __c.__destroy_.destroy();
6832     }
6833 }
6834 
6835 struct __context_and_coro
6836 {
__context_and_corostdexec::__destroy_and_continue_msvc::__context_and_coro6837     __context_and_coro()
6838     {
6839         __context_.__continue_ = __coro::noop_coroutine();
6840         __coro_ = __co_impl(__context_).__coro_;
6841     }
6842 
~__context_and_corostdexec::__destroy_and_continue_msvc::__context_and_coro6843     ~__context_and_coro()
6844     {
6845         __coro_.destroy();
6846     }
6847 
6848     __context __context_;
6849     __coro::coroutine_handle<> __coro_;
6850 };
6851 
__impl(__coro::coroutine_handle<> __destroy,__coro::coroutine_handle<> __continue)6852 inline __coro::coroutine_handle<> __impl(__coro::coroutine_handle<> __destroy,
6853                                          __coro::coroutine_handle<> __continue)
6854 {
6855     static thread_local __context_and_coro __c;
6856     __c.__context_.__destroy_ = __destroy;
6857     __c.__context_.__continue_ = __continue;
6858     return __c.__coro_;
6859 }
6860 } // namespace __destroy_and_continue_msvc
6861 } // namespace stdexec
6862 
6863 #define STDEXEC_DESTROY_AND_CONTINUE(__destroy, __continue)                    \
6864     (::stdexec::__destroy_and_continue_msvc::__impl(__destroy, __continue))
6865 #else
6866 #define STDEXEC_DESTROY_AND_CONTINUE(__destroy, __continue)                    \
6867     (__destroy.destroy(), __continue)
6868 #endif
6869 
6870 // For issuing a meaningful diagnostic for the erroneous `snd1 | snd2`.
6871 template <stdexec::sender _Sender>
6872     requires stdexec::__ok<stdexec::__bad_pipe_sink_t<_Sender>>
6873 auto operator|(stdexec::__ignore_sender, _Sender&&) noexcept
6874     -> stdexec::__ignore_sender;
6875 
6876 #include "__detail/__p2300.hpp"
6877 
6878 STDEXEC_PRAGMA_POP()
6879