15cee9157SPatrick Williams /*
25cee9157SPatrick Williams  * Copyright (c) 2021-2024 NVIDIA Corporation
35cee9157SPatrick Williams  *
45cee9157SPatrick Williams  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
55cee9157SPatrick Williams  * (the "License"); you may not use this file except in compliance with
65cee9157SPatrick Williams  * the License. You may obtain a copy of the License at
75cee9157SPatrick Williams  *
85cee9157SPatrick Williams  *   https://llvm.org/LICENSE.txt
95cee9157SPatrick Williams  *
105cee9157SPatrick Williams  * Unless required by applicable law or agreed to in writing, software
115cee9157SPatrick Williams  * distributed under the License is distributed on an "AS IS" BASIS,
125cee9157SPatrick Williams  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cee9157SPatrick Williams  * See the License for the specific language governing permissions and
145cee9157SPatrick Williams  * limitations under the License.
155cee9157SPatrick Williams  */
165cee9157SPatrick Williams #pragma once
175cee9157SPatrick Williams 
185cee9157SPatrick Williams #include "__execution_fwd.hpp"
195cee9157SPatrick Williams 
205cee9157SPatrick Williams // include these after __execution_fwd.hpp
215cee9157SPatrick Williams #include "../stop_token.hpp"
225cee9157SPatrick Williams #include "__basic_sender.hpp"
235cee9157SPatrick Williams #include "__concepts.hpp"
245cee9157SPatrick Williams #include "__continue_on.hpp"
255cee9157SPatrick Williams #include "__diagnostics.hpp"
265cee9157SPatrick Williams #include "__domain.hpp"
275cee9157SPatrick Williams #include "__env.hpp"
285cee9157SPatrick Williams #include "__into_variant.hpp"
295cee9157SPatrick Williams #include "__meta.hpp"
305cee9157SPatrick Williams #include "__optional.hpp"
315cee9157SPatrick Williams #include "__schedulers.hpp"
325cee9157SPatrick Williams #include "__senders.hpp"
335cee9157SPatrick Williams #include "__transform_completion_signatures.hpp"
345cee9157SPatrick Williams #include "__transform_sender.hpp"
355cee9157SPatrick Williams #include "__tuple.hpp"
365cee9157SPatrick Williams #include "__type_traits.hpp"
375cee9157SPatrick Williams #include "__utility.hpp"
385cee9157SPatrick Williams #include "__variant.hpp"
395cee9157SPatrick Williams 
405cee9157SPatrick Williams #include <atomic>
415cee9157SPatrick Williams #include <exception>
425cee9157SPatrick Williams 
435cee9157SPatrick Williams namespace stdexec
445cee9157SPatrick Williams {
455cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
465cee9157SPatrick Williams // [execution.senders.adaptors.when_all]
475cee9157SPatrick Williams // [execution.senders.adaptors.when_all_with_variant]
485cee9157SPatrick Williams namespace __when_all
495cee9157SPatrick Williams {
505cee9157SPatrick Williams enum __state_t
515cee9157SPatrick Williams {
525cee9157SPatrick Williams     __started,
535cee9157SPatrick Williams     __error,
545cee9157SPatrick Williams     __stopped
555cee9157SPatrick Williams };
565cee9157SPatrick Williams 
575cee9157SPatrick Williams struct __on_stop_request
585cee9157SPatrick Williams {
595cee9157SPatrick Williams     inplace_stop_source& __stop_source_;
605cee9157SPatrick Williams 
operator ()stdexec::__when_all::__on_stop_request615cee9157SPatrick Williams     void operator()() noexcept
625cee9157SPatrick Williams     {
635cee9157SPatrick Williams         __stop_source_.request_stop();
645cee9157SPatrick Williams     }
655cee9157SPatrick Williams };
665cee9157SPatrick Williams 
675cee9157SPatrick Williams template <class _Env>
__mkenv(_Env && __env,const inplace_stop_source & __stop_source)685cee9157SPatrick Williams auto __mkenv(_Env&& __env, const inplace_stop_source& __stop_source) noexcept
695cee9157SPatrick Williams {
705cee9157SPatrick Williams     return __env::__join(prop{get_stop_token, __stop_source.get_token()},
715cee9157SPatrick Williams                          static_cast<_Env&&>(__env));
725cee9157SPatrick Williams }
735cee9157SPatrick Williams 
745cee9157SPatrick Williams template <class _Env>
755cee9157SPatrick Williams using __env_t = //
765cee9157SPatrick Williams     decltype(__when_all::__mkenv(__declval<_Env>(),
775cee9157SPatrick Williams                                  __declval<inplace_stop_source&>()));
785cee9157SPatrick Williams 
795cee9157SPatrick Williams template <class _Sender, class _Env>
80*06f265f6SPatrick Williams concept __max1_sender =
81*06f265f6SPatrick Williams     sender_in<_Sender, _Env> && __mvalid<__value_types_of_t, _Sender, _Env,
825cee9157SPatrick Williams                                          __mconst<int>, __msingle_or<void>>;
835cee9157SPatrick Williams 
845cee9157SPatrick Williams template <
855cee9157SPatrick Williams     __mstring _Context = "In stdexec::when_all()..."_mstr,
865cee9157SPatrick Williams     __mstring _Diagnostic =
875cee9157SPatrick Williams         "The given sender can complete successfully in more that one way. "
885cee9157SPatrick Williams         "Use stdexec::when_all_with_variant() instead."_mstr>
895cee9157SPatrick Williams struct _INVALID_WHEN_ALL_ARGUMENT_;
905cee9157SPatrick Williams 
915cee9157SPatrick Williams template <class _Sender, class... _Env>
925cee9157SPatrick Williams using __too_many_value_completions_error =
935cee9157SPatrick Williams     __mexception<_INVALID_WHEN_ALL_ARGUMENT_<>, _WITH_SENDER_<_Sender>,
945cee9157SPatrick Williams                  _WITH_ENVIRONMENT_<_Env>...>;
955cee9157SPatrick Williams 
965cee9157SPatrick Williams template <class... _Args>
975cee9157SPatrick Williams using __all_nothrow_decay_copyable =
985cee9157SPatrick Williams     __mbool<(__nothrow_decay_copyable<_Args> && ...)>;
995cee9157SPatrick Williams 
1005cee9157SPatrick Williams template <class _Error>
1015cee9157SPatrick Williams using __set_error_t = completion_signatures<set_error_t(__decay_t<_Error>)>;
1025cee9157SPatrick Williams 
1035cee9157SPatrick Williams template <class _Sender, class... _Env>
1045cee9157SPatrick Williams using __nothrow_decay_copyable_results = //
1055cee9157SPatrick Williams     __for_each_completion_signature<
1065cee9157SPatrick Williams         __completion_signatures_of_t<_Sender, _Env...>,
1075cee9157SPatrick Williams         __all_nothrow_decay_copyable, __mand_t>;
1085cee9157SPatrick Williams 
1095cee9157SPatrick Williams template <class... _Env>
1105cee9157SPatrick Williams struct __completions_t
1115cee9157SPatrick Williams {
1125cee9157SPatrick Williams     template <class... _Senders>
1135cee9157SPatrick Williams     using __all_nothrow_decay_copyable_results = //
1145cee9157SPatrick Williams         __mand<__nothrow_decay_copyable_results<_Senders, _Env...>...>;
1155cee9157SPatrick Williams 
1165cee9157SPatrick Williams     template <class _Sender, class _ValueTuple, class... _Rest>
1175cee9157SPatrick Williams     using __value_tuple_t =
1185cee9157SPatrick Williams         __minvoke<__if_c<(0 == sizeof...(_Rest)), __mconst<_ValueTuple>,
1195cee9157SPatrick Williams                          __q<__too_many_value_completions_error>>,
1205cee9157SPatrick Williams                   _Sender, _Env...>;
1215cee9157SPatrick Williams 
1225cee9157SPatrick Williams     template <class _Sender>
1235cee9157SPatrick Williams     using __single_values_of_t = //
1245cee9157SPatrick Williams         __value_types_t<__completion_signatures_of_t<_Sender, _Env...>,
1255cee9157SPatrick Williams                         __mtransform<__q<__decay_t>, __q<__types>>,
1265cee9157SPatrick Williams                         __mbind_front_q<__value_tuple_t, _Sender>>;
1275cee9157SPatrick Williams 
1285cee9157SPatrick Williams     template <class... _Senders>
1295cee9157SPatrick Williams     using __set_values_sig_t = //
1305cee9157SPatrick Williams         __meval<completion_signatures,
1315cee9157SPatrick Williams                 __minvoke<__mconcat<__qf<set_value_t>>,
1325cee9157SPatrick Williams                           __single_values_of_t<_Senders>...>>;
1335cee9157SPatrick Williams 
1345cee9157SPatrick Williams     template <class... _Senders>
1355cee9157SPatrick Williams     using __f =  //
1365cee9157SPatrick Williams         __meval< //
1375cee9157SPatrick Williams             __concat_completion_signatures,
1385cee9157SPatrick Williams             __meval<__eptr_completion_if_t,
1395cee9157SPatrick Williams                     __all_nothrow_decay_copyable_results<_Senders...>>,
1405cee9157SPatrick Williams             completion_signatures<set_stopped_t()>,
1415cee9157SPatrick Williams             __minvoke<__with_default<__qq<__set_values_sig_t>,
1425cee9157SPatrick Williams                                      completion_signatures<>>,
1435cee9157SPatrick Williams                       _Senders...>,
1445cee9157SPatrick Williams             __transform_completion_signatures<
1455cee9157SPatrick Williams                 __completion_signatures_of_t<_Senders, _Env...>,
1465cee9157SPatrick Williams                 __mconst<completion_signatures<>>::__f, __set_error_t,
1475cee9157SPatrick Williams                 completion_signatures<>, __concat_completion_signatures>...>;
1485cee9157SPatrick Williams };
1495cee9157SPatrick Williams 
1505cee9157SPatrick Williams template <class _Tag, class _Receiver>
__complete_fn(_Tag,_Receiver & __rcvr)1515cee9157SPatrick Williams auto __complete_fn(_Tag, _Receiver& __rcvr) noexcept
1525cee9157SPatrick Williams {
1535cee9157SPatrick Williams     return [&]<class... _Ts>(_Ts&... __ts) noexcept {
1545cee9157SPatrick Williams         _Tag()(static_cast<_Receiver&&>(__rcvr), static_cast<_Ts&&>(__ts)...);
1555cee9157SPatrick Williams     };
1565cee9157SPatrick Williams }
1575cee9157SPatrick Williams 
1585cee9157SPatrick Williams template <class _Receiver, class _ValuesTuple>
__set_values(_Receiver & __rcvr,_ValuesTuple & __values)1595cee9157SPatrick Williams void __set_values(_Receiver& __rcvr, _ValuesTuple& __values) noexcept
1605cee9157SPatrick Williams {
1615cee9157SPatrick Williams     __values.apply(
1625cee9157SPatrick Williams         [&](auto&... __opt_vals) noexcept -> void {
1635cee9157SPatrick Williams             __tup::__cat_apply(__when_all::__complete_fn(set_value, __rcvr),
1645cee9157SPatrick Williams                                *__opt_vals...);
1655cee9157SPatrick Williams         },
1665cee9157SPatrick Williams         __values);
1675cee9157SPatrick Williams }
1685cee9157SPatrick Williams 
1695cee9157SPatrick Williams template <class _Env, class _Sender>
1705cee9157SPatrick Williams using __values_opt_tuple_t = //
1715cee9157SPatrick Williams     value_types_of_t<_Sender, __env_t<_Env>, __decayed_tuple, __optional>;
1725cee9157SPatrick Williams 
1735cee9157SPatrick Williams template <class _Env, __max1_sender<__env_t<_Env>>... _Senders>
1745cee9157SPatrick Williams struct __traits
1755cee9157SPatrick Williams {
1765cee9157SPatrick Williams     // tuple<optional<tuple<Vs1...>>, optional<tuple<Vs2...>>, ...>
1775cee9157SPatrick Williams     using __values_tuple = //
1785cee9157SPatrick Williams         __minvoke<__with_default<
1795cee9157SPatrick Williams                       __mtransform<__mbind_front_q<__values_opt_tuple_t, _Env>,
1805cee9157SPatrick Williams                                    __q<__tuple_for>>,
1815cee9157SPatrick Williams                       __ignore>,
1825cee9157SPatrick Williams                   _Senders...>;
1835cee9157SPatrick Williams 
1845cee9157SPatrick Williams     using __collect_errors = __mbind_front_q<__mset_insert, __mset<>>;
1855cee9157SPatrick Williams 
1865cee9157SPatrick Williams     using __errors_list = //
1875cee9157SPatrick Williams         __minvoke<
1885cee9157SPatrick Williams             __mconcat<>,
1895cee9157SPatrick Williams             __if<__mand<__nothrow_decay_copyable_results<_Senders, _Env>...>,
1905cee9157SPatrick Williams                  __types<>, __types<std::exception_ptr>>,
1915cee9157SPatrick Williams             __error_types_of_t<_Senders, __env_t<_Env>, __q<__types>>...>;
1925cee9157SPatrick Williams 
1935cee9157SPatrick Williams     using __errors_variant =
1945cee9157SPatrick Williams         __mapply<__q<__uniqued_variant_for>, __errors_list>;
1955cee9157SPatrick Williams };
1965cee9157SPatrick Williams 
1975cee9157SPatrick Williams struct _INVALID_ARGUMENTS_TO_WHEN_ALL_
1985cee9157SPatrick Williams {};
1995cee9157SPatrick Williams 
2005cee9157SPatrick Williams template <class _ErrorsVariant, class _ValuesTuple, class _StopToken>
2015cee9157SPatrick Williams struct __when_all_state
2025cee9157SPatrick Williams {
2035cee9157SPatrick Williams     using __stop_callback_t =
2045cee9157SPatrick Williams         stop_callback_for_t<_StopToken, __on_stop_request>;
2055cee9157SPatrick Williams 
2065cee9157SPatrick Williams     template <class _Receiver>
__arrivestdexec::__when_all::__when_all_state2075cee9157SPatrick Williams     void __arrive(_Receiver& __rcvr) noexcept
2085cee9157SPatrick Williams     {
2095cee9157SPatrick Williams         if (0 == --__count_)
2105cee9157SPatrick Williams         {
2115cee9157SPatrick Williams             __complete(__rcvr);
2125cee9157SPatrick Williams         }
2135cee9157SPatrick Williams     }
2145cee9157SPatrick Williams 
2155cee9157SPatrick Williams     template <class _Receiver>
__completestdexec::__when_all::__when_all_state2165cee9157SPatrick Williams     void __complete(_Receiver& __rcvr) noexcept
2175cee9157SPatrick Williams     {
2185cee9157SPatrick Williams         // Stop callback is no longer needed. Destroy it.
2195cee9157SPatrick Williams         __on_stop_.reset();
2205cee9157SPatrick Williams         // All child operations have completed and arrived at the barrier.
2215cee9157SPatrick Williams         switch (__state_.load(std::memory_order_relaxed))
2225cee9157SPatrick Williams         {
2235cee9157SPatrick Williams             case __started:
2245cee9157SPatrick Williams                 if constexpr (!same_as<_ValuesTuple, __ignore>)
2255cee9157SPatrick Williams                 {
2265cee9157SPatrick Williams                     // All child operations completed successfully:
2275cee9157SPatrick Williams                     __when_all::__set_values(__rcvr, __values_);
2285cee9157SPatrick Williams                 }
2295cee9157SPatrick Williams                 break;
2305cee9157SPatrick Williams             case __error:
2315cee9157SPatrick Williams                 if constexpr (!__same_as<_ErrorsVariant, __variant_for<>>)
2325cee9157SPatrick Williams                 {
2335cee9157SPatrick Williams                     // One or more child operations completed with an error:
2345cee9157SPatrick Williams                     __errors_.visit(__complete_fn(set_error, __rcvr),
2355cee9157SPatrick Williams                                     __errors_);
2365cee9157SPatrick Williams                 }
2375cee9157SPatrick Williams                 break;
2385cee9157SPatrick Williams             case __stopped:
2395cee9157SPatrick Williams                 stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr));
2405cee9157SPatrick Williams                 break;
2415cee9157SPatrick Williams             default:;
2425cee9157SPatrick Williams         }
2435cee9157SPatrick Williams     }
2445cee9157SPatrick Williams 
2455cee9157SPatrick Williams     std::atomic<std::size_t> __count_;
2465cee9157SPatrick Williams     inplace_stop_source __stop_source_{};
2475cee9157SPatrick Williams     // Could be non-atomic here and atomic_ref everywhere except __completion_fn
2485cee9157SPatrick Williams     std::atomic<__state_t> __state_{__started};
2495cee9157SPatrick Williams     _ErrorsVariant __errors_{};
2505cee9157SPatrick Williams     STDEXEC_ATTRIBUTE((no_unique_address))
2515cee9157SPatrick Williams     _ValuesTuple __values_{};
2525cee9157SPatrick Williams     __optional<__stop_callback_t> __on_stop_{};
2535cee9157SPatrick Williams };
2545cee9157SPatrick Williams 
2555cee9157SPatrick Williams template <class _Env>
__mk_state_fn(const _Env &)2565cee9157SPatrick Williams static auto __mk_state_fn(const _Env&) noexcept
2575cee9157SPatrick Williams {
2585cee9157SPatrick Williams     return []<__max1_sender<__env_t<_Env>>... _Child>(__ignore, __ignore,
2595cee9157SPatrick Williams                                                       _Child&&...) {
2605cee9157SPatrick Williams         using _Traits = __traits<_Env, _Child...>;
2615cee9157SPatrick Williams         using _ErrorsVariant = typename _Traits::__errors_variant;
2625cee9157SPatrick Williams         using _ValuesTuple = typename _Traits::__values_tuple;
2635cee9157SPatrick Williams         using _State = __when_all_state<_ErrorsVariant, _ValuesTuple,
2645cee9157SPatrick Williams                                         stop_token_of_t<_Env>>;
2655cee9157SPatrick Williams         return _State{sizeof...(_Child)};
2665cee9157SPatrick Williams     };
2675cee9157SPatrick Williams }
2685cee9157SPatrick Williams 
2695cee9157SPatrick Williams template <class _Env>
2705cee9157SPatrick Williams using __mk_state_fn_t = decltype(__when_all::__mk_state_fn(__declval<_Env>()));
2715cee9157SPatrick Williams 
2725cee9157SPatrick Williams struct when_all_t
2735cee9157SPatrick Williams {
2745cee9157SPatrick Williams     // Used by the default_domain to find legacy customizations:
2755cee9157SPatrick Williams     using _Sender = __1;
2765cee9157SPatrick Williams     using __legacy_customizations_t = //
2775cee9157SPatrick Williams         __types<tag_invoke_t(when_all_t, _Sender...)>;
2785cee9157SPatrick Williams 
2795cee9157SPatrick Williams     template <sender... _Senders>
2805cee9157SPatrick Williams         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::when_all_t2815cee9157SPatrick Williams     auto operator()(_Senders&&... __sndrs) const -> __well_formed_sender auto
2825cee9157SPatrick Williams     {
2835cee9157SPatrick Williams         auto __domain = __domain::__common_domain_t<_Senders...>();
2845cee9157SPatrick Williams         return stdexec::transform_sender(
2855cee9157SPatrick Williams             __domain, __make_sexpr<when_all_t>(
2865cee9157SPatrick Williams                           __(), static_cast<_Senders&&>(__sndrs)...));
2875cee9157SPatrick Williams     }
2885cee9157SPatrick Williams };
2895cee9157SPatrick Williams 
2905cee9157SPatrick Williams struct __when_all_impl : __sexpr_defaults
2915cee9157SPatrick Williams {
2925cee9157SPatrick Williams     template <class _Self, class _Env>
2935cee9157SPatrick Williams     using __error_t = __mexception<_INVALID_ARGUMENTS_TO_WHEN_ALL_,
2945cee9157SPatrick Williams                                    __children_of<_Self, __q<_WITH_SENDERS_>>,
2955cee9157SPatrick Williams                                    _WITH_ENVIRONMENT_<_Env>>;
2965cee9157SPatrick Williams 
2975cee9157SPatrick Williams     template <class _Self, class... _Env>
2985cee9157SPatrick Williams     using __completions =
2995cee9157SPatrick Williams         __children_of<_Self, __completions_t<__env_t<_Env>...>>;
3005cee9157SPatrick Williams 
3015cee9157SPatrick Williams     static constexpr auto get_attrs = //
3025cee9157SPatrick Williams         []<class... _Child>(__ignore, const _Child&...) noexcept {
3035cee9157SPatrick Williams             using _Domain = __domain::__common_domain_t<_Child...>;
3045cee9157SPatrick Williams             if constexpr (__same_as<_Domain, default_domain>)
3055cee9157SPatrick Williams             {
3065cee9157SPatrick Williams                 return env();
3075cee9157SPatrick Williams             }
3085cee9157SPatrick Williams             else
3095cee9157SPatrick Williams             {
3105cee9157SPatrick Williams                 return prop{get_domain, _Domain()};
3115cee9157SPatrick Williams             }
3125cee9157SPatrick Williams         };
3135cee9157SPatrick Williams 
3145cee9157SPatrick Williams     static constexpr auto get_completion_signatures = //
3155cee9157SPatrick Williams         []<class _Self, class... _Env>(_Self&&, _Env&&...) noexcept {
3165cee9157SPatrick Williams             static_assert(sender_expr_for<_Self, when_all_t>);
3175cee9157SPatrick Williams             return __minvoke<__mtry_catch<__q<__completions>, __q<__error_t>>,
3185cee9157SPatrick Williams                              _Self, _Env...>();
3195cee9157SPatrick Williams         };
3205cee9157SPatrick Williams 
3215cee9157SPatrick Williams     static constexpr auto get_env =                                         //
3225cee9157SPatrick Williams         []<class _State, class _Receiver>(__ignore, _State& __state,
3235cee9157SPatrick Williams                                           const _Receiver& __rcvr) noexcept //
3245cee9157SPatrick Williams         -> __env_t<env_of_t<const _Receiver&>> {
3255cee9157SPatrick Williams         return __mkenv(stdexec::get_env(__rcvr), __state.__stop_source_);
3265cee9157SPatrick Williams     };
3275cee9157SPatrick Williams 
3285cee9157SPatrick Williams     static constexpr auto get_state = //
3295cee9157SPatrick Williams         []<class _Self, class _Receiver>(_Self&& __self, _Receiver& __rcvr)
3305cee9157SPatrick Williams         -> __sexpr_apply_result_t<_Self, __mk_state_fn_t<env_of_t<_Receiver>>> {
3315cee9157SPatrick Williams         return __sexpr_apply(
3325cee9157SPatrick Williams             static_cast<_Self&&>(__self),
3335cee9157SPatrick Williams             __when_all::__mk_state_fn(stdexec::get_env(__rcvr)));
3345cee9157SPatrick Williams     };
3355cee9157SPatrick Williams 
3365cee9157SPatrick Williams     static constexpr auto start = //
3375cee9157SPatrick Williams         []<class _State, class _Receiver, class... _Operations>(
3385cee9157SPatrick Williams             _State& __state, _Receiver& __rcvr,
3395cee9157SPatrick Williams             _Operations&... __child_ops) noexcept -> void {
3405cee9157SPatrick Williams         // register stop callback:
3415cee9157SPatrick Williams         __state.__on_stop_.emplace(get_stop_token(stdexec::get_env(__rcvr)),
3425cee9157SPatrick Williams                                    __on_stop_request{__state.__stop_source_});
3435cee9157SPatrick Williams         if (__state.__stop_source_.stop_requested())
3445cee9157SPatrick Williams         {
3455cee9157SPatrick Williams             // Stop has already been requested. Don't bother starting
3465cee9157SPatrick Williams             // the child operations.
3475cee9157SPatrick Williams             stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr));
3485cee9157SPatrick Williams         }
3495cee9157SPatrick Williams         else
3505cee9157SPatrick Williams         {
3515cee9157SPatrick Williams             (stdexec::start(__child_ops), ...);
3525cee9157SPatrick Williams             if constexpr (sizeof...(__child_ops) == 0)
3535cee9157SPatrick Williams             {
3545cee9157SPatrick Williams                 __state.__complete(__rcvr);
3555cee9157SPatrick Williams             }
3565cee9157SPatrick Williams         }
3575cee9157SPatrick Williams     };
3585cee9157SPatrick Williams 
3595cee9157SPatrick Williams     template <class _State, class _Receiver, class _Error>
__set_errorstdexec::__when_all::__when_all_impl3605cee9157SPatrick Williams     static void __set_error(_State& __state, _Receiver&,
3615cee9157SPatrick Williams                             _Error&& __err) noexcept
3625cee9157SPatrick Williams     {
3635cee9157SPatrick Williams         // TODO: What memory orderings are actually needed here?
3645cee9157SPatrick Williams         if (__error != __state.__state_.exchange(__error))
3655cee9157SPatrick Williams         {
3665cee9157SPatrick Williams             __state.__stop_source_.request_stop();
3675cee9157SPatrick Williams             // We won the race, free to write the error into the operation
3685cee9157SPatrick Williams             // state without worry.
3695cee9157SPatrick Williams             if constexpr (__nothrow_decay_copyable<_Error>)
3705cee9157SPatrick Williams             {
3715cee9157SPatrick Williams                 __state.__errors_.template emplace<__decay_t<_Error>>(
3725cee9157SPatrick Williams                     static_cast<_Error&&>(__err));
3735cee9157SPatrick Williams             }
3745cee9157SPatrick Williams             else
3755cee9157SPatrick Williams             {
3765cee9157SPatrick Williams                 try
3775cee9157SPatrick Williams                 {
3785cee9157SPatrick Williams                     __state.__errors_.template emplace<__decay_t<_Error>>(
3795cee9157SPatrick Williams                         static_cast<_Error&&>(__err));
3805cee9157SPatrick Williams                 }
3815cee9157SPatrick Williams                 catch (...)
3825cee9157SPatrick Williams                 {
3835cee9157SPatrick Williams                     __state.__errors_.template emplace<std::exception_ptr>(
3845cee9157SPatrick Williams                         std::current_exception());
3855cee9157SPatrick Williams                 }
3865cee9157SPatrick Williams             }
3875cee9157SPatrick Williams         }
3885cee9157SPatrick Williams     }
3895cee9157SPatrick Williams 
3905cee9157SPatrick Williams     static constexpr auto complete = //
3915cee9157SPatrick Williams         []<class _Index, class _State, class _Receiver, class _Set,
3925cee9157SPatrick Williams            class... _Args>(_Index, _State& __state, _Receiver& __rcvr, _Set,
3935cee9157SPatrick Williams                            _Args&&... __args) noexcept -> void {
3945cee9157SPatrick Williams         if constexpr (__same_as<_Set, set_error_t>)
3955cee9157SPatrick Williams         {
3965cee9157SPatrick Williams             __set_error(__state, __rcvr, static_cast<_Args&&>(__args)...);
3975cee9157SPatrick Williams         }
3985cee9157SPatrick Williams         else if constexpr (__same_as<_Set, set_stopped_t>)
3995cee9157SPatrick Williams         {
4005cee9157SPatrick Williams             __state_t __expected = __started;
4015cee9157SPatrick Williams             // Transition to the "stopped" state if and only if we're in the
4025cee9157SPatrick Williams             // "started" state. (If this fails, it's because we're in an
4035cee9157SPatrick Williams             // error state, which trumps cancellation.)
4045cee9157SPatrick Williams             if (__state.__state_.compare_exchange_strong(__expected, __stopped))
4055cee9157SPatrick Williams             {
4065cee9157SPatrick Williams                 __state.__stop_source_.request_stop();
4075cee9157SPatrick Williams             }
4085cee9157SPatrick Williams         }
4095cee9157SPatrick Williams         else if constexpr (!__same_as<decltype(_State::__values_), __ignore>)
4105cee9157SPatrick Williams         {
4115cee9157SPatrick Williams             // We only need to bother recording the completion values
4125cee9157SPatrick Williams             // if we're not already in the "error" or "stopped" state.
4135cee9157SPatrick Williams             if (__state.__state_ == __started)
4145cee9157SPatrick Williams             {
4155cee9157SPatrick Williams                 auto& __opt_values = __tup::get<__v<_Index>>(__state.__values_);
4165cee9157SPatrick Williams                 using _Tuple = __decayed_tuple<_Args...>;
4175cee9157SPatrick Williams                 static_assert(
4185cee9157SPatrick Williams                     __same_as<decltype(*__opt_values), _Tuple&>,
4195cee9157SPatrick Williams                     "One of the senders in this when_all() is fibbing about what types it sends");
4205cee9157SPatrick Williams                 if constexpr ((__nothrow_decay_copyable<_Args> && ...))
4215cee9157SPatrick Williams                 {
4225cee9157SPatrick Williams                     __opt_values.emplace(
4235cee9157SPatrick Williams                         _Tuple{{static_cast<_Args&&>(__args)}...});
4245cee9157SPatrick Williams                 }
4255cee9157SPatrick Williams                 else
4265cee9157SPatrick Williams                 {
4275cee9157SPatrick Williams                     try
4285cee9157SPatrick Williams                     {
4295cee9157SPatrick Williams                         __opt_values.emplace(
4305cee9157SPatrick Williams                             _Tuple{{static_cast<_Args&&>(__args)}...});
4315cee9157SPatrick Williams                     }
4325cee9157SPatrick Williams                     catch (...)
4335cee9157SPatrick Williams                     {
4345cee9157SPatrick Williams                         __set_error(__state, __rcvr, std::current_exception());
4355cee9157SPatrick Williams                     }
4365cee9157SPatrick Williams                 }
4375cee9157SPatrick Williams             }
4385cee9157SPatrick Williams         }
4395cee9157SPatrick Williams 
4405cee9157SPatrick Williams         __state.__arrive(__rcvr);
4415cee9157SPatrick Williams     };
4425cee9157SPatrick Williams };
4435cee9157SPatrick Williams 
4445cee9157SPatrick Williams struct when_all_with_variant_t
4455cee9157SPatrick Williams {
4465cee9157SPatrick Williams     using _Sender = __1;
4475cee9157SPatrick Williams     using __legacy_customizations_t = //
4485cee9157SPatrick Williams         __types<tag_invoke_t(when_all_with_variant_t, _Sender...)>;
4495cee9157SPatrick Williams 
4505cee9157SPatrick Williams     template <sender... _Senders>
4515cee9157SPatrick Williams         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::when_all_with_variant_t4525cee9157SPatrick Williams     auto operator()(_Senders&&... __sndrs) const -> __well_formed_sender auto
4535cee9157SPatrick Williams     {
4545cee9157SPatrick Williams         auto __domain = __domain::__common_domain_t<_Senders...>();
4555cee9157SPatrick Williams         return stdexec::transform_sender(
4565cee9157SPatrick Williams             __domain, __make_sexpr<when_all_with_variant_t>(
4575cee9157SPatrick Williams                           __(), static_cast<_Senders&&>(__sndrs)...));
4585cee9157SPatrick Williams     }
4595cee9157SPatrick Williams 
4605cee9157SPatrick Williams     template <class _Sender, class _Env>
transform_senderstdexec::__when_all::when_all_with_variant_t4615cee9157SPatrick Williams     static auto transform_sender(_Sender&& __sndr, const _Env&)
4625cee9157SPatrick Williams     {
4635cee9157SPatrick Williams         // transform the when_all_with_variant into a regular when_all (looking
4645cee9157SPatrick Williams         // for early when_all customizations), then transform it again to look
4655cee9157SPatrick Williams         // for late customizations.
4665cee9157SPatrick Williams         return __sexpr_apply(
4675cee9157SPatrick Williams             static_cast<_Sender&&>(__sndr),
4685cee9157SPatrick Williams             [&]<class... _Child>(__ignore, __ignore, _Child&&... __child) {
4695cee9157SPatrick Williams                 return when_all_t()(
4705cee9157SPatrick Williams                     into_variant(static_cast<_Child&&>(__child))...);
4715cee9157SPatrick Williams             });
4725cee9157SPatrick Williams     }
4735cee9157SPatrick Williams };
4745cee9157SPatrick Williams 
4755cee9157SPatrick Williams struct __when_all_with_variant_impl : __sexpr_defaults
4765cee9157SPatrick Williams {
4775cee9157SPatrick Williams     static constexpr auto get_attrs = //
4785cee9157SPatrick Williams         []<class... _Child>(__ignore, const _Child&...) noexcept {
4795cee9157SPatrick Williams             using _Domain = __domain::__common_domain_t<_Child...>;
4805cee9157SPatrick Williams             if constexpr (same_as<_Domain, default_domain>)
4815cee9157SPatrick Williams             {
4825cee9157SPatrick Williams                 return env();
4835cee9157SPatrick Williams             }
4845cee9157SPatrick Williams             else
4855cee9157SPatrick Williams             {
4865cee9157SPatrick Williams                 return prop{get_domain, _Domain()};
4875cee9157SPatrick Williams             }
4885cee9157SPatrick Williams         };
4895cee9157SPatrick Williams 
4905cee9157SPatrick Williams     static constexpr auto get_completion_signatures = //
4915cee9157SPatrick Williams         []<class _Sender>(_Sender&&) noexcept         //
4925cee9157SPatrick Williams         -> __completion_signatures_of_t<              //
4935cee9157SPatrick Williams             transform_sender_result_t<default_domain, _Sender, empty_env>> {
4945cee9157SPatrick Williams         return {};
4955cee9157SPatrick Williams     };
4965cee9157SPatrick Williams };
4975cee9157SPatrick Williams 
4985cee9157SPatrick Williams struct transfer_when_all_t
4995cee9157SPatrick Williams {
5005cee9157SPatrick Williams     using _Env = __0;
5015cee9157SPatrick Williams     using _Sender = __1;
5025cee9157SPatrick Williams     using __legacy_customizations_t = //
5035cee9157SPatrick Williams         __types<tag_invoke_t(
5045cee9157SPatrick Williams             transfer_when_all_t,
5055cee9157SPatrick Williams             get_completion_scheduler_t<set_value_t>(const _Env&), _Sender...)>;
5065cee9157SPatrick Williams 
5075cee9157SPatrick Williams     template <scheduler _Scheduler, sender... _Senders>
5085cee9157SPatrick Williams         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::transfer_when_all_t509*06f265f6SPatrick Williams     auto operator()(_Scheduler&& __sched,
510*06f265f6SPatrick Williams                     _Senders&&... __sndrs) const -> __well_formed_sender auto
5115cee9157SPatrick Williams     {
5125cee9157SPatrick Williams         using _Env = __t<__schfr::__environ<__id<__decay_t<_Scheduler>>>>;
5135cee9157SPatrick Williams         auto __domain = query_or(get_domain, __sched, default_domain());
5145cee9157SPatrick Williams         return stdexec::transform_sender(
5155cee9157SPatrick Williams             __domain, __make_sexpr<transfer_when_all_t>(
5165cee9157SPatrick Williams                           _Env{static_cast<_Scheduler&&>(__sched)},
5175cee9157SPatrick Williams                           static_cast<_Senders&&>(__sndrs)...));
5185cee9157SPatrick Williams     }
5195cee9157SPatrick Williams 
5205cee9157SPatrick Williams     template <class _Sender, class _Env>
transform_senderstdexec::__when_all::transfer_when_all_t5215cee9157SPatrick Williams     static auto transform_sender(_Sender&& __sndr, const _Env&)
5225cee9157SPatrick Williams     {
5235cee9157SPatrick Williams         // transform the transfer_when_all into a regular transform | when_all
5245cee9157SPatrick Williams         // (looking for early customizations), then transform it again to look
5255cee9157SPatrick Williams         // for late customizations.
5265cee9157SPatrick Williams         return __sexpr_apply(
5275cee9157SPatrick Williams             static_cast<_Sender&&>(__sndr),
5285cee9157SPatrick Williams             [&]<class _Data, class... _Child>(__ignore, _Data&& __data,
5295cee9157SPatrick Williams                                               _Child&&... __child) {
530*06f265f6SPatrick Williams                 return continue_on(
531*06f265f6SPatrick Williams                     when_all_t()(static_cast<_Child&&>(__child)...),
5325cee9157SPatrick Williams                     get_completion_scheduler<set_value_t>(__data));
5335cee9157SPatrick Williams             });
5345cee9157SPatrick Williams     }
5355cee9157SPatrick Williams };
5365cee9157SPatrick Williams 
5375cee9157SPatrick Williams struct __transfer_when_all_impl : __sexpr_defaults
5385cee9157SPatrick Williams {
5395cee9157SPatrick Williams     static constexpr auto get_attrs = //
5405cee9157SPatrick Williams         []<class _Data>(const _Data& __data,
5415cee9157SPatrick Williams                         const auto&...) noexcept -> const _Data& {
5425cee9157SPatrick Williams         return __data;
5435cee9157SPatrick Williams     };
5445cee9157SPatrick Williams 
5455cee9157SPatrick Williams     static constexpr auto get_completion_signatures = //
5465cee9157SPatrick Williams         []<class _Sender>(_Sender&&) noexcept         //
5475cee9157SPatrick Williams         -> __completion_signatures_of_t<              //
5485cee9157SPatrick Williams             transform_sender_result_t<default_domain, _Sender, empty_env>> {
5495cee9157SPatrick Williams         return {};
5505cee9157SPatrick Williams     };
5515cee9157SPatrick Williams };
5525cee9157SPatrick Williams 
5535cee9157SPatrick Williams struct transfer_when_all_with_variant_t
5545cee9157SPatrick Williams {
5555cee9157SPatrick Williams     using _Env = __0;
5565cee9157SPatrick Williams     using _Sender = __1;
5575cee9157SPatrick Williams     using __legacy_customizations_t = //
5585cee9157SPatrick Williams         __types<tag_invoke_t(
5595cee9157SPatrick Williams             transfer_when_all_with_variant_t,
5605cee9157SPatrick Williams             get_completion_scheduler_t<set_value_t>(const _Env&), _Sender...)>;
5615cee9157SPatrick Williams 
5625cee9157SPatrick Williams     template <scheduler _Scheduler, sender... _Senders>
5635cee9157SPatrick Williams         requires __domain::__has_common_domain<_Senders...>
operator ()stdexec::__when_all::transfer_when_all_with_variant_t564*06f265f6SPatrick Williams     auto operator()(_Scheduler&& __sched,
565*06f265f6SPatrick Williams                     _Senders&&... __sndrs) const -> __well_formed_sender auto
5665cee9157SPatrick Williams     {
5675cee9157SPatrick Williams         using _Env = __t<__schfr::__environ<__id<__decay_t<_Scheduler>>>>;
5685cee9157SPatrick Williams         auto __domain = query_or(get_domain, __sched, default_domain());
5695cee9157SPatrick Williams         return stdexec::transform_sender(
5705cee9157SPatrick Williams             __domain, __make_sexpr<transfer_when_all_with_variant_t>(
5715cee9157SPatrick Williams                           _Env{{static_cast<_Scheduler&&>(__sched)}},
5725cee9157SPatrick Williams                           static_cast<_Senders&&>(__sndrs)...));
5735cee9157SPatrick Williams     }
5745cee9157SPatrick Williams 
5755cee9157SPatrick Williams     template <class _Sender, class _Env>
transform_senderstdexec::__when_all::transfer_when_all_with_variant_t5765cee9157SPatrick Williams     static auto transform_sender(_Sender&& __sndr, const _Env&)
5775cee9157SPatrick Williams     {
5785cee9157SPatrick Williams         // transform the transfer_when_all_with_variant into regular
5795cee9157SPatrick Williams         // transform_when_all and into_variant calls/ (looking for early
5805cee9157SPatrick Williams         // customizations), then transform it again to look for late
5815cee9157SPatrick Williams         // customizations.
5825cee9157SPatrick Williams         return __sexpr_apply(
5835cee9157SPatrick Williams             static_cast<_Sender&&>(__sndr),
5845cee9157SPatrick Williams             [&]<class _Data, class... _Child>(__ignore, _Data&& __data,
5855cee9157SPatrick Williams                                               _Child&&... __child) {
5865cee9157SPatrick Williams                 return transfer_when_all_t()(
5875cee9157SPatrick Williams                     get_completion_scheduler<set_value_t>(
5885cee9157SPatrick Williams                         static_cast<_Data&&>(__data)),
5895cee9157SPatrick Williams                     into_variant(static_cast<_Child&&>(__child))...);
5905cee9157SPatrick Williams             });
5915cee9157SPatrick Williams     }
5925cee9157SPatrick Williams };
5935cee9157SPatrick Williams 
5945cee9157SPatrick Williams struct __transfer_when_all_with_variant_impl : __sexpr_defaults
5955cee9157SPatrick Williams {
5965cee9157SPatrick Williams     static constexpr auto get_attrs = //
5975cee9157SPatrick Williams         []<class _Data>(const _Data& __data,
5985cee9157SPatrick Williams                         const auto&...) noexcept -> const _Data& {
5995cee9157SPatrick Williams         return __data;
6005cee9157SPatrick Williams     };
6015cee9157SPatrick Williams 
6025cee9157SPatrick Williams     static constexpr auto get_completion_signatures = //
6035cee9157SPatrick Williams         []<class _Sender>(_Sender&&) noexcept         //
6045cee9157SPatrick Williams         -> __completion_signatures_of_t<              //
6055cee9157SPatrick Williams             transform_sender_result_t<default_domain, _Sender, empty_env>> {
6065cee9157SPatrick Williams         return {};
6075cee9157SPatrick Williams     };
6085cee9157SPatrick Williams };
6095cee9157SPatrick Williams } // namespace __when_all
6105cee9157SPatrick Williams 
6115cee9157SPatrick Williams using __when_all::when_all_t;
6125cee9157SPatrick Williams inline constexpr when_all_t when_all{};
6135cee9157SPatrick Williams 
6145cee9157SPatrick Williams using __when_all::when_all_with_variant_t;
6155cee9157SPatrick Williams inline constexpr when_all_with_variant_t when_all_with_variant{};
6165cee9157SPatrick Williams 
6175cee9157SPatrick Williams using __when_all::transfer_when_all_t;
6185cee9157SPatrick Williams inline constexpr transfer_when_all_t transfer_when_all{};
6195cee9157SPatrick Williams 
6205cee9157SPatrick Williams using __when_all::transfer_when_all_with_variant_t;
6215cee9157SPatrick Williams inline constexpr transfer_when_all_with_variant_t
6225cee9157SPatrick Williams     transfer_when_all_with_variant{};
6235cee9157SPatrick Williams 
6245cee9157SPatrick Williams template <>
6255cee9157SPatrick Williams struct __sexpr_impl<when_all_t> : __when_all::__when_all_impl
6265cee9157SPatrick Williams {};
6275cee9157SPatrick Williams 
6285cee9157SPatrick Williams template <>
6295cee9157SPatrick Williams struct __sexpr_impl<when_all_with_variant_t> :
6305cee9157SPatrick Williams     __when_all::__when_all_with_variant_impl
6315cee9157SPatrick Williams {};
6325cee9157SPatrick Williams 
6335cee9157SPatrick Williams template <>
6345cee9157SPatrick Williams struct __sexpr_impl<transfer_when_all_t> : __when_all::__transfer_when_all_impl
6355cee9157SPatrick Williams {};
6365cee9157SPatrick Williams 
6375cee9157SPatrick Williams template <>
6385cee9157SPatrick Williams struct __sexpr_impl<transfer_when_all_with_variant_t> :
6395cee9157SPatrick Williams     __when_all::__transfer_when_all_with_variant_impl
6405cee9157SPatrick Williams {};
6415cee9157SPatrick Williams } // namespace stdexec
642