From febd0f91c98e201f34083a9043155fd06809317e Mon Sep 17 00:00:00 2001 From: Mikael Simberg Date: Mon, 4 Oct 2021 16:00:36 +0200 Subject: [PATCH] Update any_sender to use tag_dispatch for execution customizations --- .../include/hpx/execution_base/any_sender.hpp | 37 ++++++----- libs/core/execution_base/src/any_sender.cpp | 5 +- .../execution_base/tests/unit/any_sender.cpp | 63 +++++++++++-------- 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp b/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp index 4c561636939f..702012049356 100644 --- a/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp @@ -334,7 +334,9 @@ namespace hpx::execution::experimental { any_operation_state& operator=(any_operation_state&&) = delete; any_operation_state& operator=(any_operation_state const&) = delete; - void start() & noexcept; + HPX_CORE_EXPORT friend void tag_dispatch( + hpx::execution::experimental::start_t, + any_operation_state& os) noexcept; }; template @@ -367,7 +369,7 @@ namespace hpx::execution::experimental { return true; } - HPX_NORETURN void set_value(Ts...) && override + void set_value(Ts...) && override { throw_bad_any_call("any_receiver", "set_value"); } @@ -456,33 +458,36 @@ namespace hpx::execution::experimental { any_receiver& operator=(any_receiver&&) = default; any_receiver& operator=(any_receiver const&) = delete; - void set_value(Ts... ts) && + friend void tag_dispatch(hpx::execution::experimental::set_value_t, + any_receiver&& r, Ts... ts) { // We first move the storage to a temporary variable so that // this any_receiver is empty after this set_value. Doing // std::move(storage.get()).set_value(...) would leave us with a // non-empty any_receiver holding a moved-from receiver. - auto moved_storage = std::move(storage); + auto moved_storage = std::move(r.storage); std::move(moved_storage.get()).set_value(std::move(ts)...); } - void set_error(std::exception_ptr ep) && noexcept + friend void tag_dispatch(hpx::execution::experimental::set_error_t, + any_receiver&& r, std::exception_ptr ep) noexcept { // We first move the storage to a temporary variable so that // this any_receiver is empty after this set_error. Doing // std::move(storage.get()).set_error(...) would leave us with a // non-empty any_receiver holding a moved-from receiver. - auto moved_storage = std::move(storage); + auto moved_storage = std::move(r.storage); std::move(moved_storage.get()).set_error(std::move(ep)); } - void set_done() && noexcept + friend void tag_dispatch(hpx::execution::experimental::set_done_t, + any_receiver&& r) noexcept { // We first move the storage to a temporary variable so that // this any_receiver is empty after this set_done. Doing // std::move(storage.get()).set_done(...) would leave us with a // non-empty any_receiver holding a moved-from receiver. - auto moved_storage = std::move(storage); + auto moved_storage = std::move(r.storage); std::move(moved_storage.get()).set_done(); } }; @@ -684,13 +689,15 @@ namespace hpx::execution::experimental { static constexpr bool sends_done = false; template - detail::any_operation_state connect(R&& r) && + friend detail::any_operation_state tag_dispatch( + hpx::execution::experimental::connect_t, unique_any_sender&& s, + R&& r) { // We first move the storage to a temporary variable so that this // any_sender is empty after this connect. Doing // std::move(storage.get()).connect(...) would leave us with a // non-empty any_sender holding a moved-from sender. - auto moved_storage = std::move(storage); + auto moved_storage = std::move(s.storage); return std::move(moved_storage.get()) .connect(detail::any_receiver{std::forward(r)}); } @@ -755,20 +762,22 @@ namespace hpx::execution::experimental { static constexpr bool sends_done = false; template - detail::any_operation_state connect(R&& r) & + friend detail::any_operation_state tag_dispatch( + hpx::execution::experimental::connect_t, any_sender& s, R&& r) { - return storage.get().connect( + return s.storage.get().connect( detail::any_receiver{std::forward(r)}); } template - detail::any_operation_state connect(R&& r) && + friend detail::any_operation_state tag_dispatch( + hpx::execution::experimental::connect_t, any_sender&& s, R&& r) { // We first move the storage to a temporary variable so that this // any_sender is empty after this connect. Doing // std::move(storage.get()).connect(...) would leave us with a // non-empty any_sender holding a moved-from sender. - auto moved_storage = std::move(storage); + auto moved_storage = std::move(s.storage); return std::move(moved_storage.get()) .connect(detail::any_receiver{std::forward(r)}); } diff --git a/libs/core/execution_base/src/any_sender.cpp b/libs/core/execution_base/src/any_sender.cpp index b8a4168ca747..acf079f70c3f 100644 --- a/libs/core/execution_base/src/any_sender.cpp +++ b/libs/core/execution_base/src/any_sender.cpp @@ -27,9 +27,10 @@ namespace hpx::execution::experimental::detail { return true; } - void any_operation_state::start() & noexcept + void tag_dispatch( + hpx::execution::experimental::start_t, any_operation_state& os) noexcept { - storage.get().start(); + os.storage.get().start(); } void throw_bad_any_call(char const* class_name, char const* function_name) diff --git a/libs/core/execution_base/tests/unit/any_sender.cpp b/libs/core/execution_base/tests/unit/any_sender.cpp index f9be520b812c..b8d82fffeb71 100644 --- a/libs/core/execution_base/tests/unit/any_sender.cpp +++ b/libs/core/execution_base/tests/unit/any_sender.cpp @@ -70,19 +70,22 @@ struct non_copyable_sender std::decay_t r; std::tuple...> ts; - void start() & noexcept + friend void tag_dispatch( + hpx::execution::experimental::start_t, operation_state& os) noexcept { hpx::util::invoke_fused( hpx::util::bind_front( - hpx::execution::experimental::set_value, std::move(r)), - std::move(ts)); + hpx::execution::experimental::set_value, std::move(os.r)), + std::move(os.ts)); }; }; template - operation_state connect(R&& r) && noexcept + friend operation_state tag_dispatch( + hpx::execution::experimental::connect_t, non_copyable_sender&& s, + R&& r) noexcept { - return {std::forward(r), std::move(ts)}; + return {std::forward(r), std::move(s.ts)}; } }; @@ -123,25 +126,28 @@ struct sender std::decay_t r; std::tuple...> ts; - void start() & noexcept + friend void tag_dispatch( + hpx::execution::experimental::start_t, operation_state& os) noexcept { hpx::util::invoke_fused( hpx::util::bind_front( - hpx::execution::experimental::set_value, std::move(r)), - std::move(ts)); + hpx::execution::experimental::set_value, std::move(os.r)), + std::move(os.ts)); }; }; template - operation_state connect(R&& r) && noexcept + friend operation_state tag_dispatch( + hpx::execution::experimental::connect_t, sender&& s, R&& r) { - return {std::forward(r), std::move(ts)}; + return {std::forward(r), std::move(s.ts)}; } template - operation_state connect(R&& r) & noexcept + friend operation_state tag_dispatch( + hpx::execution::experimental::connect_t, sender& s, R&& r) { - return {std::forward(r), ts}; + return {std::forward(r), s.ts}; } }; @@ -215,7 +221,8 @@ struct error_sender struct operation_state { std::decay_t r; - void start() noexcept + friend void tag_dispatch( + hpx::execution::experimental::start_t, operation_state& os) noexcept { try { @@ -224,13 +231,14 @@ struct error_sender catch (...) { hpx::execution::experimental::set_error( - std::move(r), std::current_exception()); + std::move(os.r), std::current_exception()); } } }; template - operation_state connect(R&& r) + friend operation_state tag_dispatch( + hpx::execution::experimental::connect_t, error_sender, R&& r) { return {std::forward(r)}; } @@ -243,22 +251,24 @@ struct callback_receiver std::atomic& set_value_called; template - void set_error(E&&) && noexcept + friend void tag_dispatch(hpx::execution::experimental::set_error_t, + callback_receiver&&, E&&) noexcept { HPX_TEST(false); } - void set_done() && noexcept + friend void tag_dispatch( + hpx::execution::experimental::set_done_t, callback_receiver&&) noexcept { HPX_TEST(false); }; template - auto set_value(Ts&&... ts) && noexcept - -> decltype(HPX_INVOKE(f, std::forward(ts)...), void()) + friend auto tag_dispatch(hpx::execution::experimental::set_value_t, + callback_receiver&& r, Ts&&... ts) noexcept { - HPX_INVOKE(f, std::forward(ts)...); - set_value_called = true; + HPX_INVOKE(std::move(r.f), std::forward(ts)...); + r.set_value_called = true; } }; @@ -266,7 +276,8 @@ struct error_receiver { std::atomic& set_error_called; - void set_error(std::exception_ptr&& e) noexcept + friend void tag_dispatch(hpx::execution::experimental::set_error_t, + error_receiver&& r, std::exception_ptr&& e) noexcept { try { @@ -280,16 +291,18 @@ struct error_receiver { HPX_TEST(false); } - set_error_called = true; + r.set_error_called = true; } - void set_done() noexcept + friend void tag_dispatch( + hpx::execution::experimental::set_done_t, error_receiver&&) noexcept { HPX_TEST(false); }; template - void set_value(Ts&&...) noexcept + friend void tag_dispatch(hpx::execution::experimental::set_value_t, + error_receiver&&, Ts&&...) noexcept { HPX_TEST(false); }