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..3ed2b5ff --- /dev/null +++ b/include/beman/execution26/detail/get_completion_behaviour.hpp @@ -0,0 +1,72 @@ +// 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 { + 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(::std::forward(sender), ::std::forward(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..c7dfb601 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..79219851 --- /dev/null +++ b/tests/beman/execution26/exec-get-completion-behaviour.test.cpp @@ -0,0 +1,61 @@ +// src/beman/execution26/tests/exec-get-completion-behaviour.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#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); +} + +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(); +}