From 2e19eacde944b497b80a8a540a2a19298fdb76c0 Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Thu, 4 Jun 2026 21:18:22 +0800 Subject: [PATCH 1/7] Fix get-attrs in continues_on, starts_on and when_all --- .../beman/execution/detail/basic_sender.hpp | 4 +- .../beman/execution/detail/continues_on.hpp | 61 +++++++- .../detail/get_completion_scheduler.hpp | 15 +- .../detail/get_completion_signatures.hpp | 9 ++ include/beman/execution/detail/let.hpp | 120 ++++++++++----- include/beman/execution/detail/starts_on.hpp | 138 ++++++++++++------ include/beman/execution/detail/when_all.hpp | 54 ++++++- tests/beman/execution/CMakeLists.txt | 2 + .../execution/exec-continues-on.test.cpp | 3 + .../execution/exec-dependent-sender.test.cpp | 29 ++++ .../exec-get-start-scheduler.test.cpp | 98 +++++++++++++ tests/beman/execution/exec-starts-on.test.cpp | 22 +++ tests/beman/execution/exec-when-all.test.cpp | 23 ++- 13 files changed, 482 insertions(+), 96 deletions(-) create mode 100644 tests/beman/execution/exec-dependent-sender.test.cpp create mode 100644 tests/beman/execution/exec-get-start-scheduler.test.cpp 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..89ae549a 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,19 +111,53 @@ 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< - decltype(::beman::execution::get_completion_signatures()), - ::beman::execution::error_types_of_t, - ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + decltype(::beman::execution::get_completion_signatures()), + ::beman::execution::error_types_of_t, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + }; + + template + struct attrs { + template + auto query(::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>, + const Env&) const noexcept { + return this->sch; + } + + auto query(::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>) const noexcept { + return this->sch; + } + + 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: @@ -125,6 +167,15 @@ struct continues_on_t { } 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..963d40aa 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -4,6 +4,8 @@ #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_SCHEDULER #define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_SCHEDULER +#include "try_query.hpp" + #include #include #ifdef BEMAN_HAS_IMPORT_STD @@ -18,11 +20,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 +42,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()...) @@ -56,11 +61,11 @@ struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { 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 { @@ -77,7 +82,7 @@ template (::beman::execution::scheduler && sizeof...(E) > 0) 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); 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..5b54370c 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,49 @@ 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))); + ::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_domain(::beman::execution::get_env(sender))); + ::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 +196,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