diff --git a/include/beman/execution/detail/affine.hpp b/include/beman/execution/detail/affine.hpp index 7b3be2fe..80d48725 100644 --- a/include/beman/execution/detail/affine.hpp +++ b/include/beman/execution/detail/affine.hpp @@ -30,7 +30,7 @@ import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; import beman.execution.detail.set_value; import beman.execution.detail.store_receiver; -import beman.execution.detail.unstoppable; +import beman.execution.detail.unstoppable_scheduler; #else #include #include @@ -48,31 +48,12 @@ import beman.execution.detail.unstoppable; #include #include #include -#include +#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { -template -struct unstoppable_scheduler { - using scheduler_concept = typename Sched::scheduler_concept; - - template - requires requires { ::std::declval().query(::std::declval(), ::std::declval()...); } - auto query(const Q& q, Args&&... args) const noexcept -> decltype(auto) { - return sched.query(q, ::std::forward(args)...); - } - - auto schedule() const noexcept(std::is_nothrow_invocable_v<::beman::execution::schedule_t, Sched>) { - return ::beman::execution::unstoppable(::beman::execution::schedule(sched)); - } - - friend auto operator==(const unstoppable_scheduler& lhs, const unstoppable_scheduler& rhs) -> bool = default; - - Sched sched; -}; - /** * @brief The affine_t struct is a sender adaptor closure that transforms a sender * to complete on the scheduler obtained from the receiver's environment. diff --git a/include/beman/execution/detail/associate.hpp b/include/beman/execution/detail/associate.hpp index 2969e692..4638b027 100644 --- a/include/beman/execution/detail/associate.hpp +++ b/include/beman/execution/detail/associate.hpp @@ -18,10 +18,10 @@ import beman.execution.detail.basic_sender; import beman.execution.detail.connect; import beman.execution.detail.connect_result_t; import beman.execution.detail.completion_signatures; -import beman.execution.detail.completion_signatures_for; import beman.execution.detail.default_impls; import beman.execution.detail.env; import beman.execution.detail.forward_like; +import beman.execution.detail.get_completion_signatures; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.nothrow_callable; @@ -35,6 +35,7 @@ import beman.execution.detail.valid_completion_signatures; #else #include #include +#include #include #include #include @@ -118,7 +119,7 @@ struct associate_t { static consteval auto get_completion_signatures() { using Data = decltype(std::declval<::std::remove_cvref_t>().template get<1>()); using child_type_t = ::std::remove_cvref_t::wrap_sender>; - return ::beman::execution::detail::completion_signatures_for{}; + return ::beman::execution::get_completion_signatures(); } struct impls_for : ::beman::execution::detail::default_impls { diff --git a/include/beman/execution/detail/basic_sender.hpp b/include/beman/execution/detail/basic_sender.hpp index a013a89b..2cfb610d 100644 --- a/include/beman/execution/detail/basic_sender.hpp +++ b/include/beman/execution/detail/basic_sender.hpp @@ -74,7 +74,7 @@ struct basic_sender : ::beman::execution::detail::product_type decltype(auto) { auto&& d{this->template get<1>()}; return sub_apply.at<2>( - [&d](auto&&... c) { return ::beman::execution::detail::impls_for::get_attrs(d, c...); }, *this); + [&d](auto&&... c) { return ::beman::execution::detail::get_impls_for::get_attrs()(d, c...); }, *this); } template @@ -114,7 +114,7 @@ struct basic_sender : ::beman::execution::detail::product_type Self, typename... Env> requires(sizeof...(Env) == 1) || (... && !::beman::execution::dependent_sender) - static consteval auto get_completion_signatures() noexcept { + static consteval auto get_completion_signatures() { if constexpr (requires { Tag::template get_completion_signatures(); }) return Tag::template get_completion_signatures(); else diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index d630b6f0..f626a50f 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -25,9 +25,12 @@ import beman.execution.detail.connect; import beman.execution.detail.connect_result_t; import beman.execution.detail.decayed_tuple; import beman.execution.detail.default_impls; +import beman.execution.detail.env; import beman.execution.detail.env_of_t; import beman.execution.detail.error_types_of_t; import beman.execution.detail.fwd_env; +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_env; import beman.execution.detail.impls_for; @@ -49,6 +52,7 @@ import beman.execution.detail.sender_for; import beman.execution.detail.sender_in; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; +import beman.execution.detail.set_value; import beman.execution.detail.start; #else #include @@ -57,9 +61,12 @@ import beman.execution.detail.start; #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -79,6 +86,7 @@ import beman.execution.detail.start; #include #include #include +#include #include #endif @@ -103,13 +111,15 @@ struct continues_on_t { } private: - template + template struct get_signatures; + template + struct get_signatures : get_signatures> {}; template struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, Scheduler, Sender>, Env> { - using scheduler_sender = decltype(::beman::execution::schedule(::std::declval())); + using scheduler_sender = ::beman::execution::schedule_result_t; template using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; using type = ::beman::execution::detail::meta::combine< @@ -118,13 +128,54 @@ struct continues_on_t { ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; }; + template + struct attrs { + template + requires requires(const Scheduler& scheduler, const Env&... env) { + ::beman::execution::get_completion_scheduler(scheduler, + ::beman::execution::detail::fwd_env(env)...); + } + auto query(::beman::execution::get_completion_scheduler_t, const Env&... env) const noexcept { + return ::beman::execution::get_completion_scheduler(this->sch, env...); + } + + template + requires requires(const Scheduler& scheduler, const Env&... env) { + ::beman::execution::get_completion_domain(scheduler, ::beman::execution::detail::fwd_env(env)...); + } + auto query(::beman::execution::get_completion_domain_t, const Env&... env) const noexcept { + return ::beman::execution::get_completion_domain(this->sch, + ::beman::execution::detail::fwd_env(env)...); + } + + template + requires requires(const ChildAttrs& child_attrs, Q q, Args&&... args) { + child_attrs.query(q, ::std::forward(args)...); + } + auto query(Q q, Args&&... args) const noexcept { + return this->child_attrs.query(q, ::std::forward(args)...); + } + + Scheduler sch; + ChildAttrs child_attrs; + }; + public: template - static consteval auto get_completion_signatures() { + static consteval auto get_completion_signatures() noexcept { return typename get_signatures<::std::remove_cvref_t, Env...>::type{}; } struct impls_for : ::beman::execution::detail::default_impls { + struct get_attrs_impl { + auto operator()(const auto& sch, const auto& child) const noexcept { + using Sch = ::std::remove_cvref_t; + using ChildAttrs = ::std::remove_cvref_t; + return attrs{sch, ::beman::execution::get_env(child)}; + } + }; + static constexpr auto get_attrs{get_attrs_impl{}}; + template struct upstream_receiver { using receiver_concept = ::beman::execution::receiver_tag; diff --git a/include/beman/execution/detail/get_completion_scheduler.hpp b/include/beman/execution/detail/get_completion_scheduler.hpp index de5a67a3..cb7cba53 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -18,11 +18,13 @@ import beman.execution.detail.completion_tag; import beman.execution.detail.forwarding_query; import beman.execution.detail.scheduler; import beman.execution.detail.set_value; +import beman.execution.detail.try_query; #else #include #include #include #include +#include #endif // ---------------------------------------------------------------------------- @@ -38,7 +40,8 @@ template concept compl_sched_recurse_queryable = requires { { ::beman::execution::detail::recurse_query( - ::std::declval().query( + ::beman::execution::detail::try_query( + ::std::declval(), ::std::declval<::beman::execution::detail::get_completion_scheduler_t>(), ::std::declval()...), ::std::declval()...) @@ -49,18 +52,18 @@ template <::beman::execution::detail::completion_tag Tag> struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { template requires ::beman::execution::detail::compl_sched_recurse_queryable || - (::beman::execution::scheduler && sizeof...(E) > 0) + ::beman::execution::scheduler auto operator()(const Q& q, const E&... e) const noexcept; }; template auto recurse_query(Scheduler sch, const Envs&... envs) noexcept { ::beman::execution::detail::get_completion_scheduler_t<::beman::execution::set_value_t> get_compl_sch{}; - if constexpr (requires { ::std::as_const(sch).query(get_compl_sch, envs...); }) { - auto sch2 = ::std::as_const(sch).query(get_compl_sch, envs...); + if constexpr (requires { ::beman::execution::detail::try_query(sch, get_compl_sch, envs...); }) { + auto sch2 = ::beman::execution::detail::try_query(sch, get_compl_sch, envs...); if constexpr (::std::same_as) { while (sch != sch2) { - sch = ::std::exchange(sch2, ::std::as_const(sch2).query(get_compl_sch, envs...)); + sch = ::std::exchange(sch2, ::beman::execution::detail::try_query(sch2, get_compl_sch, envs...)); } return sch; } else { @@ -74,12 +77,12 @@ auto recurse_query(Scheduler sch, const Envs&... envs) noexcept { template <::beman::execution::detail::completion_tag Tag> template requires ::beman::execution::detail::compl_sched_recurse_queryable || - (::beman::execution::scheduler && sizeof...(E) > 0) + ::beman::execution::scheduler auto get_completion_scheduler_t::operator()(const Q& q, const E&... e) const noexcept { if constexpr (::beman::execution::detail::compl_sched_recurse_queryable) { - return ::beman::execution::detail::recurse_query(q.query(*this, e...), e...); + return ::beman::execution::detail::recurse_query(::beman::execution::detail::try_query(q, *this, e...), e...); } else { - static_assert(::beman::execution::scheduler && sizeof...(E) > 0); + static_assert(::beman::execution::scheduler); return q; } } diff --git a/include/beman/execution/detail/get_completion_signatures.hpp b/include/beman/execution/detail/get_completion_signatures.hpp index dcf513ce..9acc05cb 100644 --- a/include/beman/execution/detail/get_completion_signatures.hpp +++ b/include/beman/execution/detail/get_completion_signatures.hpp @@ -73,6 +73,15 @@ consteval auto get_completion_signatures() -> ::beman::execution::detail::valid_ ::std::remove_cvref_t::template get_completion_signatures()>) { return ::std::remove_cvref_t::template get_completion_signatures(); } + } else if constexpr (requires { + { + ::std::remove_cvref_t::get_completion_signatures() + } -> ::beman::execution::detail::valid_completion_signatures; + }) { + if constexpr (::beman::execution::detail::is_constant< + ::std::remove_cvref_t::get_completion_signatures()>) { + return ::std::remove_cvref_t::get_completion_signatures(); + } } }}; if constexpr (requires { diff --git a/include/beman/execution/detail/let.hpp b/include/beman/execution/detail/let.hpp index c40c3b14..97f8a14b 100644 --- a/include/beman/execution/detail/let.hpp +++ b/include/beman/execution/detail/let.hpp @@ -21,17 +21,19 @@ import beman.execution.detail.allocator_aware_move; import beman.execution.detail.basic_sender; import beman.execution.detail.call_result_t; import beman.execution.detail.completion_signatures; -import beman.execution.detail.completion_signatures_for; import beman.execution.detail.completion_signatures_of_t; import beman.execution.detail.connect; import beman.execution.detail.decayed_tuple; import beman.execution.detail.default_impls; +import beman.execution.detail.dependent_sender; import beman.execution.detail.emplace_from; import beman.execution.detail.env; import beman.execution.detail.env_of_t; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; +import beman.execution.detail.gather_signatures; import beman.execution.detail.get_env; +import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_domain; @@ -57,16 +59,18 @@ import beman.execution.detail.start; import beman.execution.detail.type_list; #else #include -#include #include #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -101,15 +105,32 @@ struct let_matching_completion : ::std::false_type {}; template struct let_matching_completion : ::std::true_type {}; -template -struct let_upstream_env_helper { - using type = decltype(::beman::execution::detail::join_env(::std::declval(), ::std::declval()...)); -}; -template -struct let_upstream_env_helper { - using type = Child; +template +struct get_successor_senders; + +template +struct get_successor_senders> { + using type = std::invoke_result_t; }; +template +struct non_dependent_successor_helper; + +template +struct non_dependent_successor_helper> + : std::bool_constant<(... && + !::beman::execution::dependent_sender< + typename ::beman::execution::detail::get_successor_senders::type>)> {}; + +template +struct non_dependent_successor + : ::beman::execution::detail::non_dependent_successor_helper< + Fun, + ::beman::execution::detail::gather_signatures, + ::beman::execution::detail::type_list, + ::beman::execution::detail::type_list>> {}; + template struct let_t { template <::beman::execution::detail::movable_value Fun> @@ -121,37 +142,48 @@ struct let_t { return ::beman::execution::detail::make_sender(*this, ::std::forward(fun), std::forward(sender)); } - template - static auto env(Sender&& sender) { + template + static auto let_env(const Sender& sender, const Env& e) { if constexpr (requires { ::beman::execution::detail::sched_env( ::beman::execution::get_completion_scheduler( - ::beman::execution::get_env(sender))); - }) - return ::beman::execution::detail::sched_env( - ::beman::execution::get_completion_scheduler(::beman::execution::get_env(sender))); - else if constexpr (requires { - ::beman::execution::detail::make_env( - ::beman::execution::get_domain, - ::beman::execution::get_domain(::beman::execution::get_env(sender))); - }) + ::beman::execution::get_env(sender), ::beman::execution::detail::fwd_env(e))); + }) { + return ::beman::execution::detail::sched_env(::beman::execution::get_completion_scheduler( + ::beman::execution::get_env(sender), ::beman::execution::detail::fwd_env(e))); + } else if constexpr (requires { + ::beman::execution::detail::make_env( + ::beman::execution::get_domain, + ::beman::execution::get_completion_domain( + ::beman::execution::get_env(sender), ::beman::execution::detail::fwd_env(e))); + }) return ::beman::execution::detail::make_env( - ::beman::execution::get_domain, ::beman::execution::get_domain(::beman::execution::get_env(sender))); - else + ::beman::execution::get_domain, + ::beman::execution::get_completion_domain(::beman::execution::get_env(sender), + ::beman::execution::detail::fwd_env(e))); + else { return ::beman::execution::env<>{}; - } - template - static auto join_env(Sender&& sender, Env&& e) -> decltype(auto) { - return ::beman::execution::detail::join_env(env(sender), ::beman::execution::detail::fwd_env(e)); + } } + template + using let_env_t = decltype(let_env(::std::declval(), ::std::declval())); + private: template struct get_signatures; - template + + template + requires ::beman::execution::detail::non_dependent_successor::value + struct get_signatures< + ::beman::execution::detail::basic_sender<::beman::execution::detail::let_t, Fun, Child>> + : get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::let_t, Fun, Child>, + ::beman::execution::env<>> {}; + + template struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::let_t, Fun, Child>, - Env...> { + Env> { template using other_completion = let_other_completion; template @@ -163,38 +195,44 @@ struct let_t { struct apply_decayed { using sender_type = ::beman::execution::detail::call_result_t...>; using completions = ::std::conditional_t< - noexcept(::std::declval()(std::declval<::std::decay_t>()...)), + noexcept(::std::declval()(::std::declval<::std::decay_t>()...)), ::beman::execution::completion_signatures<>, ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; }; + + using successor_env = + ::beman::execution::detail::join_env, ::beman::execution::detail::fwd_env>; + template struct get_completions; template