From c418e38a27d10132c2113109d90e47e2422267b9 Mon Sep 17 00:00:00 2001 From: Maikel Nadolski Date: Wed, 8 Jan 2025 14:39:09 +0100 Subject: [PATCH 1/5] WIP: initial implementation of D3206R0 --- .../beman/execution26/detail/basic_sender.hpp | 35 +++++++--- .../detail/completion_behaviour.hpp | 13 ++++ .../execution26/detail/default_impls.hpp | 4 ++ .../detail/get_completion_behaviour.hpp | 68 +++++++++++++++++++ include/beman/execution26/detail/just.hpp | 8 ++- src/beman/execution26/CMakeLists.txt | 2 + tests/beman/execution26/CMakeLists.txt | 1 + .../exec-get-completion-behaviour.test.cpp | 53 +++++++++++++++ 8 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 include/beman/execution26/detail/completion_behaviour.hpp create mode 100644 include/beman/execution26/detail/get_completion_behaviour.hpp create mode 100644 tests/beman/execution26/exec-get-completion-behaviour.test.cpp diff --git a/include/beman/execution26/detail/basic_sender.hpp b/include/beman/execution26/detail/basic_sender.hpp index ce765f1e..ae7a2e65 100644 --- a/include/beman/execution26/detail/basic_sender.hpp +++ b/include/beman/execution26/detail/basic_sender.hpp @@ -39,16 +39,29 @@ struct basic_sender : ::beman::execution26::detail::product_type + constexpr auto get_completion_behaviour(this Self&& self, Env&& env) noexcept -> decltype(auto) { + auto data{::beman::execution26::detail::get_sender_data(self)}; + return ::std::apply( + [&data, &env](auto&&... cs) { + return ::beman::execution26::detail::impls_for::get_completion_behaviour( + ::std::forward(env), + ::beman::execution26::detail::forward_like(data.data), + ::beman::execution26::detail::forward_like(cs)...); + }, + ::beman::execution26::detail::forward_like(data.children)); + } + template - requires(not::beman::execution26::receiver) + requires(not ::beman::execution26::receiver) auto connect(Receiver receiver) = BEMAN_EXECUTION26_DELETE("the passed receiver doesn't model receiver"); private: #if __cpp_explicit_this_parameter < 302110L //-dk:TODO need to figure out how to use explicit this with forwarding template <::beman::execution26::receiver Receiver> auto connect(Receiver receiver) & noexcept( - noexcept(::beman::execution26::detail::basic_operation{*this, ::std::move(receiver)})) - -> ::beman::execution26::detail::basic_operation { + noexcept(::beman::execution26::detail::basic_operation{ + *this, ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation { return {*this, ::std::move(receiver)}; } template <::beman::execution26::receiver Receiver> @@ -59,9 +72,9 @@ struct basic_sender : ::beman::execution26::detail::product_type auto connect(Receiver receiver) && noexcept( - noexcept(::beman::execution26::detail::basic_operation{::std::move(*this), - ::std::move(receiver)})) - -> ::beman::execution26::detail::basic_operation { + noexcept(::beman::execution26::detail::basic_operation{ + ::std::move(*this), + ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation { return {::std::move(*this), ::std::move(receiver)}; } #else @@ -69,8 +82,8 @@ struct basic_sender : ::beman::execution26::detail::product_type{ - ::std::forward(self), ::std::move(receiver)})) - -> ::beman::execution26::detail::basic_operation { + ::std::forward(self), + ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation { return {::std::forward(self), ::std::move(receiver)}; } #endif @@ -101,6 +114,12 @@ struct basic_sender : ::beman::execution26::detail::product_type ::beman::execution26::detail::completion_signatures_for { return {}; } + + template <::beman::execution26::detail::decays_to Self, typename Env> + auto get_completion_behaviour(this Self&&, Env&&) noexcept + -> ::beman::execution26::detail::completion_signatures_for { + return {}; + } #endif }; } // namespace beman::execution26::detail diff --git a/include/beman/execution26/detail/completion_behaviour.hpp b/include/beman/execution26/detail/completion_behaviour.hpp new file mode 100644 index 00000000..3601caf1 --- /dev/null +++ b/include/beman/execution26/detail/completion_behaviour.hpp @@ -0,0 +1,13 @@ +// include/beman/execution26/detail/completion_behaviour.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_COMPLETION_BEHAVIOUR +#define INCLUDED_BEMAN_EXECUTION26_DETAIL_COMPLETION_BEHAVIOUR + +#include + +namespace beman::execution26 { +enum class completion_behaviour : std::uint8_t { inline_completion, synchronous, asynchronous, unknown }; +} // namespace beman::execution26 + +#endif diff --git a/include/beman/execution26/detail/default_impls.hpp b/include/beman/execution26/detail/default_impls.hpp index d4f44bb2..f521d03d 100644 --- a/include/beman/execution26/detail/default_impls.hpp +++ b/include/beman/execution26/detail/default_impls.hpp @@ -52,6 +52,10 @@ struct default_impls { static_assert(Index::value == 0); Tag()(::std::move(receiver), ::std::forward(args)...); }; + static constexpr auto get_completion_behaviour = + [](const auto& /* env */, const auto& /* data */, const auto&... /* children */) noexcept { + return ::beman::execution26::completion_behaviour::unknown; + }; }; } // namespace beman::execution26::detail diff --git a/include/beman/execution26/detail/get_completion_behaviour.hpp b/include/beman/execution26/detail/get_completion_behaviour.hpp new file mode 100644 index 00000000..bd2e4b53 --- /dev/null +++ b/include/beman/execution26/detail/get_completion_behaviour.hpp @@ -0,0 +1,68 @@ +// include/beman/execution26/detail/get_completion_behaviour.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_GET_COMPLETION_BEHAVIOUR +#define INCLUDED_BEMAN_EXECUTION26_DETAIL_GET_COMPLETION_BEHAVIOUR + +#include +#include +#include +#include +#include + +#include + +namespace beman::execution26 { + +struct get_completion_behaviour_t { + template + constexpr auto operator()(Sender&& sender) const noexcept { + if constexpr (requires { typename ::std::remove_cvref_t::completion_behaviour; }) { + return typename ::std::remove_cvref_t::completion_behaviour{}; + } else if constexpr (requires { ::std::forward(sender).get_completion_behaviour(); }) { + return ::std::forward(sender).get_completion_behaviour(); + } else if constexpr (::beman::execution26::detail::is_awaitable< + ::std::remove_cvref_t, + ::beman::execution26::detail::env_promise<::beman::execution26::empty_env>>) { + return sender.await_ready() ? ::beman::execution26::completion_behaviour::inline_completion + : ::beman::execution26::completion_behaviour::unknown; + } else { + return ::beman::execution26::completion_behaviour::unknown; + } + } + + template + constexpr auto operator()(Sender&& sender, Env&& env) const noexcept { + auto new_sender{[](auto&& sndr, auto&& e) -> decltype(auto) { + auto domain{::beman::execution26::detail::get_domain_late(sndr, e)}; + return ::beman::execution26::transform_sender( + domain, ::std::forward(sndr), ::std::forward(e)); + }}; + + using new_sender_type = + ::std::remove_cvref_t(sender), ::std::forward(env)))>; + using decayed_env = ::std::remove_cvref_t; + + if constexpr (requires { typename new_sender_type::completion_behaviour; }) { + return typename new_sender_type::completion_behaviour{}; + } else if constexpr (requires { ::std::move(new_sender).get_completion_behaviour(std::forward(env)); }) { + return std::move(new_sender).get_completion_behaviour(std::forward(env)); + } else if constexpr (::beman::execution26::detail::is_awaitable< + new_sender_type, + ::beman::execution26::detail::env_promise>) { + if (new_sender(sender, env).await_ready()) { + return completion_behaviour::inline_completion; + } else { + return completion_behaviour::unknown; + } + } else { + return completion_behaviour::unknown; + } + } +}; + +inline constexpr get_completion_behaviour_t get_completion_behaviour{}; + +} // namespace beman::execution26 + +#endif diff --git a/include/beman/execution26/detail/just.hpp b/include/beman/execution26/detail/just.hpp index 8296e87d..dc3ef22c 100644 --- a/include/beman/execution26/detail/just.hpp +++ b/include/beman/execution26/detail/just.hpp @@ -22,8 +22,8 @@ namespace beman::execution26::detail { template -concept just_size = (not::std::same_as or 1u == sizeof...(T)) && - (not::std::same_as or 0u == sizeof...(T)); +concept just_size = (not ::std::same_as or 1u == sizeof...(T)) && + (not ::std::same_as or 0u == sizeof...(T)); template struct just_t { template @@ -49,6 +49,10 @@ struct impls_for> : ::beman::execution26::detail::default_imp Completion()(::std::move(receiver), ::std::move(state.template get())...); }(::std::make_index_sequence{}); }; + + static constexpr auto get_completion_behaviour = [](const auto&, const auto&, const auto&) { + return ::beman::execution26::completion_behaviour::inline_completion; + }; }; } // namespace beman::execution26::detail diff --git a/src/beman/execution26/CMakeLists.txt b/src/beman/execution26/CMakeLists.txt index 1c02b30a..343aed1f 100644 --- a/src/beman/execution26/CMakeLists.txt +++ b/src/beman/execution26/CMakeLists.txt @@ -53,6 +53,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/child_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/class_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/common.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_behaviour.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_signature.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/completion_signatures.hpp @@ -84,6 +85,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/gather_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_allocator.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_awaiter.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_completion_behaviour.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_completion_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_completion_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution26/detail/get_delegation_scheduler.hpp diff --git a/tests/beman/execution26/CMakeLists.txt b/tests/beman/execution26/CMakeLists.txt index b9130f6e..4dee7c6b 100644 --- a/tests/beman/execution26/CMakeLists.txt +++ b/tests/beman/execution26/CMakeLists.txt @@ -23,6 +23,7 @@ list( exec-general.test exec-get-allocator.test exec-get-compl-sched.test + exec-get-completion-behaviour.test exec-get-delegation-scheduler.test exec-get-domain.test exec-get-env.test diff --git a/tests/beman/execution26/exec-get-completion-behaviour.test.cpp b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp new file mode 100644 index 00000000..9a021729 --- /dev/null +++ b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp @@ -0,0 +1,53 @@ +// src/beman/execution26/tests/exec-get-completion-behaviour.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include + +#include + +namespace { + +template +using value = std::integral_constant; + +struct awaitable { + static constexpr auto await_ready() noexcept -> bool { return true; } + auto await_suspend(auto parent) noexcept { return parent; } + auto await_resume() noexcept -> void {} +}; + +void test_constexpr_awaitable() { + auto completion_behaviour = value{}; + ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); +} +struct sender { + using completion_behaviour = value; +}; + +struct sender2 { + static constexpr auto get_completion_behaviour() noexcept -> test_std::completion_behaviour { + return test_std::completion_behaviour::inline_completion; + } +}; + +void test_typedef_sender() { + auto completion_behaviour = + std::integral_constant{}; + ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); +} + +void test_constexpr_sender() { + auto completion_behaviour = + std::integral_constant{}; + ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); +} + +} // namespace + +TEST(exec_get_completion_behaviour) { + test_constexpr_awaitable(); + test_typedef_sender(); + test_constexpr_sender(); +} From 068398039fb8a0de870bb1a345f6b0c8ea122609 Mon Sep 17 00:00:00 2001 From: Maikel Nadolski Date: Wed, 8 Jan 2025 15:01:02 +0100 Subject: [PATCH 2/5] Fix test for just sender --- .../execution26/detail/get_completion_behaviour.hpp | 10 +++++++--- include/beman/execution26/detail/just.hpp | 2 +- .../execution26/exec-get-completion-behaviour.test.cpp | 8 ++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/beman/execution26/detail/get_completion_behaviour.hpp b/include/beman/execution26/detail/get_completion_behaviour.hpp index bd2e4b53..3ed2b5ff 100644 --- a/include/beman/execution26/detail/get_completion_behaviour.hpp +++ b/include/beman/execution26/detail/get_completion_behaviour.hpp @@ -45,12 +45,16 @@ struct get_completion_behaviour_t { if constexpr (requires { typename new_sender_type::completion_behaviour; }) { return typename new_sender_type::completion_behaviour{}; - } else if constexpr (requires { ::std::move(new_sender).get_completion_behaviour(std::forward(env)); }) { - return std::move(new_sender).get_completion_behaviour(std::forward(env)); + } else if constexpr (requires { + new_sender(::std::forward(sender), ::std::forward(env)) + .get_completion_behaviour(std::forward(env)); + }) { + return new_sender(::std::forward(sender), ::std::forward(env)) + .get_completion_behaviour(std::forward(env)); } else if constexpr (::beman::execution26::detail::is_awaitable< new_sender_type, ::beman::execution26::detail::env_promise>) { - if (new_sender(sender, env).await_ready()) { + if (new_sender(::std::forward(sender), ::std::forward(env)).await_ready()) { return completion_behaviour::inline_completion; } else { return completion_behaviour::unknown; diff --git a/include/beman/execution26/detail/just.hpp b/include/beman/execution26/detail/just.hpp index dc3ef22c..c7dfb601 100644 --- a/include/beman/execution26/detail/just.hpp +++ b/include/beman/execution26/detail/just.hpp @@ -50,7 +50,7 @@ struct impls_for> : ::beman::execution26::detail::default_imp }(::std::make_index_sequence{}); }; - static constexpr auto get_completion_behaviour = [](const auto&, const auto&, const auto&) { + static constexpr auto get_completion_behaviour = [](const auto&, const auto&, const auto&...) { return ::beman::execution26::completion_behaviour::inline_completion; }; }; diff --git a/tests/beman/execution26/exec-get-completion-behaviour.test.cpp b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp index 9a021729..79219851 100644 --- a/tests/beman/execution26/exec-get-completion-behaviour.test.cpp +++ b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include +#include #include @@ -44,10 +45,17 @@ void test_constexpr_sender() { ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); } +void test_just() { + auto just = test_std::just(); + auto completion_behaviour = test_std::get_completion_behaviour(just, test_std::empty_env{}); + ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); +} + } // namespace TEST(exec_get_completion_behaviour) { test_constexpr_awaitable(); test_typedef_sender(); test_constexpr_sender(); + test_just(); } From 37cb03855885e79a21217638c5edb87739a55310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 12 Jan 2025 19:59:40 +0000 Subject: [PATCH 3/5] applied some fixes --- .../beman/execution26/detail/basic_sender.hpp | 21 +++++++++++++++++-- .../execution26/detail/default_impls.hpp | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/beman/execution26/detail/basic_sender.hpp b/include/beman/execution26/detail/basic_sender.hpp index ae7a2e65..34853688 100644 --- a/include/beman/execution26/detail/basic_sender.hpp +++ b/include/beman/execution26/detail/basic_sender.hpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -39,7 +39,23 @@ struct basic_sender : ::beman::execution26::detail::product_type +#if __cpp_explicit_this_parameter < 302110L //-dk:TODO need to figure out how to use explicit this with forwarding + template + constexpr auto get_completion_behaviour(Env&& env) noexcept -> decltype(auto) { + return [](Self&& self, Env&& env) ->decltype(auto) { + auto data{::beman::execution26::detail::get_sender_data(self)}; + return ::std::apply( + [&data, &env](auto&&... cs) { + return ::beman::execution26::detail::impls_for::get_completion_behaviour( + ::std::forward(env), + ::beman::execution26::detail::forward_like(data.data), + ::beman::execution26::detail::forward_like(cs)...); + }, + ::beman::execution26::detail::forward_like(data.children)); + }(*this, ::std::forward(env)); + } +#else + template constexpr auto get_completion_behaviour(this Self&& self, Env&& env) noexcept -> decltype(auto) { auto data{::beman::execution26::detail::get_sender_data(self)}; return ::std::apply( @@ -51,6 +67,7 @@ struct basic_sender : ::beman::execution26::detail::product_type(data.children)); } +#endif template requires(not ::beman::execution26::receiver) diff --git a/include/beman/execution26/detail/default_impls.hpp b/include/beman/execution26/detail/default_impls.hpp index f521d03d..e7471100 100644 --- a/include/beman/execution26/detail/default_impls.hpp +++ b/include/beman/execution26/detail/default_impls.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include From 0a41d6f976c7baffed1c9dd4f626f6ab73f067d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 12 Jan 2025 20:16:53 +0000 Subject: [PATCH 4/5] clang-format --- .../beman/execution26/detail/basic_sender.hpp | 20 +++++++++---------- include/beman/execution26/detail/just.hpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/beman/execution26/detail/basic_sender.hpp b/include/beman/execution26/detail/basic_sender.hpp index 34853688..04854fef 100644 --- a/include/beman/execution26/detail/basic_sender.hpp +++ b/include/beman/execution26/detail/basic_sender.hpp @@ -42,7 +42,7 @@ struct basic_sender : ::beman::execution26::detail::product_type constexpr auto get_completion_behaviour(Env&& env) noexcept -> decltype(auto) { - return [](Self&& self, Env&& env) ->decltype(auto) { + return [](Self&& self, Env&& env) -> decltype(auto) { auto data{::beman::execution26::detail::get_sender_data(self)}; return ::std::apply( [&data, &env](auto&&... cs) { @@ -52,7 +52,7 @@ struct basic_sender : ::beman::execution26::detail::product_type(cs)...); }, ::beman::execution26::detail::forward_like(data.children)); - }(*this, ::std::forward(env)); + }(*this, ::std::forward(env)); } #else template @@ -70,15 +70,15 @@ struct basic_sender : ::beman::execution26::detail::product_type - requires(not ::beman::execution26::receiver) + requires(not::beman::execution26::receiver) auto connect(Receiver receiver) = BEMAN_EXECUTION26_DELETE("the passed receiver doesn't model receiver"); private: #if __cpp_explicit_this_parameter < 302110L //-dk:TODO need to figure out how to use explicit this with forwarding template <::beman::execution26::receiver Receiver> auto connect(Receiver receiver) & noexcept( - noexcept(::beman::execution26::detail::basic_operation{ - *this, ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation { + noexcept(::beman::execution26::detail::basic_operation{*this, ::std::move(receiver)})) + -> ::beman::execution26::detail::basic_operation { return {*this, ::std::move(receiver)}; } template <::beman::execution26::receiver Receiver> @@ -89,9 +89,9 @@ struct basic_sender : ::beman::execution26::detail::product_type auto connect(Receiver receiver) && noexcept( - noexcept(::beman::execution26::detail::basic_operation{ - ::std::move(*this), - ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation { + noexcept(::beman::execution26::detail::basic_operation{::std::move(*this), + ::std::move(receiver)})) + -> ::beman::execution26::detail::basic_operation { return {::std::move(*this), ::std::move(receiver)}; } #else @@ -99,8 +99,8 @@ struct basic_sender : ::beman::execution26::detail::product_type{ - ::std::forward(self), - ::std::move(receiver)})) -> ::beman::execution26::detail::basic_operation { + ::std::forward(self), ::std::move(receiver)})) + -> ::beman::execution26::detail::basic_operation { return {::std::forward(self), ::std::move(receiver)}; } #endif diff --git a/include/beman/execution26/detail/just.hpp b/include/beman/execution26/detail/just.hpp index c7dfb601..7a837a9a 100644 --- a/include/beman/execution26/detail/just.hpp +++ b/include/beman/execution26/detail/just.hpp @@ -22,8 +22,8 @@ namespace beman::execution26::detail { template -concept just_size = (not ::std::same_as or 1u == sizeof...(T)) && - (not ::std::same_as or 0u == sizeof...(T)); +concept just_size = (not::std::same_as or 1u == sizeof...(T)) && + (not::std::same_as or 0u == sizeof...(T)); template struct just_t { template From 0827385b5ed3e651aa0fa4da4def449fc61685c8 Mon Sep 17 00:00:00 2001 From: Maikel Nadolski Date: Mon, 13 Jan 2025 09:55:58 +0100 Subject: [PATCH 5/5] More constexpr --- .../beman/execution26/detail/forward_like.hpp | 14 +++++------ .../detail/get_completion_behaviour.hpp | 3 ++- include/beman/execution26/detail/just.hpp | 6 ++--- .../beman/execution26/detail/product_type.hpp | 24 ++++++++++--------- .../execution26/detail/sender_decompose.hpp | 4 ++-- .../exec-get-completion-behaviour.test.cpp | 6 +++++ 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/include/beman/execution26/detail/forward_like.hpp b/include/beman/execution26/detail/forward_like.hpp index 4b958901..5192cb36 100644 --- a/include/beman/execution26/detail/forward_like.hpp +++ b/include/beman/execution26/detail/forward_like.hpp @@ -18,35 +18,35 @@ struct forward_like_helper; template struct forward_like_helper { template - static auto forward(U&& u) -> ::std::remove_reference_t&& { + static constexpr auto forward(U&& u) -> ::std::remove_reference_t&& { return ::std::move(u); // NOLINT(bugprone-move-forwarding-reference) } }; template struct forward_like_helper { template - static auto forward(U&& u) -> ::std::remove_cvref_t&& { + static constexpr auto forward(U&& u) -> ::std::remove_cvref_t&& { return ::std::move(u); // NOLINT(bugprone-move-forwarding-reference) } }; template struct forward_like_helper { template - static auto forward(U&& u) -> ::std::remove_cvref_t& { + static constexpr auto forward(U&& u) -> ::std::remove_cvref_t& { return ::std::forward(u); } }; template struct forward_like_helper { template - static auto forward(U&& u) -> const ::std::remove_cvref_t&& { + static constexpr auto forward(U&& u) -> const ::std::remove_cvref_t&& { return ::std::move(u); // NOLINT(bugprone-move-forwarding-reference) } }; template struct forward_like_helper { template - static auto forward(U&& u) -> const ::std::remove_cvref_t& { + static constexpr auto forward(U&& u) -> const ::std::remove_cvref_t& { return ::std::forward(u); } }; @@ -54,7 +54,7 @@ struct forward_like_helper { // The overload own_forward_like is used for testing on systems // which actually do provide an implementation. template -auto own_forward_like(U&& u) noexcept -> decltype(auto) { +constexpr auto own_forward_like(U&& u) noexcept -> decltype(auto) { return ::beman::execution26::detail::forward_like_helper::forward(::std::forward(u)); } @@ -64,7 +64,7 @@ auto own_forward_like(U&& u) noexcept -> decltype(auto) { * \internal */ template -auto forward_like(U&& u) noexcept -> decltype(auto) { +constexpr auto forward_like(U&& u) noexcept -> decltype(auto) { #if 202207 <= disabled__cpp_lib_forward_like return ::std::forward_like(::std::forward(u)); #else diff --git a/include/beman/execution26/detail/get_completion_behaviour.hpp b/include/beman/execution26/detail/get_completion_behaviour.hpp index 3ed2b5ff..0b002790 100644 --- a/include/beman/execution26/detail/get_completion_behaviour.hpp +++ b/include/beman/execution26/detail/get_completion_behaviour.hpp @@ -49,7 +49,8 @@ struct get_completion_behaviour_t { new_sender(::std::forward(sender), ::std::forward(env)) .get_completion_behaviour(std::forward(env)); }) { - return new_sender(::std::forward(sender), ::std::forward(env)) + std::remove_cvref_t copiedEnv(env); + return new_sender(::std::forward(sender), ::std::forward(copiedEnv)) .get_completion_behaviour(std::forward(env)); } else if constexpr (::beman::execution26::detail::is_awaitable< new_sender_type, diff --git a/include/beman/execution26/detail/just.hpp b/include/beman/execution26/detail/just.hpp index 7a837a9a..6b93d57d 100644 --- a/include/beman/execution26/detail/just.hpp +++ b/include/beman/execution26/detail/just.hpp @@ -22,14 +22,14 @@ namespace beman::execution26::detail { template -concept just_size = (not::std::same_as or 1u == sizeof...(T)) && - (not::std::same_as or 0u == sizeof...(T)); +concept just_size = (not ::std::same_as or 1u == sizeof...(T)) && + (not ::std::same_as or 0u == sizeof...(T)); template struct just_t { template requires ::beman::execution26::detail::just_size && (::std::movable<::std::decay_t> && ...) - auto operator()(T&&... arg) const { + constexpr auto operator()(T&&... arg) const { return ::beman::execution26::detail::make_sender( *this, ::beman::execution26::detail::product_type{::std::forward(arg)...}); } diff --git a/include/beman/execution26/detail/product_type.hpp b/include/beman/execution26/detail/product_type.hpp index b309f95c..ee520a51 100644 --- a/include/beman/execution26/detail/product_type.hpp +++ b/include/beman/execution26/detail/product_type.hpp @@ -29,34 +29,35 @@ struct product_type_base<::std::index_sequence, T...> static constexpr bool is_product_type{true}; template <::std::size_t J, typename S> - static auto element_get(::beman::execution26::detail::product_type_element& self) noexcept -> S& { + static constexpr auto element_get(::beman::execution26::detail::product_type_element& self) noexcept -> S& { return self.value; } template <::std::size_t J, typename S> - static auto element_get(::beman::execution26::detail::product_type_element&& self) noexcept -> S&& { + static constexpr auto + element_get(::beman::execution26::detail::product_type_element&& self) noexcept -> S&& { return ::std::move(self.value); } template <::std::size_t J, typename S> - static auto element_get(const ::beman::execution26::detail::product_type_element& self) noexcept - -> const S& { + static constexpr auto + element_get(const ::beman::execution26::detail::product_type_element& self) noexcept -> const S& { return self.value; } template <::std::size_t J> - auto get() & -> decltype(auto) { + constexpr auto get() & -> decltype(auto) { return this->element_get(*this); } template <::std::size_t J> - auto get() && -> decltype(auto) { + constexpr auto get() && -> decltype(auto) { return this->element_get(::std::move(*this)); } template <::std::size_t J> - auto get() const& -> decltype(auto) { + constexpr auto get() const& -> decltype(auto) { return this->element_get(*this); } template <::std::size_t J, typename Allocator, typename Self> - static auto make_element(Allocator&& alloc, Self&& self) -> decltype(auto) { + static constexpr auto make_element(Allocator&& alloc, Self&& self) -> decltype(auto) { using type = ::std::remove_cvref_t(std::forward(self)))>; if constexpr (::std::uses_allocator_v) return ::std::make_obj_using_allocator(alloc, @@ -65,7 +66,7 @@ struct product_type_base<::std::index_sequence, T...> return product_type_base::element_get(std::forward(self)); } - auto operator==(const product_type_base&) const -> bool = default; + constexpr auto operator==(const product_type_base&) const -> bool = default; }; template @@ -74,12 +75,13 @@ concept is_product_type_c = requires(const T& t) { T::is_product_type; }; template struct product_type : ::beman::execution26::detail::product_type_base<::std::index_sequence_for, T...> { template - static auto make_from(Allocator&& allocator, Product&& product, std::index_sequence) -> product_type { + static constexpr auto + make_from(Allocator&& allocator, Product&& product, std::index_sequence) -> product_type { return {product_type::template make_element(allocator, ::std::forward(product))...}; } template - static auto make_from(Allocator&& allocator, Product&& product) -> product_type { + static constexpr auto make_from(Allocator&& allocator, Product&& product) -> product_type { return product_type::make_from( ::std::forward(allocator), ::std::forward(product), ::std::index_sequence_for{}); } diff --git a/include/beman/execution26/detail/sender_decompose.hpp b/include/beman/execution26/detail/sender_decompose.hpp index d8915f54..0c801aa5 100644 --- a/include/beman/execution26/detail/sender_decompose.hpp +++ b/include/beman/execution26/detail/sender_decompose.hpp @@ -35,7 +35,7 @@ struct sender_data { }; template -auto get_sender_data(Sender&& sender) { +constexpr auto get_sender_data(Sender&& sender) { #if 0 //-dk:TODO should use a dynamic/language approach: auto&& [tag, data, ... children] = sender; @@ -82,7 +82,7 @@ auto get_sender_data(Sender&& sender) { } template -auto get_sender_meta(Sender&& sender) { +constexpr auto get_sender_meta(Sender&& sender) { using type = decltype(get_sender_data(sender)); return sender_meta{}; } diff --git a/tests/beman/execution26/exec-get-completion-behaviour.test.cpp b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp index 79219851..44eff6fe 100644 --- a/tests/beman/execution26/exec-get-completion-behaviour.test.cpp +++ b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp @@ -51,6 +51,11 @@ void test_just() { ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); } +void test_constexpr_just() { + constexpr auto completion_behaviour = test_std::get_completion_behaviour(test_std::just(), test_std::empty_env{}); + ASSERT(test_std::completion_behaviour::inline_completion == completion_behaviour); +} + } // namespace TEST(exec_get_completion_behaviour) { @@ -58,4 +63,5 @@ TEST(exec_get_completion_behaviour) { test_typedef_sender(); test_constexpr_sender(); test_just(); + test_constexpr_just(); }