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