From c956bb0d65e7eb1155214f57fe6f872b387efe68 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Tue, 27 Oct 2026 18:09:49 +0800 Subject: [PATCH 1/5] Add is_completion_query type traits and integrate into query logic --- .../beman/execution/detail/continues_on.hpp | 15 ++++--- include/beman/execution/detail/get_domain.hpp | 9 ----- .../execution/detail/is_completion_query.hpp | 39 +++++++++++++++++++ include/beman/execution/detail/on.hpp | 21 ++++------ .../execution/detail/parallel_scheduler.hpp | 5 +++ include/beman/execution/detail/run_loop.hpp | 9 +++++ include/beman/execution/detail/starts_on.hpp | 27 +++++++------ .../beman/execution/detail/task_scheduler.hpp | 5 +++ src/beman/execution/CMakeLists.txt | 2 + src/beman/execution/is_completion_query.cppm | 12 ++++++ .../execution/exec-run-loop-types.test.cpp | 3 +- tests/beman/execution/exec-starts-on.test.cpp | 11 ------ 12 files changed, 102 insertions(+), 56 deletions(-) create mode 100644 include/beman/execution/detail/is_completion_query.hpp create mode 100644 src/beman/execution/is_completion_query.cppm diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index 70db1ef0..b4f74adb 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -37,6 +37,7 @@ import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_env; import beman.execution.detail.hide_sched; import beman.execution.detail.impls_for; +import beman.execution.detail.is_completion_query; import beman.execution.detail.join_env; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -75,6 +76,7 @@ import beman.execution.detail.start; #include #include #include +#include #include #include #include @@ -188,12 +190,13 @@ struct continues_on_t { return ::beman::execution::get_completion_domain(this->sch, this->template wrap_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)...); + template + requires(!::beman::execution::detail::is_completion_query_v) && + requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { + q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); + } + auto query(Query q, Args&&... args) const noexcept { + return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); } Scheduler sch; diff --git a/include/beman/execution/detail/get_domain.hpp b/include/beman/execution/detail/get_domain.hpp index 51325e24..ce75e0b5 100644 --- a/include/beman/execution/detail/get_domain.hpp +++ b/include/beman/execution/detail/get_domain.hpp @@ -47,15 +47,6 @@ struct get_domain_t : ::beman::execution::forwarding_query_t { ::beman::execution::get_start_scheduler(env), ::beman::execution::detail::hide_sched(env)))); static_assert(noexcept(type{})); return type{}; - } else if constexpr (requires { - ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( - ::beman::execution::get_start_scheduler(env), - ::beman::execution::detail::hide_sched(env)); - }) { - using type = decltype(auto(::beman::execution::get_completion_domain<::beman::execution::set_value_t>( - ::beman::execution::get_start_scheduler(env), ::beman::execution::detail::hide_sched(env)))); - static_assert(noexcept(type{})); - return type{}; } else { return ::beman::execution::default_domain{}; } diff --git a/include/beman/execution/detail/is_completion_query.hpp b/include/beman/execution/detail/is_completion_query.hpp new file mode 100644 index 00000000..45be41b9 --- /dev/null +++ b/include/beman/execution/detail/is_completion_query.hpp @@ -0,0 +1,39 @@ +// include/beman/execution/detail/is_completion_query.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_IS_COMPLETION_QUERY +#define INCLUDED_BEMAN_EXECUTION_DETAIL_IS_COMPLETION_QUERY + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_completion_scheduler; +#else +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template +struct is_completion_query : ::std::false_type {}; + +template +struct is_completion_query<::beman::execution::get_completion_scheduler_t> : ::std::true_type {}; + +template +struct is_completion_query<::beman::execution::get_completion_domain_t> : ::std::true_type {}; + +template +inline constexpr bool is_completion_query_v = ::beman::execution::detail::is_completion_query::value; +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_IS_COMPLETION_QUERY diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index 3c5e8faa..20cdc329 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -27,6 +27,7 @@ import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_domain; import beman.execution.detail.get_env; import beman.execution.detail.get_start_scheduler; +import beman.execution.detail.is_completion_query; import beman.execution.detail.join_env; import beman.execution.detail.make_sender; import beman.execution.detail.product_type; @@ -54,6 +55,7 @@ import beman.execution.detail.transform_sender; #include #include #include +#include #include #include #include @@ -160,24 +162,15 @@ struct on_t : ::beman::execution::sender_adaptor_closure { } private: - template - struct is_completion_query : ::std::false_type {}; - - template - struct is_completion_query<::beman::execution::get_completion_scheduler_t> : ::std::true_type {}; - - template - struct is_completion_query<::beman::execution::get_completion_domain_t> : ::std::true_type {}; - template struct attrs_base { template - requires(!is_completion_query<::std::remove_cvref_t>::value) && - requires(const ChildAttrs& child_attrs, Query query, Args&&... args) { - query(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); + requires(!::beman::execution::detail::is_completion_query_v) && + requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { + q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); } - auto query(Query query, Args&&... args) const noexcept { - return query(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); + auto query(Query q, Args&&... args) const noexcept { + return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); } ChildAttrs child_attrs; diff --git a/include/beman/execution/detail/parallel_scheduler.hpp b/include/beman/execution/detail/parallel_scheduler.hpp index c1d2e704..47f0e2a4 100644 --- a/include/beman/execution/detail/parallel_scheduler.hpp +++ b/include/beman/execution/detail/parallel_scheduler.hpp @@ -123,6 +123,11 @@ class parallel_scheduler { return {}; } + auto query(::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>) const noexcept + -> parallel_scheduler { + return *this; + } + auto schedule() const noexcept -> sender; private: diff --git a/include/beman/execution/detail/run_loop.hpp b/include/beman/execution/detail/run_loop.hpp index 06a9eab7..ebb50a10 100644 --- a/include/beman/execution/detail/run_loop.hpp +++ b/include/beman/execution/detail/run_loop.hpp @@ -56,6 +56,8 @@ class run_loop { run_loop* loop; template + requires ::std::same_as || + ::std::same_as auto query(const ::beman::execution::get_completion_scheduler_t&) const noexcept -> scheduler { return {this->loop}; } @@ -131,6 +133,13 @@ class run_loop { -> ::beman::execution::forward_progress_guarantee { return ::beman::execution::forward_progress_guarantee::parallel; } + + template + requires ::std::same_as || + ::std::same_as + auto query(::beman::execution::get_completion_scheduler_t) const noexcept -> scheduler { + return *this; + } }; enum class state : unsigned char { starting, running, finishing }; diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index de520929..6a186cb1 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -26,6 +26,7 @@ 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.is_completion_query; import beman.execution.detail.join_env; import beman.execution.detail.just; import beman.execution.detail.let; @@ -56,6 +57,7 @@ import beman.execution.detail.set_value; #include #include #include +#include #include #include #include @@ -115,15 +117,11 @@ struct starts_on_t { } template - auto query(::beman::execution::get_completion_scheduler_t, const Env&... env) const noexcept { - if constexpr (requires { - ::beman::execution::get_completion_scheduler(this->child_attrs, - this->wrap_env(env)...); - }) { - return ::beman::execution::get_completion_scheduler(this->child_attrs, this->wrap_env(env)...); - } else { - return this->sch; + requires requires(const attrs& self, const ChildAttrs& child_attrs, const Env&... env) { + ::beman::execution::get_completion_scheduler(child_attrs, self.wrap_env(env)...); } + auto query(::beman::execution::get_completion_scheduler_t, const Env&... env) const noexcept { + return ::beman::execution::get_completion_scheduler(this->child_attrs, this->wrap_env(env)...); } template @@ -133,12 +131,13 @@ struct starts_on_t { return {}; } - template - requires requires(const Tag& tag, const ChildAttrs& child_attrs, Env&&... env) { - tag(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(env)...); - } - auto query(Tag tag, Env&&... env) const noexcept { - return tag(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(env)...); + template + requires(!::beman::execution::detail::is_completion_query_v) && + requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { + q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); + } + auto query(Query q, Args&&... args) const noexcept { + return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); } Scheduler sch; diff --git a/include/beman/execution/detail/task_scheduler.hpp b/include/beman/execution/detail/task_scheduler.hpp index 1ac636ca..504933c8 100644 --- a/include/beman/execution/detail/task_scheduler.hpp +++ b/include/beman/execution/detail/task_scheduler.hpp @@ -359,6 +359,11 @@ class task_scheduler { return domain{}; } + auto query(::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>) const noexcept + -> ::beman::execution::task_scheduler { + return *this; + } + friend auto operator==(const task_scheduler& lhs, const task_scheduler& rhs) noexcept -> bool { if (lhs.backend_ == nullptr) { return rhs.backend_ == nullptr; diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 51cec4b2..7a0368f5 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -127,6 +127,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/intrusive_stack.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_awaitable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_awaiter.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_completion_query.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_constant.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/join_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/just.hpp @@ -360,6 +361,7 @@ if(BEMAN_USE_MODULES) intrusive_stack.cppm is_awaitable.cppm is_awaiter.cppm + is_completion_query.cppm is_constant.cppm is_sender.cppm join_env.cppm diff --git a/src/beman/execution/is_completion_query.cppm b/src/beman/execution/is_completion_query.cppm new file mode 100644 index 00000000..3810556a --- /dev/null +++ b/src/beman/execution/is_completion_query.cppm @@ -0,0 +1,12 @@ +module; +// src/beman/execution/is_completion_query.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.is_completion_query; + +namespace beman::execution::detail { +export using beman::execution::detail::is_completion_query; +export using beman::execution::detail::is_completion_query_v; +} // namespace beman::execution::detail diff --git a/tests/beman/execution/exec-run-loop-types.test.cpp b/tests/beman/execution/exec-run-loop-types.test.cpp index cced0e8e..85d91ba1 100644 --- a/tests/beman/execution/exec-run-loop-types.test.cpp +++ b/tests/beman/execution/exec-run-loop-types.test.cpp @@ -118,14 +118,13 @@ TEST(exec_run_loop_types) { }); // p7.2: auto e{test_std::get_env(sender)}; + static_assert(not std::invocable, decltype(e)>); static_assert(requires { - { test_std::get_completion_scheduler(e) } noexcept -> std::same_as; { test_std::get_completion_scheduler(e) } noexcept -> std::same_as; { test_std::get_completion_scheduler(e) } noexcept -> std::same_as; }); - ASSERT(scheduler == test_std::get_completion_scheduler(e)); ASSERT(scheduler == test_std::get_completion_scheduler(e)); ASSERT(scheduler == test_std::get_completion_scheduler(e)); diff --git a/tests/beman/execution/exec-starts-on.test.cpp b/tests/beman/execution/exec-starts-on.test.cpp index a2cd6baa..946a8d4b 100644 --- a/tests/beman/execution/exec-starts-on.test.cpp +++ b/tests/beman/execution/exec-starts-on.test.cpp @@ -114,16 +114,6 @@ auto test_starts_on_start_scheduler() { static_assert(std::same_as); } -auto test_starts_on_attrs() { - using starts_on_sender = decltype(test_std::starts_on(scheduler{}, sender{})); - using attrs = decltype(test_std::get_env(std::declval())); - - static_assert(not has_start_scheduler_query); - static_assert( - std::same_as(std::declval())), - scheduler>); -} - auto test_starts_on_attributes() { test_std::run_loop loop; test::sender_env s{42}; @@ -148,7 +138,6 @@ TEST(exec_starts_on) { test_use(scheduler{}, sender{}); test_starts_on_completions(); - test_starts_on_attrs(); test_starts_on_start_scheduler(); test_starts_on_attributes(); } From 90a511ba75abf3329d3bbee0b4ccb70e5944bc57 Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Tue, 27 Oct 2026 21:08:33 +0800 Subject: [PATCH 2/5] Reduce redundant code and improve `affine` attributes --- include/beman/execution/detail/affine.hpp | 62 +++++++++++++++++++ .../beman/execution/detail/continues_on.hpp | 27 ++++---- .../detail/hide_completion_queries.hpp | 53 ++++++++++++++++ .../execution/detail/is_completion_query.hpp | 39 ------------ include/beman/execution/detail/let.hpp | 11 ++++ include/beman/execution/detail/on.hpp | 28 +++------ include/beman/execution/detail/starts_on.hpp | 31 +++++----- src/beman/execution/CMakeLists.txt | 4 +- .../execution/hide_completion_queries.cppm | 11 ++++ src/beman/execution/is_completion_query.cppm | 12 ---- tests/beman/execution/exec-affine.test.cpp | 12 ++++ 11 files changed, 186 insertions(+), 104 deletions(-) create mode 100644 include/beman/execution/detail/hide_completion_queries.hpp delete mode 100644 include/beman/execution/detail/is_completion_query.hpp create mode 100644 src/beman/execution/hide_completion_queries.cppm delete mode 100644 src/beman/execution/is_completion_query.cppm diff --git a/include/beman/execution/detail/affine.hpp b/include/beman/execution/detail/affine.hpp index 80d48725..45080b10 100644 --- a/include/beman/execution/detail/affine.hpp +++ b/include/beman/execution/detail/affine.hpp @@ -16,10 +16,16 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.basic_sender; import beman.execution.detail.continues_on; +import beman.execution.detail.default_impls; import beman.execution.detail.env; import beman.execution.detail.forward_like; +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.get_start_scheduler; +import beman.execution.detail.hide_completion_queries; +import beman.execution.detail.hide_sched; import beman.execution.detail.infallible_scheduler; import beman.execution.detail.make_sender; import beman.execution.detail.nested_sender_has_affine; @@ -36,8 +42,12 @@ import beman.execution.detail.unstoppable_scheduler; #include #include #include +#include +#include #include #include +#include +#include #include #include #include @@ -120,6 +130,47 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::detail::unstoppable_scheduler{::beman::execution::get_start_scheduler(env)}); } } + + private: + template + struct attrs : ::beman::execution::detail::hide_completion_queries { + using base = ::beman::execution::detail::hide_completion_queries; + + using base::query; + + template + requires ::std::invocable<::beman::execution::get_start_scheduler_t, Env> && + ::beman::execution::detail::infallible_scheduler< + ::std::invoke_result_t<::beman::execution::get_start_scheduler_t, Env>, + Env> && + requires { + ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::beman::execution::get_start_scheduler(::std::declval()), + ::beman::execution::detail::hide_sched(::std::declval())); + } + static auto query(::beman::execution::get_completion_scheduler_t, const Env& env) noexcept { + auto sch = ::beman::execution::get_start_scheduler(env); + return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + sch, ::beman::execution::detail::hide_sched(env)); + } + + template + requires ::std::invocable<::beman::execution::get_start_scheduler_t, Env> && + ::beman::execution::detail::infallible_scheduler< + ::std::invoke_result_t<::beman::execution::get_start_scheduler_t, Env>, + Env> && + requires { + ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( + ::beman::execution::get_start_scheduler(::std::declval()), + ::beman::execution::detail::hide_sched(::std::declval())); + } + static auto query(::beman::execution::get_completion_domain_t, const Env& env) noexcept { + auto sch = ::beman::execution::get_start_scheduler(env); + return ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( + sch, ::beman::execution::detail::hide_sched(env)); + } + }; + template struct get_signatures; @@ -144,10 +195,21 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { static consteval auto get() { return ::beman::execution::get_completion_signatures(); } }; + public: template static consteval auto get_completion_signatures() { return get_signatures<::std::remove_cvref_t, Env...>::get(); } + + struct impls_for : ::beman::execution::detail::default_impls { + struct get_attrs_impl { + auto operator()(const auto&, const auto& child) const noexcept { + using ChildAttrs = ::std::remove_cvref_t; + return attrs{::beman::execution::get_env(child)}; + } + }; + static constexpr auto get_attrs{get_attrs_impl{}}; + }; }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index b4f74adb..a7730acb 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -35,9 +35,9 @@ 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.hide_completion_queries; import beman.execution.detail.hide_sched; import beman.execution.detail.impls_for; -import beman.execution.detail.is_completion_query; import beman.execution.detail.join_env; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -74,9 +74,9 @@ import beman.execution.detail.start; #include #include #include +#include #include #include -#include #include #include #include @@ -160,7 +160,12 @@ struct continues_on_t { }; template - struct attrs { + struct attrs : ::beman::execution::detail::hide_completion_queries { + using base = ::beman::execution::detail::hide_completion_queries; + + attrs(Scheduler sch, ChildAttrs child_attrs) noexcept + : base(::std::move(child_attrs)), sch(::std::move(sch)) {} + template auto wrap_env(const Env& env) const noexcept { using tag_t = ::std::conditional_t<::std::same_as, ::beman::execution::set_value_t, Tag>; @@ -174,6 +179,8 @@ struct continues_on_t { } } + using base::query; + template requires requires(const attrs& self, const Scheduler& scheduler, const Env&... env) { ::beman::execution::get_completion_scheduler(scheduler, self.template wrap_env(env)...); @@ -190,17 +197,7 @@ struct continues_on_t { return ::beman::execution::get_completion_domain(this->sch, this->template wrap_env(env)...); } - template - requires(!::beman::execution::detail::is_completion_query_v) && - requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { - q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); - } - auto query(Query q, Args&&... args) const noexcept { - return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); - } - - Scheduler sch; - ChildAttrs child_attrs; + Scheduler sch; }; public: @@ -291,7 +288,7 @@ struct continues_on_t { ::beman::execution::env_of_t>; return state_type(sch, receiver); - }; + } }; static constexpr auto get_state{get_state_impl{}}; diff --git a/include/beman/execution/detail/hide_completion_queries.hpp b/include/beman/execution/detail/hide_completion_queries.hpp new file mode 100644 index 00000000..83c0be6e --- /dev/null +++ b/include/beman/execution/detail/hide_completion_queries.hpp @@ -0,0 +1,53 @@ +// include/beman/execution/detail/hide_completion_queries.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_COMPLETION_QUERIES +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_COMPLETION_QUERIES + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.fwd_env; +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_completion_scheduler; +#else +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template +struct is_completion_query : ::std::false_type {}; + +template +struct is_completion_query<::beman::execution::get_completion_scheduler_t> : ::std::true_type {}; + +template +struct is_completion_query<::beman::execution::get_completion_domain_t> : ::std::true_type {}; + +template +struct hide_completion_queries { + template + requires(!::beman::execution::detail::is_completion_query::value) && + requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { + q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); + } + auto query(Query q, Args&&... args) const noexcept { + return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); + } + + ChildAttrs child_attrs; +}; +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_COMPLETION_QUERIES diff --git a/include/beman/execution/detail/is_completion_query.hpp b/include/beman/execution/detail/is_completion_query.hpp deleted file mode 100644 index 45be41b9..00000000 --- a/include/beman/execution/detail/is_completion_query.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// include/beman/execution/detail/is_completion_query.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_IS_COMPLETION_QUERY -#define INCLUDED_BEMAN_EXECUTION_DETAIL_IS_COMPLETION_QUERY - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.get_completion_domain; -import beman.execution.detail.get_completion_scheduler; -#else -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -struct is_completion_query : ::std::false_type {}; - -template -struct is_completion_query<::beman::execution::get_completion_scheduler_t> : ::std::true_type {}; - -template -struct is_completion_query<::beman::execution::get_completion_domain_t> : ::std::true_type {}; - -template -inline constexpr bool is_completion_query_v = ::beman::execution::detail::is_completion_query::value; -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_IS_COMPLETION_QUERY diff --git a/include/beman/execution/detail/let.hpp b/include/beman/execution/detail/let.hpp index 36831ce2..89201ef8 100644 --- a/include/beman/execution/detail/let.hpp +++ b/include/beman/execution/detail/let.hpp @@ -37,6 +37,7 @@ 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; +import beman.execution.detail.hide_completion_queries; import beman.execution.detail.impls_for; import beman.execution.detail.join_env; import beman.execution.detail.make_env; @@ -71,6 +72,7 @@ import beman.execution.detail.type_list; #include #include #include +#include #include #include #include @@ -311,6 +313,15 @@ struct let_t { {}}; }}; + struct get_attrs_impl { + auto operator()(const auto&, const auto& child) const noexcept { + using ChildAttrs = ::std::remove_cvref_t; + return ::beman::execution::detail::hide_completion_queries{ + ::beman::execution::get_env(child)}; + } + }; + static constexpr auto get_attrs{get_attrs_impl{}}; + template static constexpr bool nothrow = ::std::is_nothrow_constructible_v<::beman::execution::detail::decayed_tuple, Args...> && diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index 20cdc329..d169f51b 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -27,7 +27,7 @@ import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_domain; import beman.execution.detail.get_env; import beman.execution.detail.get_start_scheduler; -import beman.execution.detail.is_completion_query; +import beman.execution.detail.hide_completion_queries; import beman.execution.detail.join_env; import beman.execution.detail.make_sender; import beman.execution.detail.product_type; @@ -55,7 +55,7 @@ import beman.execution.detail.transform_sender; #include #include #include -#include +#include #include #include #include @@ -163,22 +163,10 @@ struct on_t : ::beman::execution::sender_adaptor_closure { private: template - struct attrs_base { - template - requires(!::beman::execution::detail::is_completion_query_v) && - requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { - q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); - } - auto query(Query q, Args&&... args) const noexcept { - return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); - } + struct attrs1 : ::beman::execution::detail::hide_completion_queries { + using base = ::beman::execution::detail::hide_completion_queries; - ChildAttrs child_attrs; - }; - - template - struct attrs1 : attrs_base { - using attrs_base::query; + using base::query; template requires requires(const Env& env) { @@ -202,8 +190,8 @@ struct on_t : ::beman::execution::sender_adaptor_closure { }; template - struct attrs2 : attrs_base { - using attrs_base::query; + struct attrs2 : ::beman::execution::detail::hide_completion_queries { + using base = ::beman::execution::detail::hide_completion_queries; template auto original_sched(const Env& env) const noexcept { @@ -211,6 +199,8 @@ struct on_t : ::beman::execution::sender_adaptor_closure { env); } + using base::query; + template requires requires(const attrs2& self, const Env& env) { ::beman::execution::get_completion_scheduler(self.original_sched(env), diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index 6a186cb1..29717345 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -26,7 +26,7 @@ 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.is_completion_query; +import beman.execution.detail.hide_completion_queries; import beman.execution.detail.join_env; import beman.execution.detail.just; import beman.execution.detail.let; @@ -57,7 +57,7 @@ import beman.execution.detail.set_value; #include #include #include -#include +#include #include #include #include @@ -110,12 +110,19 @@ struct starts_on_t { }; template - struct attrs { + struct attrs : ::beman::execution::detail::hide_completion_queries { + using base = ::beman::execution::detail::hide_completion_queries; + + attrs(Scheduler sch, ChildAttrs child_attrs) noexcept + : base(::std::move(child_attrs)), sch(::std::move(sch)) {} + template auto wrap_env(const Env& env) const noexcept { return ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(this->sch), env); } + using base::query; + template requires requires(const attrs& self, const ChildAttrs& child_attrs, const Env&... env) { ::beman::execution::get_completion_scheduler(child_attrs, self.wrap_env(env)...); @@ -131,17 +138,7 @@ struct starts_on_t { return {}; } - template - requires(!::beman::execution::detail::is_completion_query_v) && - requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { - q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); - } - auto query(Query q, Args&&... args) const noexcept { - return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); - } - - Scheduler sch; - ChildAttrs child_attrs; + Scheduler sch; }; public: @@ -153,9 +150,9 @@ struct starts_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 ChildEnv = ::std::remove_cvref_t; - return attrs{sch, ::beman::execution::get_env(child)}; + 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{}}; diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 7a0368f5..9917f9de 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -112,6 +112,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_stop_token.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/has_as_awaitable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/has_completions.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/hide_completion_queries.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/hide_sched.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/immovable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/impls_for.hpp @@ -127,7 +128,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/intrusive_stack.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_awaitable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_awaiter.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_completion_query.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/is_constant.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/join_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/just.hpp @@ -346,6 +346,7 @@ if(BEMAN_USE_MODULES) get_stop_token.cppm has_as_awaitable.cppm has_completions.cppm + hide_completion_queries.cppm hide_sched.cppm immovable.cppm impls_for.cppm @@ -361,7 +362,6 @@ if(BEMAN_USE_MODULES) intrusive_stack.cppm is_awaitable.cppm is_awaiter.cppm - is_completion_query.cppm is_constant.cppm is_sender.cppm join_env.cppm diff --git a/src/beman/execution/hide_completion_queries.cppm b/src/beman/execution/hide_completion_queries.cppm new file mode 100644 index 00000000..3c11f736 --- /dev/null +++ b/src/beman/execution/hide_completion_queries.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/hide_completion_queries.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.hide_completion_queries; + +namespace beman::execution::detail { +export using beman::execution::detail::hide_completion_queries; +} // namespace beman::execution::detail diff --git a/src/beman/execution/is_completion_query.cppm b/src/beman/execution/is_completion_query.cppm deleted file mode 100644 index 3810556a..00000000 --- a/src/beman/execution/is_completion_query.cppm +++ /dev/null @@ -1,12 +0,0 @@ -module; -// src/beman/execution/is_completion_query.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.is_completion_query; - -namespace beman::execution::detail { -export using beman::execution::detail::is_completion_query; -export using beman::execution::detail::is_completion_query_v; -} // namespace beman::execution::detail diff --git a/tests/beman/execution/exec-affine.test.cpp b/tests/beman/execution/exec-affine.test.cpp index 0d28223d..bf8e89f2 100644 --- a/tests/beman/execution/exec-affine.test.cpp +++ b/tests/beman/execution/exec-affine.test.cpp @@ -29,6 +29,7 @@ import beman.execution; #include #include #include +#include #include #include #include @@ -168,6 +169,17 @@ auto test_affine_attributes() { test::test_sender_env(84, test::test_non_forwardable_attr{}, s); test::test_sender_env(42, test::test_forwardable_attr{}, test_std::affine(s)); test::test_sender_env(84, test::test_non_forwardable_attr{}, test_std::affine(s)); + + test_std::run_loop loop; + test_std::prop env{test_std::get_start_scheduler, test_std::task_scheduler(loop.get_scheduler())}; + auto sndr = s | test_std::affine(); + auto sch = test_std::get_completion_scheduler(test_std::get_env(sndr), env); + + static_assert(std::same_as); + ASSERT(sch == loop.get_scheduler()); + + using domain = decltype(test_std::get_completion_domain<>(test_std::get_env(sndr), env)); + static_assert(std::same_as); } } // namespace From da4d3a6ce2e6f9814b70c91664668a35cf11034b Mon Sep 17 00:00:00 2001 From: Cra3z Date: Wed, 28 Oct 2026 09:47:42 +0800 Subject: [PATCH 3/5] Make MSVC happy --- include/beman/execution/detail/affine.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/beman/execution/detail/affine.hpp b/include/beman/execution/detail/affine.hpp index 45080b10..66909cf0 100644 --- a/include/beman/execution/detail/affine.hpp +++ b/include/beman/execution/detail/affine.hpp @@ -148,7 +148,7 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::get_start_scheduler(::std::declval()), ::beman::execution::detail::hide_sched(::std::declval())); } - static auto query(::beman::execution::get_completion_scheduler_t, const Env& env) noexcept { + auto query(::beman::execution::get_completion_scheduler_t, const Env& env) const noexcept { auto sch = ::beman::execution::get_start_scheduler(env); return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( sch, ::beman::execution::detail::hide_sched(env)); @@ -164,7 +164,7 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::get_start_scheduler(::std::declval()), ::beman::execution::detail::hide_sched(::std::declval())); } - static auto query(::beman::execution::get_completion_domain_t, const Env& env) noexcept { + auto query(::beman::execution::get_completion_domain_t, const Env& env) const noexcept { auto sch = ::beman::execution::get_start_scheduler(env); return ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( sch, ::beman::execution::detail::hide_sched(env)); From fda6615843357e3f11c13f3a7cc0cc335897c473 Mon Sep 17 00:00:00 2001 From: Cra3z Date: Wed, 28 Oct 2026 11:48:58 +0800 Subject: [PATCH 4/5] Fix `sender_in` propagation --- include/beman/execution/detail/affine.hpp | 70 +++------ .../beman/execution/detail/continues_on.hpp | 136 +++++++++++------- .../detail/hide_completion_queries.hpp | 6 +- .../beman/execution/detail/into_variant.hpp | 13 +- include/beman/execution/detail/let.hpp | 55 ++++--- include/beman/execution/detail/on.hpp | 49 ------- include/beman/execution/detail/run_loop.hpp | 17 +-- include/beman/execution/detail/sends.hpp | 43 ++++++ .../beman/execution/detail/sends_stopped.hpp | 16 +-- include/beman/execution/detail/starts_on.hpp | 13 ++ include/beman/execution/detail/then.hpp | 33 +++-- include/beman/execution/detail/when_all.hpp | 2 + .../detail/when_all_with_variant.hpp | 4 + include/beman/execution/detail/write_env.hpp | 30 ++-- src/beman/execution/CMakeLists.txt | 2 + src/beman/execution/sends.cppm | 11 ++ src/beman/execution/when_all.cppm | 4 + tests/beman/execution/exec-let.test.cpp | 21 ++- .../execution/exec-run-loop-types.test.cpp | 11 +- .../execution/exec-snd-concepts.test.cpp | 30 ++-- 20 files changed, 325 insertions(+), 241 deletions(-) create mode 100644 include/beman/execution/detail/sends.hpp create mode 100644 src/beman/execution/sends.cppm diff --git a/include/beman/execution/detail/affine.hpp b/include/beman/execution/detail/affine.hpp index 66909cf0..f6f1a138 100644 --- a/include/beman/execution/detail/affine.hpp +++ b/include/beman/execution/detail/affine.hpp @@ -18,6 +18,7 @@ import beman.execution.detail.basic_sender; import beman.execution.detail.continues_on; import beman.execution.detail.default_impls; import beman.execution.detail.env; +import beman.execution.detail.env_of_t; import beman.execution.detail.forward_like; import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_completion_scheduler; @@ -34,6 +35,8 @@ import beman.execution.detail.scheduler; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; +import beman.execution.detail.sender_in; +import beman.execution.detail.sends; import beman.execution.detail.set_value; import beman.execution.detail.store_receiver; import beman.execution.detail.unstoppable_scheduler; @@ -41,6 +44,7 @@ import beman.execution.detail.unstoppable_scheduler; #include #include #include +#include #include #include #include @@ -56,6 +60,8 @@ import beman.execution.detail.unstoppable_scheduler; #include #include #include +#include +#include #include #include #include @@ -112,19 +118,14 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { * @return A transformed sender that is affined to the scheduler. */ template <::beman::execution::detail::sender_for Sender, typename Env> + requires ::beman::execution::detail::nested_sender_has_affine || + ::beman::execution::detail:: + infallible_scheduler<::std::invoke_result_t<::beman::execution::get_start_scheduler_t, Env>, Env> static auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env& env) { auto& child = sender.template get<2>(); if constexpr (::beman::execution::detail::nested_sender_has_affine) { return ::beman::execution::detail::forward_like(child).affine(); } else { - static_assert( - requires { - { - ::beman::execution::get_start_scheduler(::std::declval()) - } -> ::beman::execution::detail::infallible_scheduler; - }, - "the result type of querying `get_start_scheduler` on an `Env` shall be a scheduler type whose " - "schedule asynchronous operation can only complete with set_value unless stop can be requested"); return ::beman::execution::continues_on( ::beman::execution::detail::forward_like(child), ::beman::execution::detail::unstoppable_scheduler{::beman::execution::get_start_scheduler(env)}); @@ -132,17 +133,14 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { } private: - template - struct attrs : ::beman::execution::detail::hide_completion_queries { - using base = ::beman::execution::detail::hide_completion_queries; + template + struct attrs : ::beman::execution::detail::hide_completion_queries<::beman::execution::env_of_t> { + using base = ::beman::execution::detail::hide_completion_queries<::beman::execution::env_of_t>; using base::query; template - requires ::std::invocable<::beman::execution::get_start_scheduler_t, Env> && - ::beman::execution::detail::infallible_scheduler< - ::std::invoke_result_t<::beman::execution::get_start_scheduler_t, Env>, - Env> && + requires ::beman::execution::sender_in && ::beman::execution::detail::sends && requires { ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( ::beman::execution::get_start_scheduler(::std::declval()), @@ -155,11 +153,8 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { } template - requires ::std::invocable<::beman::execution::get_start_scheduler_t, Env> && - ::beman::execution::detail::infallible_scheduler< - ::std::invoke_result_t<::beman::execution::get_start_scheduler_t, Env>, - Env> && - requires { + requires ::beman::execution::sender_in && + (::std::same_as || ::beman::execution::detail::sends) && requires { ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( ::beman::execution::get_start_scheduler(::std::declval()), ::beman::execution::detail::hide_sched(::std::declval())); @@ -171,41 +166,12 @@ struct affine_t : ::beman::execution::sender_adaptor_closure { } }; - template - struct get_signatures; - - template - struct get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::affine_t, Data, Child>, - Env> { - static consteval auto get() { - if constexpr (!requires { - { - ::beman::execution::get_start_scheduler(::std::declval()) - } -> ::beman::execution::detail::infallible_scheduler; - }) { - throw ::beman::execution::detail::infallible_scheduler_error{}; - } - return ::beman::execution::get_completion_signatures(); - } - }; - - template - struct get_signatures< - ::beman::execution::detail::basic_sender<::beman::execution::detail::affine_t, Data, Child>> { - static consteval auto get() { return ::beman::execution::get_completion_signatures(); } - }; - public: - template - static consteval auto get_completion_signatures() { - return get_signatures<::std::remove_cvref_t, Env...>::get(); - } - struct impls_for : ::beman::execution::detail::default_impls { struct get_attrs_impl { - auto operator()(const auto&, const auto& child) const noexcept { - using ChildAttrs = ::std::remove_cvref_t; - return attrs{::beman::execution::get_env(child)}; + template + auto operator()(const auto&, const Child& child) const noexcept { + return attrs{::beman::execution::get_env(child)}; } }; static constexpr auto get_attrs{get_attrs_impl{}}; diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index a7730acb..65975503 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -120,41 +120,74 @@ struct continues_on_t { } private: + template + using is_not_set_value = ::std::negation<::beman::execution::detail::is_set_value>; + + template + struct is_nothrow_decay_copy_sig; + + template + struct is_nothrow_decay_copy_sig + : ::std::conjunction<::std::is_nothrow_constructible<::std::decay_t, Args>...> {}; + + template + struct is_nothrow_decay_copy_compl_sigs; + + template + struct is_nothrow_decay_copy_compl_sigs<::beman::execution::completion_signatures> + : ::std::conjunction...> {}; + + template + struct decay_sig; + + template + struct decay_sig { + using type = Tag(::std::decay_t...); + }; + + template + using decay_sig_t = typename decay_sig::type; + template using variant_type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend< ::std::monostate, ::beman::execution::detail::meta::transform< ::beman::execution::detail::as_tuple_t, - ::beman::execution::detail::meta::to<::std::variant, - ::beman::execution::completion_signatures_of_t>>>>; - - template - using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; - - template - using is_not_set_value = ::std::negation<::beman::execution::detail::is_set_value>; + ::beman::execution::detail::meta::to< + ::std::variant, + ::beman::execution::detail::meta::combine< + ::beman::execution::completion_signatures_of_t, + ::std::conditional_t>::value, + ::beman::execution::completion_signatures<>, + ::beman::execution::completion_signatures<::beman::execution::set_error_t( + ::std::exception_ptr)>>>>>>>; template struct get_signatures; template struct get_signatures : get_signatures> {}; template + requires ::beman::execution::sender_in> struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, Scheduler, Sender>, Env> { - using exception_signature = ::std::conditional_t< - ::std::is_nothrow_move_constructible_v>, - ::beman::execution::completion_signatures<>, - ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; - static consteval auto get() { - [[maybe_unused]] auto child_sigs = ::beman::execution::get_completion_signatures(); + using env_t = ::beman::execution::detail::fwd_env_t; + [[maybe_unused]] auto child_sigs = ::beman::execution::get_completion_signatures(); [[maybe_unused]] auto sched_sigs = - ::beman::execution::get_completion_signatures<::beman::execution::schedule_result_t, Env>(); - using child_sigs_t = decltype(child_sigs); - using extra_sigs_t = ::beman::execution::detail::meta::filter; - using type = ::beman::execution::detail::meta::unique< - ::beman::execution::detail::meta::combine>; + ::beman::execution::get_completion_signatures<::beman::execution::schedule_result_t, + env_t>(); + using child_sigs_t = decltype(child_sigs); + using extra_sigs_t = ::beman::execution::detail::meta::filter; + using error_completion = ::std::conditional_t< + is_nothrow_decay_copy_compl_sigs::value, + ::beman::execution::completion_signatures<>, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine< + ::beman::execution::detail::meta::transform, + error_completion, + extra_sigs_t>>; return type{}; } }; @@ -202,6 +235,7 @@ struct continues_on_t { public: template + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { return get_signatures<::std::remove_cvref_t, Env...>::get(); } @@ -222,24 +256,17 @@ struct continues_on_t { State* state; auto set_value() && noexcept -> void { - constexpr bool nothrow = ::std::is_nothrow_move_constructible_vasync_result)>; - try { - ::std::visit( - [this](Tuple& result) noexcept -> void { - if constexpr (!::std::same_as<::std::monostate, Tuple>) { - ::std::apply( - [this](auto&& tag, auto&&... args) { - tag(::std::move(this->state->receiver), ::std::move(args)...); - }, - result); - } - }, - state->async_result); - } catch (...) { - if constexpr (!nothrow) { - ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception()); - } - } + ::std::visit( + [this](Tuple& result) noexcept -> void { + if constexpr (!::std::same_as<::std::monostate, Tuple>) { + ::std::apply( + [this](auto&& tag, auto&&... args) { + tag(::std::move(this->state->receiver), ::std::move(args)...); + }, + result); + } + }, + state->async_result); } template @@ -256,19 +283,19 @@ struct continues_on_t { template struct state_base { - Receiver receiver; - Variant async_result{}; + Receiver& receiver; + Variant async_result{}; }; template struct state_type : state_base { using receiver_t = upstream_receiver>; using operation_t = - ::beman::execution::connect_result_t<::beman::execution::schedule_result_t, receiver_t>; + ::beman::execution::connect_result_t<::beman::execution::schedule_result_t, receiver_t>; operation_t op_state; static constexpr bool nothrow() { - return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval()), + return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval()), receiver_t{nullptr})); } explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow()) @@ -278,14 +305,16 @@ struct continues_on_t { struct get_state_impl { template - requires ::beman::execution::sender_in<::beman::execution::detail::child_type, - ::beman::execution::env_of_t> + requires ::beman::execution::sender_in< + ::beman::execution::detail::child_type, + ::beman::execution::detail::fwd_env_t<::beman::execution::env_of_t>> auto operator()(Sender&& sender, Receiver& receiver) const { - auto sch{sender.template get<1>()}; + auto& sch = sender.template get<1>(); - using sched_t = ::std::remove_cvref_t; - using variant_t = variant_type<::beman::execution::detail::child_type, - ::beman::execution::env_of_t>; + using sched_t = ::std::remove_reference_t; + using variant_t = + variant_type<::beman::execution::detail::child_type, + ::beman::execution::detail::fwd_env_t<::beman::execution::env_of_t>>; return state_type(sch, receiver); } @@ -294,23 +323,22 @@ struct continues_on_t { struct complete_impl { template - auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const noexcept -> void { + auto operator()(auto, auto& state, auto&, Tag, Args&&... args) const noexcept -> void { using result_t = ::beman::execution::detail::decayed_tuple; - constexpr bool nothrow = ::std::is_nothrow_move_constructible_v; + constexpr bool nothrow = (::std::is_nothrow_constructible_v<::std::decay_t, Args> && ...); try { [&]() noexcept(nothrow) { - state.async_result.template emplace(Tag(), std::forward(args)...); + state.async_result.template emplace(Tag(), ::std::forward(args)...); }(); } catch (...) { if constexpr (!nothrow) { - ::beman::execution::set_error(::std::move(receiver), ::std::current_exception()); + state.async_result + .template emplace<::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>>( + ::beman::execution::set_error, ::std::current_exception()); } } - if (state.async_result.index() == 0) - return; - ::beman::execution::start(state.op_state); } }; diff --git a/include/beman/execution/detail/hide_completion_queries.hpp b/include/beman/execution/detail/hide_completion_queries.hpp index 83c0be6e..ba12bb62 100644 --- a/include/beman/execution/detail/hide_completion_queries.hpp +++ b/include/beman/execution/detail/hide_completion_queries.hpp @@ -38,13 +38,13 @@ struct hide_completion_queries { template requires(!::beman::execution::detail::is_completion_query::value) && requires(const Query& q, const ChildAttrs& child_attrs, Args&&... args) { - q(::beman::execution::detail::fwd_env(child_attrs), ::std::forward(args)...); + ::beman::execution::detail::fwd_env(child_attrs).query(q, ::std::forward(args)...); } auto query(Query q, Args&&... args) const noexcept { - return q(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward(args)...); + return ::beman::execution::detail::fwd_env(child_attrs).query(q, ::std::forward(args)...); } - ChildAttrs child_attrs; + ::std::remove_cvref_t child_attrs; }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/into_variant.hpp b/include/beman/execution/detail/into_variant.hpp index 2a73285c..bbd5874b 100644 --- a/include/beman/execution/detail/into_variant.hpp +++ b/include/beman/execution/detail/into_variant.hpp @@ -25,11 +25,13 @@ import beman.execution.detail.dependent_sender_error; 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.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; +import beman.execution.detail.sender_in; import beman.execution.detail.sends_stopped; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; @@ -46,11 +48,13 @@ import beman.execution.detail.variant_or_empty; #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -78,20 +82,22 @@ struct into_variant_t : ::beman::execution::sender_adaptor_closure struct get_signatures : get_signatures> {}; template <::beman::execution::sender Child, typename State, typename Env> + requires ::beman::execution::sender_in> struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::into_variant_t, State, Child>, Env> { static consteval auto get() { - using variant_type = ::beman::execution::value_types_of_t; + using env_t = ::beman::execution::detail::fwd_env_t; + using variant_type = ::beman::execution::value_types_of_t; using value_types = ::std::conditional_t< ::std::same_as, ::beman::execution::completion_signatures<>, ::beman::execution::completion_signatures<::beman::execution::set_value_t(variant_type)>>; - using error_types = ::beman::execution::error_types_of_t; + using error_types = ::beman::execution::error_types_of_t; using stopped_types = - ::std::conditional_t<::beman::execution::sends_stopped, + ::std::conditional_t<::beman::execution::sends_stopped, ::beman::execution::completion_signatures<::beman::execution::set_stopped_t()>, ::beman::execution::completion_signatures<>>; using type = ::beman::execution::detail::meta:: @@ -102,6 +108,7 @@ struct into_variant_t : ::beman::execution::sender_adaptor_closure + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { return get_signatures<::std::remove_cvref_t, Env...>::get(); } diff --git a/include/beman/execution/detail/let.hpp b/include/beman/execution/detail/let.hpp index 89201ef8..1502e118 100644 --- a/include/beman/execution/detail/let.hpp +++ b/include/beman/execution/detail/let.hpp @@ -53,6 +53,7 @@ import beman.execution.detail.receiver; import beman.execution.detail.sched_env; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; +import beman.execution.detail.sender_in; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; @@ -87,6 +88,7 @@ import beman.execution.detail.type_list; #include #include #include +#include #include #include #include @@ -112,7 +114,7 @@ struct get_successor_senders; template struct get_successor_senders> { - using type = std::invoke_result_t; + using type = std::invoke_result_t&...>; }; template @@ -125,13 +127,30 @@ struct non_dependent_successor_helper::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>> {}; +using 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 successor_in_helper; + +template +struct successor_in_helper> + : std::bool_constant<(... && ::beman::execution::sender_in< + typename ::beman::execution::detail::get_successor_senders::type, + Env>)> {}; + +template +using successor_in = ::beman::execution::detail::successor_in_helper< + Env, + Fun, + ::beman::execution::detail::gather_signatures, + ::beman::execution::detail::type_list, + ::beman::execution::detail::type_list>>; template struct let_t { @@ -192,6 +211,10 @@ struct let_t { template using matching_completion = let_matching_completion; + template + using successor_env = + ::beman::execution::detail::join_env, ::beman::execution::detail::fwd_env>; + template struct get_signatures; @@ -201,12 +224,11 @@ struct let_t { : get_signatures<::beman::execution::detail::basic_sender, ::beman::execution::env<>> {}; template + requires ::beman::execution::sender_in> && + ::beman::execution::detail::successor_in>::value struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::let_t, Fun, Child>, Env> { - using successor_env = - ::beman::execution::detail::join_env, ::beman::execution::detail::fwd_env>; - template struct get_completions; template @@ -214,12 +236,13 @@ struct let_t { using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine< ::beman::execution::completion_signatures<>, ::beman::execution::completion_signatures_of_t::sender_type, - successor_env>..., + successor_env>..., typename apply_decayed::completions...>>; }; - using upstream_completions = ::beman::execution::completion_signatures_of_t; - using other_completions = ::beman::execution::detail::meta::filter; + using upstream_completions = + ::beman::execution::completion_signatures_of_t>; + using other_completions = ::beman::execution::detail::meta::filter; using matching_completions = ::beman::execution::detail::meta::filter; using type = ::beman::execution::detail::meta::unique< @@ -231,9 +254,9 @@ struct let_t { public: template - requires requires { get_signatures, Env...>::get(); } + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { - return get_signatures, Env...>::get(); + return get_signatures<::std::remove_cvref_t, Env...>::get(); } struct impls_for : ::beman::execution::detail::default_impls { diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index d169f51b..f2091c69 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -221,55 +221,6 @@ struct on_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::detail::fwd_env(env)); } }; - - template - struct get_signatures; - - /// for `on(scheduler, sender)` - template - struct get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, Sched, Child>, - Env> { - static consteval auto get() - requires ::std::invocable<::beman::execution::get_start_scheduler_t, Env> - { - using transformed_sndr = decltype(on_t::transform_sender( - ::beman::execution::set_value, - ::std::declval< - ::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, Sched, Child>>(), - ::std::declval())); - return ::beman::execution::get_completion_signatures(); - } - }; - - /// for `on(sender, scheduler, closure)` - template - struct get_signatures< - ::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, - ::beman::execution::detail::product_type, - Child>, - Env> { - static consteval auto get() - requires ::std::invocable<::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>, - ::beman::execution::env_of_t, - Env> - { - using transformed_sndr = decltype(on_t::transform_sender( - ::beman::execution::set_value, - ::std::declval< - ::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, - ::beman::execution::detail::product_type, - Child>>(), - ::std::declval())); - return ::beman::execution::get_completion_signatures(); - } - }; - - public: - template - requires requires { get_signatures, Env>::get(); } - static consteval auto get_completion_signatures() noexcept { - return get_signatures, Env>::get(); - } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/run_loop.hpp b/include/beman/execution/detail/run_loop.hpp index ebb50a10..0c5c50ca 100644 --- a/include/beman/execution/detail/run_loop.hpp +++ b/include/beman/execution/detail/run_loop.hpp @@ -28,6 +28,7 @@ import beman.execution.detail.scheduler_tag; import beman.execution.detail.sender; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; +import beman.execution.detail.stop_token_of_t; import beman.execution.detail.unstoppable_token; #else #include @@ -42,6 +43,7 @@ import beman.execution.detail.unstoppable_token; #include #include #include +#include #include #endif @@ -93,20 +95,9 @@ class run_loop { }; struct sender { using sender_concept = ::beman::execution::sender_tag; - template + template static consteval auto get_completion_signatures() noexcept { - // [exec.getcomplsigs] permits sizeof...(Env) == 0. Answering that - // query as if for env<> matches [exec.run.loop]'s formula, whose - // E = env<> has an unstoppable stop token, and matches how the - // other environment-sensitive senders here (then, into_variant) - // handle the empty pack. Without this the member's body is - // ill-formed for an empty pack -- get_stop_token() with no - // argument -- and because the return type is deduced, that is a - // hard error rather than a substitution failure. - if constexpr (0u == sizeof...(Env)) - return get_completion_signatures>(); - else if constexpr (::beman::execution::unstoppable_token()...))>) + if constexpr (::beman::execution::unstoppable_token<::beman::execution::stop_token_of_t>) return ::beman::execution::completion_signatures<::beman::execution::set_value_t()>{}; else return ::beman::execution::completion_signatures<::beman::execution::set_value_t(), diff --git a/include/beman/execution/detail/sends.hpp b/include/beman/execution/detail/sends.hpp new file mode 100644 index 00000000..f813c85f --- /dev/null +++ b/include/beman/execution/detail/sends.hpp @@ -0,0 +1,43 @@ +// include/beman/execution/detail/sends.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SENDS +#define INCLUDED_BEMAN_EXECUTION_DETAIL_SENDS + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.completion_signatures_of_t; +import beman.execution.detail.completion_tag; +import beman.execution.detail.gather_signatures; +import beman.execution.detail.sender_in; +import beman.execution.detail.type_list; +#else +#include +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template + requires ::beman::execution::sender_in && ::beman::execution::detail::completion_tag +inline constexpr bool sends = + (!::std::same_as< + ::beman::execution::detail::type_list<>, + ::beman::execution::detail::gather_signatures, + ::beman::execution::detail::type_list, + ::beman::execution::detail::type_list>>); +} + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_SENDS diff --git a/include/beman/execution/detail/sends_stopped.hpp b/include/beman/execution/detail/sends_stopped.hpp index 22f712bd..52e76703 100644 --- a/include/beman/execution/detail/sends_stopped.hpp +++ b/include/beman/execution/detail/sends_stopped.hpp @@ -11,19 +11,15 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.completion_signatures_of_t; import beman.execution.detail.env; -import beman.execution.detail.gather_signatures; import beman.execution.detail.sender_in; +import beman.execution.detail.sends; import beman.execution.detail.set_stopped; -import beman.execution.detail.type_list; #else -#include #include -#include #include +#include #include -#include #endif // ---------------------------------------------------------------------------- @@ -31,12 +27,8 @@ import beman.execution.detail.type_list; namespace beman::execution { template > requires ::beman::execution::sender_in -inline constexpr bool sends_stopped{!::std::same_as< - ::beman::execution::detail::type_list<>, - ::beman::execution::detail::gather_signatures<::beman::execution::set_stopped_t, - ::beman::execution::completion_signatures_of_t, - ::beman::execution::detail::type_list, - ::beman::execution::detail::type_list>>}; +inline constexpr bool sends_stopped = + ::beman::execution::detail::sends<::beman::execution::set_stopped_t, Sender, Env>; } // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index 29717345..2e769db2 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -14,6 +14,7 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.basic_sender; +import beman.execution.detail.child_type; import beman.execution.detail.completion_signatures; import beman.execution.detail.completion_signatures_of_t; import beman.execution.detail.continues_on; @@ -39,6 +40,7 @@ import beman.execution.detail.schedule_result_t; import beman.execution.detail.scheduler; import beman.execution.detail.sender; import beman.execution.detail.sender_for; +import beman.execution.detail.sender_in; import beman.execution.detail.sends_stopped; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; @@ -68,6 +70,7 @@ import beman.execution.detail.set_value; #include #include #include +#include #include #include #include @@ -79,6 +82,8 @@ import beman.execution.detail.set_value; namespace beman::execution::detail { struct starts_on_t { template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename Env> + requires ::beman::execution::sender_in<::beman::execution::detail::child_type, + ::beman::execution::detail::fwd_env_t> static auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env&) noexcept { auto&& sched{sender.template get<1>()}; auto&& child{sender.template get<2>()}; @@ -96,6 +101,13 @@ struct starts_on_t { template struct get_signatures : get_signatures> {}; template + requires requires { + starts_on_t::transform_sender( + ::beman::execution::set_value, + ::std::declval<::beman::execution::detail:: + basic_sender<::beman::execution::detail::starts_on_t, Scheduler, Child>>(), + ::std::declval()); + } struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::starts_on_t, Scheduler, Child>, Env> { @@ -143,6 +155,7 @@ struct starts_on_t { public: template + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { return get_signatures<::std::remove_cvref_t, Env...>::get(); } diff --git a/include/beman/execution/detail/then.hpp b/include/beman/execution/detail/then.hpp index 5b59550c..2c6b99cb 100644 --- a/include/beman/execution/detail/then.hpp +++ b/include/beman/execution/detail/then.hpp @@ -24,6 +24,8 @@ import beman.execution.detail.default_impls; import beman.execution.detail.dependent_sender; import beman.execution.detail.dependent_sender_error; import beman.execution.detail.env; +import beman.execution.detail.fwd_env; +import beman.execution.detail.get_completion_signatures; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -33,6 +35,7 @@ import beman.execution.detail.movable_value; import beman.execution.detail.nested_sender_has_affine; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; +import beman.execution.detail.sender_in; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; @@ -46,6 +49,8 @@ import beman.execution.detail.transform_sender; #include #include #include +#include +#include #include #include #include @@ -56,6 +61,7 @@ import beman.execution.detail.transform_sender; #include #include #include +#include #include #include #include @@ -132,24 +138,31 @@ struct then_t : ::beman::execution::sender_adaptor_closure> { template struct get_signatures : get_signatures> {}; template + requires ::beman::execution::sender_in> struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::then_t, Fun, Child>, Env> { - using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine< - ::beman::execution::detail::meta::transform< - ::beman::execution::detail::then_transform_t::template transform, - ::beman::execution::completion_signatures_of_t>, - ::std::conditional_t< - ::beman::execution::detail:: - then_exception>::value, - ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>, - ::beman::execution::completion_signatures<>>>>; + static consteval auto get() { + [[maybe_unused]] auto child_sigs = + ::beman::execution::get_completion_signatures>(); + using child_sigs_t = decltype(child_sigs); + using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine< + ::beman::execution::detail::meta::transform< + ::beman::execution::detail::then_transform_t::template transform, + child_sigs_t>, + ::std::conditional_t< + ::beman::execution::detail::then_exception::value, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>, + ::beman::execution::completion_signatures<>>>>; + return type{}; + } }; public: template + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { - return typename get_signatures, Env...>::type{}; + return get_signatures<::std::remove_cvref_t, Env...>::get(); } struct impls_for : ::beman::execution::detail::default_impls { diff --git a/include/beman/execution/detail/when_all.hpp b/include/beman/execution/detail/when_all.hpp index 03c2ee1d..a0c36bb3 100644 --- a/include/beman/execution/detail/when_all.hpp +++ b/include/beman/execution/detail/when_all.hpp @@ -151,6 +151,7 @@ struct when_all_t { template struct get_signatures : get_signatures> {}; template + requires(... && ::beman::execution::sender_in>) struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::when_all_t, Data, Sender...>, Env> { @@ -220,6 +221,7 @@ struct when_all_t { public: template + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { return typename get_signatures, Env...>::type{}; } diff --git a/include/beman/execution/detail/when_all_with_variant.hpp b/include/beman/execution/detail/when_all_with_variant.hpp index ce6c3140..56730760 100644 --- a/include/beman/execution/detail/when_all_with_variant.hpp +++ b/include/beman/execution/detail/when_all_with_variant.hpp @@ -24,6 +24,7 @@ import beman.execution.detail.into_variant; import beman.execution.detail.make_sender; import beman.execution.detail.sender; import beman.execution.detail.sender_for; +import beman.execution.detail.sender_in; import beman.execution.detail.set_value; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; @@ -41,6 +42,7 @@ import beman.execution.detail.when_all; #include #include #include +#include #include #include #include @@ -70,6 +72,7 @@ struct when_all_with_variant_t { template struct get_signatures : get_signatures> {}; template + requires(... && ::beman::execution::sender_in>) struct get_signatures<::beman::execution::detail:: basic_sender<::beman::execution::detail::when_all_with_variant_t, Data, Children...>, Env> { @@ -128,6 +131,7 @@ struct when_all_with_variant_t { public: template <::beman::execution::sender Sender, typename... Env> + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { return get_signatures<::std::remove_cvref_t, Env...>::get(); } diff --git a/include/beman/execution/detail/write_env.hpp b/include/beman/execution/detail/write_env.hpp index eaafafdd..5190155c 100644 --- a/include/beman/execution/detail/write_env.hpp +++ b/include/beman/execution/detail/write_env.hpp @@ -24,6 +24,7 @@ import beman.execution.detail.make_sender; import beman.execution.detail.nested_sender_has_affine; import beman.execution.detail.queryable; import beman.execution.detail.sender; +import beman.execution.detail.sender_in; import beman.execution.detail.sender_adaptor_closure; #else #include @@ -34,6 +35,7 @@ import beman.execution.detail.sender_adaptor_closure; #include #include #include +#include #include #endif @@ -41,14 +43,19 @@ import beman.execution.detail.sender_adaptor_closure; namespace beman::execution::detail { -template -struct write_env_env_type { - using type = decltype(::beman::execution::detail::join_env(::std::declval(), ::std::declval()...)); -}; +template +struct write_env_env_type; + template -struct write_env_env_type { +struct write_env_env_type { using type = NewEnv; }; + +template +struct write_env_env_type { + using type = ::beman::execution::detail::join_env; +}; + struct write_env_t { template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env> constexpr auto operator()(Sender&& sender, Env&& env) const { @@ -71,18 +78,21 @@ struct write_env_t { template struct get_signatures; template + requires ::beman::execution::sender_in::type> struct get_signatures< ::beman::execution::detail::basic_sender<::beman::execution::detail::write_env_t, NewEnv, Child>, Env...> { - using type = decltype(::beman::execution::get_completion_signatures< - Child, - typename write_env_env_type::type>()); - }; + static consteval auto get() { + return ::beman::execution::get_completion_signatures::type>(); + } + }; // namespace beman::execution::detail public: template + requires requires { get_signatures<::std::remove_cvref_t, Env...>{}; } static consteval auto get_completion_signatures() { - return typename get_signatures, Env...>::type{}; + return get_signatures<::std::remove_cvref_t, Env...>::get(); } struct impls_for : ::beman::execution::detail::default_impls { diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 9917f9de..cb77cab7 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -188,6 +188,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sender_has_affine.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sender_in.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sender_to.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sends.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sends_stopped.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/set_error.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/set_stopped.hpp @@ -421,6 +422,7 @@ if(BEMAN_USE_MODULES) sender_in.cppm sender.cppm sender_to.cppm + sends.cppm sends_stopped.cppm set_error.cppm set_stopped.cppm diff --git a/src/beman/execution/sends.cppm b/src/beman/execution/sends.cppm new file mode 100644 index 00000000..d33b5c7c --- /dev/null +++ b/src/beman/execution/sends.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/sends.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.sends; + +namespace beman::execution::detail { +export using beman::execution::detail::sends; +} // namespace beman::execution::detail diff --git a/src/beman/execution/when_all.cppm b/src/beman/execution/when_all.cppm index cc2f500b..1224a189 100644 --- a/src/beman/execution/when_all.cppm +++ b/src/beman/execution/when_all.cppm @@ -6,6 +6,10 @@ module; export module beman.execution.detail.when_all; +namespace beman::execution::detail { +export using beman::execution::detail::when_all_env; +} // namespace beman::execution::detail + namespace beman::execution { export using beman::execution::when_all_t; export using beman::execution::when_all; diff --git a/tests/beman/execution/exec-let.test.cpp b/tests/beman/execution/exec-let.test.cpp index 2fb658a9..ae7d2b5e 100644 --- a/tests/beman/execution/exec-let.test.cpp +++ b/tests/beman/execution/exec-let.test.cpp @@ -12,6 +12,7 @@ import std; #include #include #include +#include #include #include #include @@ -85,6 +86,25 @@ auto test_let_value() { auto state1{test_std::connect(s1, receiver{})}; test::use(state1); test_std::start(state1); + + test_std::sync_wait(test_std::just(42) | test_std::let_value([](int& i) noexcept { + ASSERT(i == 42); + return test_std::just(std::ref(i)) | test_std::let_value([&i](int& j) noexcept { + ASSERT(&i == &j); + ASSERT(i == 42 && i == j); + return test_std::just(); + }); + })); + + auto [vec] = test_std::sync_wait(test_std::just(std::vector{1, 2, 3}) | + test_std::let_value([](std::vector& v) noexcept { + for (int& i : v) { + i *= 2; + } + return test_std::just(std::move(v)); + })) + .value(); + ASSERT((vec == std::vector{2, 4, 6})); } template @@ -120,7 +140,6 @@ auto test_let_value_allocator() -> void { auto s{ex::just(std::span(values)) | ex::let_value(fun()) | ex::then([](auto&&) noexcept {})}; static_assert(test_std::sender); static_assert(test_std::sender_in); - //-dk:TODO static_assert(std::same_as{}))>); ex::sync_wait(s); } diff --git a/tests/beman/execution/exec-run-loop-types.test.cpp b/tests/beman/execution/exec-run-loop-types.test.cpp index 85d91ba1..d0300df5 100644 --- a/tests/beman/execution/exec-run-loop-types.test.cpp +++ b/tests/beman/execution/exec-run-loop-types.test.cpp @@ -99,16 +99,7 @@ TEST(exec_run_loop_types) { ::std::same_as, decltype(test_std::get_completion_signatures())>); - // [exec.getcomplsigs] constrains sizeof...(Env) <= 1, so the - // zero-environment query is well-formed and must be answered. It is - // answered as for env<>, whose stop token is unstoppable. - static_assert(::std::same_as, - decltype(test_std::get_completion_signatures())>); - // ... and because detail::non_dependent_sender is itself spelled with that - // query inside a requires-expression, a sender that cannot answer it makes - // the concept ill-formed rather than false. Asserting the concept is what - // pins that down. - static_assert(not test_std::dependent_sender); + static_assert(test_std::dependent_sender); // p7: static_assert( test_std::receiver_of())>); diff --git a/tests/beman/execution/exec-snd-concepts.test.cpp b/tests/beman/execution/exec-snd-concepts.test.cpp index 87d92269..27cd687d 100644 --- a/tests/beman/execution/exec-snd-concepts.test.cpp +++ b/tests/beman/execution/exec-snd-concepts.test.cpp @@ -12,13 +12,6 @@ import std; import beman.execution; import beman.execution.detail; #else -#include -#include -#include -#include -#include -#include - #include #endif @@ -161,7 +154,28 @@ auto test_sender_in() -> void { static_assert(not test_std::sender_in); static_assert(test_std::sender_in); static_assert(test_std::sender_in); - //-dk:TODO add missing test cases for sender_in + + test_std::run_loop loop; + test_std::prop env_has_allocator{test_std::get_allocator, std::allocator{}}; + test_std::prop env_has_start_scheduler{test_std::get_start_scheduler, loop.get_scheduler()}; + + auto sndr = test_std::just() | + test_std::let_value([] { return test_std::read_env(test_std::get_allocator) | test_std::affine(); }); + static_assert(!test_std::sender_in>); + static_assert(test_std::sender_in); + auto [al] = test_std::sync_wait(sndr | test_std::write_env(env_has_allocator)).value(); + ASSERT(al == std::allocator{}); + + auto sndr2 = test_std::when_all(test_std::read_env(test_std::get_allocator), + test_std::read_env(test_std::get_start_scheduler)); + static_assert(!test_std::sender_in>); + static_assert(!test_std::sender_in>); + static_assert(!test_std::sender_in); + static_assert(test_std::sender_in); + static_assert(!test_std::sender_in); + static_assert(test_std::sender_in); } auto test_tag_of_t() -> void { From c5d09909b70c83251512200353bcc9c6d14e603e Mon Sep 17 00:00:00 2001 From: Cra3z <3324654761@qq.com> Date: Wed, 28 Oct 2026 21:35:21 +0800 Subject: [PATCH 5/5] `continues_on` and `starts_on` should be dependent-sender if scheduler-sender is dependent-sender --- include/beman/execution/detail/continues_on.hpp | 9 +++++++-- include/beman/execution/detail/starts_on.hpp | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index 65975503..84a10684 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -26,6 +26,7 @@ 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.dependent_sender; import beman.execution.detail.env; import beman.execution.detail.env_of_t; import beman.execution.detail.error_types_of_t; @@ -66,6 +67,7 @@ import beman.execution.detail.start; #include #include #include +#include #include #include #include @@ -165,8 +167,11 @@ struct continues_on_t { template struct get_signatures; - template - struct get_signatures : get_signatures> {}; + template + requires(!::beman::execution::dependent_sender<::beman::execution::schedule_result_t>) + struct get_signatures< + ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, Scheduler, Sender>> + : get_signatures> {}; template requires ::beman::execution::sender_in> struct get_signatures< diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index 2e769db2..a21e05da 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -19,6 +19,7 @@ import beman.execution.detail.completion_signatures; import beman.execution.detail.completion_signatures_of_t; import beman.execution.detail.continues_on; import beman.execution.detail.default_impls; +import beman.execution.detail.dependent_sender; import beman.execution.detail.env; import beman.execution.detail.error_types_of_t; import beman.execution.detail.forward_like; @@ -51,6 +52,7 @@ import beman.execution.detail.set_value; #include #include #include +#include #include #include #include @@ -98,8 +100,11 @@ struct starts_on_t { private: template struct get_signatures; - template - struct get_signatures : get_signatures> {}; + template + requires(!::beman::execution::dependent_sender<::beman::execution::schedule_result_t>) + struct get_signatures< + ::beman::execution::detail::basic_sender<::beman::execution::detail::starts_on_t, Scheduler, Child>> + : get_signatures> {}; template requires requires { starts_on_t::transform_sender(