diff --git a/Makefile b/Makefile index dcba1b5a..6bd96c88 100644 --- a/Makefile +++ b/Makefile @@ -134,6 +134,23 @@ doc: ./bin/mk-doc.py docs/*.mds doxygen docs/Doxyfile +LLVM_VERSION=22.1.0 +DEV_DIR=build/dev-$(shell uname -s) +TESTCASE = * +DEV_TEST_OPTION=-DBEMAN_EXECUTION_TEST_CASE=$(TESTCASE) + +dev-config: + PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ cmake -B $(DEV_DIR) -G Ninja -DBEMAN_EXECUTION_BUILD_EXAMPLES=OFF -DBEMAN_EXECUTION_INSTALL_CONFIG_FILE_PACKAGE=OFF $(DEV_TEST_OPTION) + +dev-build: dev-config + PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ cmake --build $(DEV_DIR) + +dev-test: dev-build + PATH=/opt/llvm-$(LLVM_VERSION)/bin:$$PATH CXX=clang++ ctest --test-dir $(DEV_DIR) -R beman.execution.$(TESTCASE).test + +dev: dev-test + + # $(SANITIZERS): # $(MAKE) SANITIZER=$@ diff --git a/include/beman/execution/detail/affine_on.hpp b/include/beman/execution/detail/affine_on.hpp index 9c2210a5..b154ab57 100644 --- a/include/beman/execution/detail/affine_on.hpp +++ b/include/beman/execution/detail/affine_on.hpp @@ -17,11 +17,11 @@ import std; import beman.execution.detail.basic_sender; import beman.execution.detail.completion_signatures; import beman.execution.detail.completion_signatures_of_t; +import beman.execution.detail.continues_on; import beman.execution.detail.env; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; import beman.execution.detail.get_completion_signatures; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_scheduler; import beman.execution.detail.get_stop_token; import beman.execution.detail.make_sender; @@ -38,20 +38,19 @@ import beman.execution.detail.sender_has_affine_on; import beman.execution.detail.set_value; import beman.execution.detail.store_receiver; import beman.execution.detail.tag_of_t; -import beman.execution.detail.transform_sender; import beman.execution.detail.unstoppable; import beman.execution.detail.write_env; #else +#include +#include #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -60,7 +59,6 @@ import beman.execution.detail.write_env; #include #include #include -#include #include #include #endif @@ -100,10 +98,8 @@ struct affine_on_t : ::beman::execution::sender_adaptor_closure { */ template <::beman::execution::sender Sender> auto operator()(Sender&& sender) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sender), - ::beman::execution::detail::make_sender( - *this, ::beman::execution::env<>{}, ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, ::beman::execution::env<>{}, ::std::forward(sender)); } /** @@ -136,7 +132,7 @@ struct affine_on_t : ::beman::execution::sender_adaptor_closure { { ::beman::execution::get_scheduler(env) } -> ::beman::execution::scheduler; { ::beman::execution::schedule(::beman::execution::get_scheduler(env)) } -> ::beman::execution::sender; } - static auto transform_sender(Sender&& sender, const Env& ev) { + static auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env& ev) { static_assert(requires { { ::beman::execution::get_completion_signatures { return ::beman::execution::detail::store_receiver( ::beman::execution::detail::forward_like(child), [](Child&& child, const auto& ev) { - return ::beman::execution::unstoppable(::beman::execution::schedule_from( - ::beman::execution::get_scheduler(ev), - ::beman::execution::write_env(::std::forward(child), ev))); + return ::beman::execution::unstoppable(::beman::execution::continues_on( + ::beman::execution::write_env(::std::forward(child), ev), + ::beman::execution::get_scheduler(ev))); }); } } diff --git a/include/beman/execution/detail/associate.hpp b/include/beman/execution/detail/associate.hpp index 8b567d01..ac333c10 100644 --- a/include/beman/execution/detail/associate.hpp +++ b/include/beman/execution/detail/associate.hpp @@ -22,7 +22,6 @@ import beman.execution.detail.completion_signatures_for; import beman.execution.detail.default_impls; import beman.execution.detail.env; import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.nothrow_callable; @@ -32,19 +31,16 @@ import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; import beman.execution.detail.start; -import beman.execution.detail.transform_sender; import beman.execution.detail.valid_completion_signatures; #else #include #include -#include #include #include #include #include #include #include -#include #endif // ---------------------------------------------------------------------------- @@ -108,12 +104,8 @@ associate_data(Token, Sender&&) -> associate_data; struct associate_t { template <::beman::execution::sender Sender, ::beman::execution::scope_token Token> auto operator()(Sender&& sender, Token token) const { - auto domain(::beman::execution::detail::get_domain_early(sender)); - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::associate_data(::std::move(token), ::std::forward(sender)))); + return ::beman::execution::detail::make_sender( + *this, ::beman::execution::detail::associate_data(::std::move(token), ::std::forward(sender))); } template <::beman::execution::scope_token Token> diff --git a/include/beman/execution/detail/atomic_intrusive_stack.hpp b/include/beman/execution/detail/atomic_intrusive_stack.hpp index 1113e7ef..4db200e2 100644 --- a/include/beman/execution/detail/atomic_intrusive_stack.hpp +++ b/include/beman/execution/detail/atomic_intrusive_stack.hpp @@ -80,11 +80,9 @@ class atomic_intrusive_stack { auto stack = ::beman::execution::detail::intrusive_stack{}; void* ptr = head_.exchange(this); if (ptr == this) { - return stack; + return {}; } - auto item = static_cast(ptr); - stack.head_ = item; - return stack; + return ::beman::execution::detail::intrusive_stack{static_cast(ptr)}; } private: diff --git a/include/beman/execution/detail/basic_receiver.hpp b/include/beman/execution/detail/basic_receiver.hpp index da85dce8..b4427dff 100644 --- a/include/beman/execution/detail/basic_receiver.hpp +++ b/include/beman/execution/detail/basic_receiver.hpp @@ -72,7 +72,7 @@ template this->complete(Index(), this->op->state, this->op->receiver, - ::beman::execution::set_value_t(), + ::beman::execution::set_value, ::std::forward(args)...); } @@ -81,11 +81,8 @@ template requires ::beman::execution::detail:: callable { - this->complete(Index(), - this->op->state, - this->op->receiver, - ::beman::execution::set_error_t(), - ::std::forward(error)); + this->complete( + Index(), this->op->state, this->op->receiver, ::beman::execution::set_error, ::std::forward(error)); } auto set_stopped() && noexcept -> void diff --git a/include/beman/execution/detail/bulk.hpp b/include/beman/execution/detail/bulk.hpp index 12b3f4ec..b228941d 100644 --- a/include/beman/execution/detail/bulk.hpp +++ b/include/beman/execution/detail/bulk.hpp @@ -21,7 +21,6 @@ import beman.execution.detail.completion_signatures_of_t; import beman.execution.detail.default_impls; import beman.execution.detail.execution_policy; import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; import beman.execution.detail.meta.unique; @@ -31,7 +30,6 @@ import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; import beman.execution.detail.set_error; import beman.execution.detail.set_value; -import beman.execution.detail.transform_sender; #else #include #include @@ -39,7 +37,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #include #include #include @@ -49,7 +46,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #endif // ---------------------------------------------------------------------------- @@ -120,13 +116,11 @@ struct bulk_algo_t : ::beman::execution::sender_adaptor_closure> && ::std::integral && ::std::copy_constructible<::std::decay_t>) auto operator()(Sender&& sndr, Policy&& policy, Shape shape, F&& f) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ - ::std::forward(policy), shape, ::std::forward(f)}, - ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ + ::std::forward(policy), shape, ::std::forward(f)}, + ::std::forward(sndr)); } private: @@ -210,17 +204,15 @@ struct bulk_t : ::beman::execution::sender_adaptor_closure { ::beman::execution::is_execution_policy_v<::std::remove_cvref_t> && ::std::integral && ::std::copy_constructible<::std::decay_t>) auto operator()(Sender&& sndr, Policy&& policy, Shape shape, F&& f) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ - ::std::forward(policy), shape, ::std::forward(f)}, - ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type<::std::remove_cvref_t, Shape, ::std::decay_t>{ + ::std::forward(policy), shape, ::std::forward(f)}, + ::std::forward(sndr)); } - template <::beman::execution::detail::sender_for Sender, typename... Env> - auto transform_sender(Sender&& sndr, Env&&...) const { + template <::beman::execution::detail::sender_for Sender, typename Env> + auto transform_sender(::beman::execution::set_value_t, Sender&& sndr, const Env&) const { auto data = ::beman::execution::detail::forward_like(sndr.template get<1>()); auto child = ::beman::execution::detail::forward_like(sndr.template get<2>()); diff --git a/include/beman/execution/detail/common_domain.hpp b/include/beman/execution/detail/common_domain.hpp new file mode 100644 index 00000000..889dcf0a --- /dev/null +++ b/include/beman/execution/detail/common_domain.hpp @@ -0,0 +1,47 @@ +// include/beman/execution/detail/common_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMMON_DOMAIN +#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMMON_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.indeterminate_domain; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +template +struct common_domain_impl { + using type = ::beman::execution::indeterminate_domain; +}; + +template + requires requires { typename ::std::common_type_t; } +struct common_domain_impl { + using type = ::std::common_type_t; +}; + +template +using common_domain_t = typename common_domain_impl<::std::decay_t...>::type; + +template +constexpr auto common_domain(Domains&&...) noexcept { + return common_domain_t{}; +} + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMMON_DOMAIN diff --git a/include/beman/execution/detail/compl_domain.hpp b/include/beman/execution/detail/compl_domain.hpp new file mode 100644 index 00000000..e9ed7d2d --- /dev/null +++ b/include/beman/execution/detail/compl_domain.hpp @@ -0,0 +1,44 @@ +// include/beman/execution/detail/compl_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN +#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_env; +#else +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template +constexpr auto compl_domain(const Sndr& sndr, const Envs&... envs) noexcept { + if constexpr (requires { + ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...); + }) { + return ::beman::execution::get_completion_domain(::beman::execution::get_env(sndr), envs...); + } else { + return ::beman::execution::default_domain(); + } +} + +template +using compl_domain_of_t = + decltype(::beman::execution::detail::compl_domain(::std::declval(), ::std::declval()...)); +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPL_DOMAIN diff --git a/include/beman/execution/detail/completion_domain.hpp b/include/beman/execution/detail/completion_domain.hpp deleted file mode 100644 index fa643c3d..00000000 --- a/include/beman/execution/detail/completion_domain.hpp +++ /dev/null @@ -1,84 +0,0 @@ -// include/beman/execution/detail/completion_domain.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_DOMAIN -#define INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_DOMAIN - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.default_domain; -import beman.execution.detail.get_completion_scheduler; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -import beman.execution.detail.sender; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.set_value; -#else -#include -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -struct completion_domain_undefined {}; -template -struct completion_domain_merge {}; -template -struct completion_domain_merge { - using type = T; -}; -template -struct completion_domain_merge { - using type = T; -}; -template -struct completion_domain_merge { - using type = T; -}; -template <> -struct completion_domain_merge { - using type = completion_domain_undefined; -}; - -/*! - * \brief Get a sender's completion domain or the specified default. - * \headerfile beman/execution/execution.hpp - * \internal - */ -template -constexpr auto completion_domain(const Sender& sender) noexcept { - - static_assert(::beman::execution::sender); - constexpr auto get = [](Tag, const Sender& sender) { - if constexpr (requires { - ::beman::execution::get_domain( - ::beman::execution::get_completion_scheduler(::beman::execution::get_env(sender))); - }) { - return ::beman::execution::get_domain( - ::beman::execution::get_completion_scheduler(::beman::execution::get_env(sender))); - } else { - return completion_domain_undefined{}; - } - }; - - using type = typename completion_domain_merge< - typename completion_domain_merge::type, - decltype(get(::beman::execution::set_value, sender))>::type; - return ::std::conditional_t<::std::same_as, Default, type>(); -} -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_COMPLETION_DOMAIN diff --git a/include/beman/execution/detail/connect.hpp b/include/beman/execution/detail/connect.hpp index 28de8f01..f4642379 100644 --- a/include/beman/execution/detail/connect.hpp +++ b/include/beman/execution/detail/connect.hpp @@ -14,13 +14,11 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.connect_awaitable; -import beman.execution.detail.get_domain_late; import beman.execution.detail.get_env; import beman.execution.detail.operation_state; import beman.execution.detail.transform_sender; #else #include -#include #include #include #include @@ -41,11 +39,8 @@ struct connect_t { static auto make_new_sender(Sender&& sender, Receiver&& receiver) //-dk:TODO this noexcept needs to get confirmed/fixed noexcept(true) -> decltype(auto) { - return ::beman::execution::transform_sender( - decltype(::beman::execution::detail::get_domain_late(::std::forward(sender), - ::beman::execution::get_env(receiver))){}, - ::std::forward(sender), - ::beman::execution::get_env(receiver)); + return ::beman::execution::transform_sender(::std::forward(sender), + ::beman::execution::get_env(receiver)); } template static constexpr auto connect_noexcept() -> bool { diff --git a/include/beman/execution/detail/continues_on.hpp b/include/beman/execution/detail/continues_on.hpp index 98e2d19f..f57d665f 100644 --- a/include/beman/execution/detail/continues_on.hpp +++ b/include/beman/execution/detail/continues_on.hpp @@ -8,46 +8,78 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else +#include +#include +#include #include +#include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.as_tuple; import beman.execution.detail.basic_sender; -import beman.execution.detail.default_domain; +import beman.execution.detail.child_type; +import beman.execution.detail.completion_signatures; +import beman.execution.detail.completion_signatures_for; +import beman.execution.detail.completion_signatures_of_t; +import beman.execution.detail.connect; +import beman.execution.detail.connect_result_t; +import beman.execution.detail.decayed_tuple; import beman.execution.detail.default_impls; +import beman.execution.detail.env_of_t; +import beman.execution.detail.error_types_of_t; import beman.execution.detail.fwd_env; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; -import beman.execution.detail.get_domain_late; +import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_env; import beman.execution.detail.impls_for; import beman.execution.detail.join_env; import beman.execution.detail.make_sender; -import beman.execution.detail.query_with_default; -import beman.execution.detail.sched_attrs; +import beman.execution.detail.meta.combine; +import beman.execution.detail.meta.prepend; +import beman.execution.detail.meta.to; +import beman.execution.detail.meta.transform; +import beman.execution.detail.meta.unique; +import beman.execution.detail.receiver; +import beman.execution.detail.schedule; import beman.execution.detail.schedule_from; +import beman.execution.detail.schedule_result_t; 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.transform_sender; +import beman.execution.detail.sender_in; +import beman.execution.detail.set_error; +import beman.execution.detail.set_stopped; +import beman.execution.detail.start; #else -#include +#include +#include +#include +#include +#include #include +#include +#include #include -#include -#include #include #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include #include -#include +#include +#include +#include +#include #endif // ---------------------------------------------------------------------------- @@ -55,72 +87,154 @@ import beman.execution.detail.transform_sender; #include namespace beman::execution::detail { -// specialize default_domain appropriately -/*! - * \brief The actual implementation of the continues_on customization point object - * \headerfile beman/execution/execution.hpp - * \internal - */ + struct continues_on_t { - template <::beman::execution::detail::sender_for Sender, typename... Env> - static auto transform_sender(Sender&& sender, Env&&...) { - auto&& data{sender.template get<1>()}; - auto&& child{sender.template get<2>()}; - return ::beman::execution::schedule_from(std::move(data), std::move(child)); - } template <::beman::execution::scheduler Scheduler> auto operator()(Scheduler&& scheduler) const { return ::beman::execution::detail::make_sender_adaptor(*this, ::std::forward(scheduler)); } + template <::beman::execution::sender Sender, ::beman::execution::scheduler Scheduler> auto operator()(Sender&& sender, Scheduler&& scheduler) const { - auto domain(::beman::execution::detail::get_domain_early(sender)); - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, std::forward(scheduler), ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, + ::std::forward(scheduler), + ::beman::execution::schedule_from(::std::forward(sender))); } + + private: + template + struct get_signatures; + template + struct get_signatures< + ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, Scheduler, Sender>, + Env> { + using scheduler_sender = decltype(::beman::execution::schedule(::std::declval())); + template + using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; + using type = ::beman::execution::detail::meta::combine< + decltype(::beman::execution::get_completion_signatures()), + ::beman::execution::error_types_of_t, + ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>; + }; + + public: + template + static consteval auto get_completion_signatures() { + return typename get_signatures<::std::remove_cvref_t, Env...>::type{}; + } + struct impls_for : ::beman::execution::detail::default_impls { - struct get_attrs_impl { - auto operator()(const auto& data, const auto& child) const noexcept -> decltype(auto) { - return ::beman::execution::detail::join_env( - ::beman::execution::detail::sched_attrs(data), - ::beman::execution::detail::fwd_env(::beman::execution::get_env(child))); + template + struct upstream_receiver { + using receiver_concept = ::beman::execution::receiver_t; + State* state; + + auto set_value() && noexcept -> void { + 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 (...) { + ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception()); + } } + + template + auto set_error(Error&& err) && noexcept -> void { + ::beman::execution::set_error(std::move(state->receiver), std::forward(err)); + } + + auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(std::move(state->receiver)); } + + auto get_env() const noexcept -> decltype(auto) { + return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver)); + } + }; + + template + struct state_base { + Receiver receiver; + Variant async_result{}; }; - static constexpr auto get_attrs{get_attrs_impl{}}; + + 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>; + operation_t op_state; + + static constexpr bool nothrow() { + return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval()), + receiver_t{nullptr})); + } + explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow()) + : state_base{rcvr}, + op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {} + }; + + struct get_state_impl { + template + requires ::beman::execution::sender_in<::beman::execution::detail::child_type, + ::beman::execution::env_of_t> + auto operator()(Sender&& sender, Receiver& receiver) const { + auto sch{sender.template get<1>()}; + + using sched_t = ::std::remove_cvref_t; + using variant_t = ::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< + ::beman::execution::detail::child_type, + ::beman::execution::env_of_t>>>>>; + + return state_type(sch, receiver); + }; + }; + static constexpr auto get_state{get_state_impl{}}; + + struct complete_impl { + template + auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const noexcept -> void { + using result_t = ::beman::execution::detail::decayed_tuple; + constexpr bool nothrow = ::std::is_nothrow_constructible_v; + + try { + [&]() noexcept(nothrow) { + state.async_result.template emplace(Tag(), std::forward(args)...); + }(); + } catch (...) { + if constexpr (not nothrow) + ::beman::execution::set_error(::std::move(receiver), ::std::current_exception()); + } + + if (state.async_result.index() == 0) + return; + + ::beman::execution::start(state.op_state); + } + }; + static constexpr auto complete{complete_impl{}}; }; }; -/*! - * \brief Get the sender's domain when the sender is continue_on - * \headerfile beman/execution/execution.hpp - * \internal - */ -#ifndef BEMAN_HAS_MODULES -#if 0 -template <::beman::execution::detail::sender_for<::beman::execution::detail::continues_on_t> Sender, typename Env> -auto get_domain_late(Sender&& sender, Env&&) { -#else -template -auto get_domain_late( - const ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>& sender, Env&&) { -#endif - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -#endif } // namespace beman::execution::detail #include namespace beman::execution { using continues_on_t = ::beman::execution::detail::continues_on_t; -/*! - * \brief Customization point object to create a `continues_on` sender. - * \headerfile beman/execution/execution.hpp - */ inline constexpr continues_on_t continues_on{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/default_domain.hpp b/include/beman/execution/detail/default_domain.hpp index faa29f8e..bd92b445 100644 --- a/include/beman/execution/detail/default_domain.hpp +++ b/include/beman/execution/detail/default_domain.hpp @@ -14,81 +14,46 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.queryable; import beman.execution.detail.sender; -import beman.execution.detail.sender_decompose; import beman.execution.detail.tag_of_t; #else #include #include -#include #include #endif // ---------------------------------------------------------------------------- namespace beman::execution { -/*! - * \brief Domain type used when no domain is specified explicitly. - * \headerfile beman/execution/execution.hpp - * - * \details - * The default_domain tries to delegate any of the transformations to a member - * function of the - * tag type of the passed sender. If there is no corresponding member function - * no transformation is applied. - */ + struct default_domain { - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable... Env> - requires(sizeof...(Env) <= 1) && requires(Sender&& sender, Env&&... env) { - ::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...); + template + requires(sizeof...(Env) <= 1) && requires(Sender&& sender, const Env&... env) { + ::beman::execution::tag_of_t().transform_sender(Tag(), ::std::forward(sender), env...); } - static constexpr auto transform_sender(Sender&& sender, Env&&... env) noexcept( - noexcept(::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...))) + static constexpr auto transform_sender(Tag, Sender&& sender, const Env&... env) noexcept(noexcept( + ::beman::execution::tag_of_t().transform_sender(Tag(), ::std::forward(sender), env...))) -> ::beman::execution::sender decltype(auto) { - return ::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...); + return ::beman::execution::tag_of_t().transform_sender(Tag(), ::std::forward(sender), env...); } - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable... Env> - requires(sizeof...(Env) <= 1) && (not requires(Sender&& sender, Env&&... env) { - ::beman::execution::tag_of_t().transform_sender(::std::forward(sender), - ::std::forward(env)...); + template + requires(sizeof...(Env) <= 1) && (not requires(Sender&& sender, const Env&... env) { + ::beman::execution::tag_of_t().transform_sender( + Tag(), ::std::forward(sender), env...); }) - static constexpr auto transform_sender(Sender&& sender, - Env&&...) noexcept(noexcept(::std::forward(sender))) - -> ::beman::execution::sender decltype(auto) { - return ::std::forward(sender); - } - - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env> - requires requires(Sender&& sender, Env&& env) { - ::beman::execution::tag_of_t().transform_env(::std::forward(sender), - ::std::forward(env)); - } - static constexpr auto transform_env(Sender&& sender, Env&& env) noexcept -> ::beman::execution::detail::queryable - decltype(auto) { - return ::beman::execution::tag_of_t().transform_env(::std::forward(sender), - ::std::forward(env)); - } - - template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env> - requires(not requires(Sender&& sender, Env&& env) { - ::beman::execution::tag_of_t().transform_env(::std::forward(sender), - ::std::forward(env)); - }) - static constexpr auto transform_env(Sender&&, Env&& env) noexcept -> ::beman::execution::detail::queryable - decltype(auto) { - return static_cast(::std::forward(env)); + static constexpr auto + transform_sender(Tag, Sender&& sender, const Env&...) noexcept(::std::is_nothrow_constructible_v) + -> Sender { + return static_cast(sender); } template - requires requires(Sender&& sender, Args&&... args) { - Tag().apply_sender(::std::forward(sender), ::std::forward(args)...); + requires requires(Tag tag, Sender&& sender, Args&&... args) { + tag.apply_sender(::std::forward(sender), ::std::forward(args)...); } - static constexpr auto apply_sender(Tag, Sender&& sender, Args&&... args) noexcept(noexcept( - Tag().apply_sender(::std::forward(sender), ::std::forward(args)...))) -> decltype(auto) { - return Tag().apply_sender(::std::forward(sender), ::std::forward(args)...); + static constexpr auto apply_sender(Tag tag, Sender&& sender, Args&&... args) noexcept( + noexcept(tag.apply_sender(::std::forward(sender), ::std::forward(args)...))) -> decltype(auto) { + return tag.apply_sender(::std::forward(sender), ::std::forward(args)...); } }; } // namespace beman::execution diff --git a/include/beman/execution/detail/env.hpp b/include/beman/execution/detail/env.hpp index f1bd293f..86e4ff14 100644 --- a/include/beman/execution/detail/env.hpp +++ b/include/beman/execution/detail/env.hpp @@ -9,13 +9,16 @@ import std; #else #include +#include #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.non_assignable; import beman.execution.detail.queryable; +import beman.execution.detail.type_list; #else #include #include +#include #endif // ---------------------------------------------------------------------------- @@ -26,8 +29,8 @@ struct env_base { Env env_; }; -template -concept has_query = requires(const E& e) { e.query(::std::declval()); }; +template +concept has_query = requires(const E& e) { e.query(::std::declval(), ::std::declval()...); }; template struct find_env; @@ -41,6 +44,19 @@ template struct find_env { using type = typename find_env::type; }; + +template +struct find_env_with_args; +template + requires ::beman::execution::detail::has_query +struct find_env_with_args, E0, E...> { + using type = E0; +}; +template + requires(not ::beman::execution::detail::has_query) +struct find_env_with_args, E0, E...> { + using type = typename find_env_with_args, E...>::type; +}; } // namespace beman::execution::detail // ---------------------------------------------------------------------------- @@ -50,11 +66,13 @@ template <::beman::execution::detail::queryable... Envs> struct env : ::beman::execution::detail::env_base... { [[no_unique_address]] ::beman::execution::detail::non_assignable na_{}; - template - requires(::beman::execution::detail::has_query || ...) - constexpr auto query(Q q) const noexcept -> decltype(auto) { - using E = typename ::beman::execution::detail::find_env::type; - return q(static_cast&>(*this).env_); + template + requires(::beman::execution::detail::has_query || ...) + constexpr auto query(Q q, Args&&... args) const noexcept -> decltype(auto) { + using E = typename ::beman::execution::detail:: + find_env_with_args, Envs...>::type; + return static_cast&>(*this).env_.query( + q, ::std::forward(args)...); } }; diff --git a/include/beman/execution/detail/get_completion_domain.hpp b/include/beman/execution/detail/get_completion_domain.hpp new file mode 100644 index 00000000..a150ba98 --- /dev/null +++ b/include/beman/execution/detail/get_completion_domain.hpp @@ -0,0 +1,96 @@ +// include/beman/execution/detail/get_completion_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_GET_COMPLETION_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.completion_tag; +import beman.execution.detail.default_domain; +import beman.execution.detail.forwarding_query; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.queryable; +import beman.execution.detail.scheduler; +import beman.execution.detail.set_value; +import beman.execution.detail.try_query; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +struct no_completion_domain {}; + +template + requires ::std::same_as || ::beman::execution::detail::completion_tag +struct get_completion_domain_t : ::beman::execution::forwarding_query_t { + template + static auto impl(Q&& q, E&&... e) noexcept { + if constexpr (requires { + ::beman::execution::detail::try_query( + ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + }) { + return ::beman::execution::detail::try_query( + ::std::forward(q), get_completion_domain_t{}, ::std::forward(e)...); + } else if constexpr (::std::same_as) { + return get_completion_domain_t<::beman::execution::set_value_t>::impl(::std::forward(q), + ::std::forward(e)...); + } else if constexpr (requires { + ::beman::execution::detail::try_query( + ::beman::execution::get_completion_scheduler(q, e...), + get_completion_domain_t<::beman::execution::set_value_t>{}, + ::std::forward(q), + ::std::forward(e)...); + }) { + return ::beman::execution::detail::try_query(::beman::execution::get_completion_scheduler(q, e...), + get_completion_domain_t<::beman::execution::set_value_t>{}, + ::std::forward(q), + ::std::forward(e)...); + } else if constexpr (::beman::execution::scheduler && 0u != sizeof...(E)) { + return ::beman::execution::default_domain{}; + } else { + return ::beman::execution::detail::no_completion_domain{}; + } + }; + + template + using domain_of = decltype((impl)(::std::declval(), ::std::declval()...)); + + template <::beman::execution::detail::queryable Q, typename... E> + requires(!::std::same_as, ::beman::execution::detail::no_completion_domain>) + auto operator()(Q&&, E&&...) const noexcept { + using domain = domain_of; + static_assert(noexcept(domain{}), "the domain's default constructor has to be noexcept"); + return domain{}; + } +}; +} // namespace beman::execution::detail + +namespace beman::execution { +template + requires ::std::same_as || ::beman::execution::detail::completion_tag +using get_completion_domain_t = ::beman::execution::detail::get_completion_domain_t; +template + requires ::std::same_as || ::beman::execution::detail::completion_tag +inline constexpr get_completion_domain_t get_completion_domain{}; +} // namespace beman::execution + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/get_completion_scheduler.hpp b/include/beman/execution/detail/get_completion_scheduler.hpp index f5d95e46..de5a67a3 100644 --- a/include/beman/execution/detail/get_completion_scheduler.hpp +++ b/include/beman/execution/detail/get_completion_scheduler.hpp @@ -14,85 +14,81 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.almost_scheduler; import beman.execution.detail.completion_tag; -import beman.execution.detail.decayed_same_as; import beman.execution.detail.forwarding_query; -import beman.execution.detail.get_env; -import beman.execution.detail.schedule; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; +import beman.execution.detail.scheduler; import beman.execution.detail.set_value; #else -#include #include -#include #include -#include -#include -#include -#include +#include #include #endif // ---------------------------------------------------------------------------- -namespace beman::execution { -template -struct get_completion_scheduler_t; +namespace beman::execution::detail { +template +auto recurse_query(Scheduler sch, const Envs&... envs) noexcept; -template -struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { - template - requires(not requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - env.query(self); - }) - auto operator()(Env&&) const noexcept = - BEMAN_EXECUTION_DELETE("The environment needs a query(get_completion_scheduler_t) member"); +template <::beman::execution::detail::completion_tag Tag> +struct get_completion_scheduler_t; - template - requires(requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - env.query(self); - } && (not requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept; - })) - auto operator()(Env&&) const noexcept = - BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to be noexcept"); +template +concept compl_sched_recurse_queryable = requires { + { + ::beman::execution::detail::recurse_query( + ::std::declval().query( + ::std::declval<::beman::execution::detail::get_completion_scheduler_t>(), + ::std::declval()...), + ::std::declval()...) + } -> ::beman::execution::scheduler; +}; - template - requires( - requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - env.query(self); - } && - requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept; - } && - (not requires(const get_completion_scheduler_t& self, - const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self, - const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept -> ::beman::execution::detail::almost_scheduler; - { - ::beman::execution::get_env(::beman::execution::schedule(env.query(self))) - .query(value_self) - } -> ::beman::execution::detail::decayed_same_as; - })) - auto operator()(Env&&) const noexcept = - BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to return a scheduler"); +template <::beman::execution::detail::completion_tag Tag> +struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t { + template + requires ::beman::execution::detail::compl_sched_recurse_queryable || + (::beman::execution::scheduler && sizeof...(E) > 0) + auto operator()(const Q& q, const E&... e) const noexcept; +}; - template - requires requires(const get_completion_scheduler_t& self, - const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self, - const ::std::remove_cvref_t& env) { - { env.query(self) } noexcept -> ::beman::execution::detail::almost_scheduler; - { - ::beman::execution::get_env(::beman::execution::schedule(env.query(self))).query(value_self) - } -> ::beman::execution::detail::decayed_same_as; +template +auto recurse_query(Scheduler sch, const Envs&... envs) noexcept { + ::beman::execution::detail::get_completion_scheduler_t<::beman::execution::set_value_t> get_compl_sch{}; + if constexpr (requires { ::std::as_const(sch).query(get_compl_sch, envs...); }) { + auto sch2 = ::std::as_const(sch).query(get_compl_sch, envs...); + if constexpr (::std::same_as) { + while (sch != sch2) { + sch = ::std::exchange(sch2, ::std::as_const(sch2).query(get_compl_sch, envs...)); + } + return sch; + } else { + return (recurse_query)(sch2, envs...); } - auto operator()(Env&& env) const noexcept { - return ::std::as_const(env).query(*this); + } else { + return sch; } -}; +} + +template <::beman::execution::detail::completion_tag Tag> +template + requires ::beman::execution::detail::compl_sched_recurse_queryable || + (::beman::execution::scheduler && sizeof...(E) > 0) +auto get_completion_scheduler_t::operator()(const Q& q, const E&... e) const noexcept { + if constexpr (::beman::execution::detail::compl_sched_recurse_queryable) { + return ::beman::execution::detail::recurse_query(q.query(*this, e...), e...); + } else { + static_assert(::beman::execution::scheduler && sizeof...(E) > 0); + return q; + } +} + +} // namespace beman::execution::detail +namespace beman::execution { +template <::beman::execution::detail::completion_tag Tag> +using get_completion_scheduler_t = ::beman::execution::detail::get_completion_scheduler_t; template <::beman::execution::detail::completion_tag Tag> inline constexpr get_completion_scheduler_t get_completion_scheduler{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/get_completion_signatures.hpp b/include/beman/execution/detail/get_completion_signatures.hpp index 065a0721..dcf513ce 100644 --- a/include/beman/execution/detail/get_completion_signatures.hpp +++ b/include/beman/execution/detail/get_completion_signatures.hpp @@ -18,7 +18,6 @@ import beman.execution.detail.await_result_type; import beman.execution.detail.completion_signatures; import beman.execution.detail.dependent_sender_error; import beman.execution.detail.env_promise; -import beman.execution.detail.get_domain_late; import beman.execution.detail.is_awaitable; import beman.execution.detail.is_constant; import beman.execution.detail.set_error; @@ -31,7 +30,6 @@ import beman.execution.detail.valid_completion_signatures; #include #include #include -#include #include #include #include @@ -51,10 +49,7 @@ struct get_completion_signatures_new_sender { template struct get_completion_signatures_new_sender { - using type = decltype(::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_late(::std::declval(), ::std::declval()), - ::std::declval(), - ::std::declval())); + using type = decltype(::beman::execution::transform_sender(::std::declval(), ::std::declval())); }; template diff --git a/include/beman/execution/detail/get_domain.hpp b/include/beman/execution/detail/get_domain.hpp index b16b25e1..d774a526 100644 --- a/include/beman/execution/detail/get_domain.hpp +++ b/include/beman/execution/detail/get_domain.hpp @@ -9,41 +9,49 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else +#include #include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; import beman.execution.detail.forwarding_query; +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_scheduler; +import beman.execution.detail.hide_sched; +import beman.execution.detail.set_value; #else +#include #include +#include +#include +#include +#include #endif // ---------------------------------------------------------------------------- -namespace beman::execution { -struct get_domain_t { - template - requires(not requires(Object&& object, const get_domain_t& tag) { - ::std::forward(object).query(tag); - }) && (not requires(Object&& object, const get_domain_t& tag) { ::std::as_const(object).query(tag); }) - auto operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("object needs a query(get_domain_t) overload"); - template - requires(not requires(Object&& object, const get_domain_t& tag) { ::std::as_const(object).query(tag); }) - auto - operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("query(get_domain_t) overload needs to be const"); - template - requires(not requires(Object&& object, const get_domain_t& tag) { - { ::std::as_const(object).query(tag) } noexcept; - }) - auto - operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("query(get_domain_t) overload needs to be noexcept"); - - template - constexpr auto operator()(Object&& object) const noexcept { - return ::std::as_const(object).query(*this); +namespace beman::execution::detail { +struct get_domain_t : ::beman::execution::forwarding_query_t { + template + constexpr auto operator()(Env&& env) const noexcept { + if constexpr (requires { ::std::as_const(env).query(*this); }) { + return ::std::as_const(env).query(*this); + } else if constexpr (requires { + ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( + ::beman::execution::get_scheduler(env), + ::beman::execution::detail::hide_sched(env)); + }) { + return ::beman::execution::get_completion_domain<::beman::execution::set_value_t>( + ::beman::execution::get_scheduler(env), ::beman::execution::detail::hide_sched(env)); + } else { + return ::beman::execution::default_domain{}; + } } - constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; } }; +} // namespace beman::execution::detail +namespace beman::execution { +using get_domain_t = ::beman::execution::detail::get_domain_t; inline constexpr get_domain_t get_domain{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/get_domain_early.hpp b/include/beman/execution/detail/get_domain_early.hpp deleted file mode 100644 index 13e40915..00000000 --- a/include/beman/execution/detail/get_domain_early.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// include/beman/execution/detail/get_domain_early.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_EARLY -#define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_EARLY - -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.completion_domain; -import beman.execution.detail.default_domain; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -#else -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -constexpr auto get_domain_early(const Sender& sender) noexcept { - if constexpr (requires { ::beman::execution::get_domain(::beman::execution::get_env(sender)); }) - return decltype(::beman::execution::get_domain(::beman::execution::get_env(sender))){}; - else if constexpr (requires { ::beman::execution::detail::completion_domain(sender); }) - return decltype(::beman::execution::detail::completion_domain(sender)){}; - else - return ::beman::execution::default_domain{}; -} -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_EARLY diff --git a/include/beman/execution/detail/get_domain_late.hpp b/include/beman/execution/detail/get_domain_late.hpp deleted file mode 100644 index 147c1767..00000000 --- a/include/beman/execution/detail/get_domain_late.hpp +++ /dev/null @@ -1,76 +0,0 @@ -// include/beman/execution/detail/get_domain_late.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_LATE -#define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_LATE - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.completion_domain; -import beman.execution.detail.default_domain; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -import beman.execution.detail.get_scheduler; -import beman.execution.detail.sender_decompose; -import beman.execution.detail.tag_of_t; -#else -#include -#include -#include -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { -template -concept not_void = !::std::same_as; - -template -struct get_domain_late_helper { - template - static constexpr auto get(const Sender& sender, const Env& env) noexcept { - if constexpr (requires { - { - ::beman::execution::get_domain(::beman::execution::get_env(sender)) - } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::get_domain(::beman::execution::get_env(sender)); - else if constexpr (requires { - { - ::beman::execution::detail::completion_domain(sender) - } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::detail::completion_domain(sender); - else if constexpr (requires { - { ::beman::execution::get_domain(env) } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::get_domain(env); - else if constexpr (requires { - { - ::beman::execution::get_domain(::beman::execution::get_scheduler(env)) - } -> ::beman::execution::detail::not_void; - }) - return ::beman::execution::get_domain(::beman::execution::get_scheduler(env)); - else - return ::beman::execution::default_domain(); - } -}; -template -constexpr auto get_domain_late(const Sender& sender, const Env& env) noexcept { - using tag_t = ::beman::execution::tag_of_t; - return ::beman::execution::detail::get_domain_late_helper::get(sender, env); -} -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_GET_DOMAIN_LATE diff --git a/include/beman/execution/detail/get_scheduler.hpp b/include/beman/execution/detail/get_scheduler.hpp index 914cd5ee..a0dc5c50 100644 --- a/include/beman/execution/detail/get_scheduler.hpp +++ b/include/beman/execution/detail/get_scheduler.hpp @@ -12,26 +12,35 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.forwarding_query; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.hide_sched; +import beman.execution.detail.set_value; #else #include +#include +#include +#include #endif // ---------------------------------------------------------------------------- -namespace beman::execution { +namespace beman::execution::detail { struct get_scheduler_t : ::beman::execution::forwarding_query_t { template - requires requires(const get_scheduler_t& self, Env&& env) { ::std::as_const(env).query(self); } + requires requires(const get_scheduler_t& self, Env&& env) { + ::std::as_const(env).query(self); + ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::std::as_const(env).query(self), ::beman::execution::detail::hide_sched(env)); + } auto operator()(Env&& env) const noexcept { - static_assert(noexcept(::std::as_const(env).query(*this))); - //-dk:TODO mandate that the result is a scheduler - // static_assert(::beman::execution::scheduler< - // decltype(::std::as_const(env).query(*this)) - // >) - return ::std::as_const(env).query(*this); + return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( + ::std::as_const(env).query(*this), ::beman::execution::detail::hide_sched(env)); } }; +} // namespace beman::execution::detail +namespace beman::execution { +using get_scheduler_t = ::beman::execution::detail::get_scheduler_t; inline constexpr get_scheduler_t get_scheduler{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/hide_sched.hpp b/include/beman/execution/detail/hide_sched.hpp new file mode 100644 index 00000000..76f38110 --- /dev/null +++ b/include/beman/execution/detail/hide_sched.hpp @@ -0,0 +1,51 @@ +// include/beman/execution/detail/hide_sched.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.queryable; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +struct get_domain_t; +struct get_scheduler_t; + +template <::beman::execution::detail::queryable Q> +struct hide_sched_t { + template + requires requires { ::std::declval().query(::std::declval(), ::std::declval()...); } + auto query(Tag&& tag, Args&&... args) const noexcept -> decltype(auto) { + return q.query(::std::forward(tag), ::std::forward(args)...); + } + + template + auto query(::beman::execution::detail::get_domain_t, Args&&... args) const noexcept -> void = delete; + + template + auto query(::beman::execution::detail::get_scheduler_t, Args&&... args) const noexcept -> void = delete; + + const Q& q; +}; + +template <::beman::execution::detail::queryable Q> +auto hide_sched(const Q& q) noexcept { + return ::beman::execution::detail::hide_sched_t{q}; +} +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_HIDE_SCHED diff --git a/include/beman/execution/detail/indeterminate_domain.hpp b/include/beman/execution/detail/indeterminate_domain.hpp new file mode 100644 index 00000000..6bfde2d5 --- /dev/null +++ b/include/beman/execution/detail/indeterminate_domain.hpp @@ -0,0 +1,84 @@ +// include/beman/execution/detail/indeterminate_domain.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_INDETERMINATE_DOMAIN + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#include +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.default_domain; +import beman.execution.detail.meta.unique; +import beman.execution.detail.queryable; +import beman.execution.detail.sender; +#else +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution { + +template +struct indeterminate_domain { + indeterminate_domain() = default; + + constexpr indeterminate_domain(const auto&) noexcept {} + + template + static constexpr auto transform_sender(Tag tag, Sndr&& sndr, const Env& env) noexcept( + noexcept(::beman::execution::default_domain{}.transform_sender(tag, ::std::forward(sndr), env))) + -> decltype(auto) { + auto make_new_sender = [&]() -> decltype(auto) { + return ::beman::execution::default_domain{}.transform_sender(tag, ::std::forward(sndr), env); + }; + (..., verify_mandates_<::std::decay_t, Domains, Tag, Sndr, Env>()); + return make_new_sender(); + } + + template + static consteval auto verify_mandates_() noexcept -> void { + if constexpr (requires { + ::std::declval().transform_sender( + ::std::declval(), ::std::declval(), ::std::declval()); + }) { + static_assert( + ::std::same_as<::std::decay_t().transform_sender( + ::std::declval(), ::std::declval(), ::std::declval()))>, + Expected>, + "indeterminate_domain: all possible domains must agree on the result " + "type of transform_sender, or be ill-formed for the given (Tag, Sndr, Env)"); + } + } +}; + +} // namespace beman::execution + +template +struct std::common_type<::beman::execution::indeterminate_domain, + ::beman::execution::indeterminate_domain> { + using type = + ::beman::execution::detail::meta::unique<::beman::execution::indeterminate_domain>; +}; + +template +struct std::common_type<::beman::execution::indeterminate_domain, D> { + using type = ::beman::execution::detail::meta::unique<::beman::execution::indeterminate_domain>; +}; + +template +struct std::common_type> + : ::std::common_type<::beman::execution::indeterminate_domain, D> {}; + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/inline_attrs.hpp b/include/beman/execution/detail/inline_attrs.hpp new file mode 100644 index 00000000..5e2988f4 --- /dev/null +++ b/include/beman/execution/detail/inline_attrs.hpp @@ -0,0 +1,43 @@ +// include/beman/execution/detail/inline_attrs.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_INLINE_ATTRS +#define INCLUDED_BEMAN_EXECUTION_DETAIL_INLINE_ATTRS + +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.get_domain; +import beman.execution.detail.get_scheduler; +#else +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { + +template +struct inline_attrs { + template + requires requires(const Env& env) { ::beman::execution::get_scheduler(env); } + constexpr auto query(const ::beman::execution::get_completion_scheduler_t&, const Env& env) const noexcept { + return ::beman::execution::get_scheduler(env); + } + + template + requires requires(const Env& env) { ::beman::execution::get_domain(env); } + constexpr auto query(const ::beman::execution::get_completion_domain_t&, const Env& env) const noexcept { + return ::beman::execution::get_domain(env); + } +}; + +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_INLINE_ATTRS diff --git a/include/beman/execution/detail/inline_scheduler.hpp b/include/beman/execution/detail/inline_scheduler.hpp index ac2d364f..eca5164a 100644 --- a/include/beman/execution/detail/inline_scheduler.hpp +++ b/include/beman/execution/detail/inline_scheduler.hpp @@ -13,7 +13,6 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.sender; import beman.execution.detail.receiver; import beman.execution.detail.set_value; @@ -21,27 +20,22 @@ import beman.execution.detail.operation_state; import beman.execution.detail.scheduler; import beman.execution.detail.scheduler_t; import beman.execution.detail.completion_signatures; +import beman.execution.detail.inline_attrs; #else -#include #include #include #include #include #include #include +#include #endif namespace beman::execution { struct inline_scheduler { using scheduler_concept = ::beman::execution::scheduler_t; - struct env { - static auto - query(const ::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>&) noexcept - -> inline_scheduler { - return {}; - } - }; + using env = ::beman::execution::detail::inline_attrs<::beman::execution::set_value_t>; template <::beman::execution::receiver Rcvr> struct state { diff --git a/include/beman/execution/detail/into_variant.hpp b/include/beman/execution/detail/into_variant.hpp index 167e3892..2a73285c 100644 --- a/include/beman/execution/detail/into_variant.hpp +++ b/include/beman/execution/detail/into_variant.hpp @@ -25,7 +25,6 @@ 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.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -35,7 +34,6 @@ import beman.execution.detail.sends_stopped; import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; -import beman.execution.detail.transform_sender; import beman.execution.detail.value_types_of_t; import beman.execution.detail.variant_or_empty; #else @@ -48,7 +46,6 @@ import beman.execution.detail.variant_or_empty; #include #include #include -#include #include #include #include @@ -57,7 +54,6 @@ import beman.execution.detail.variant_or_empty; #include #include #include -#include #include #endif @@ -67,9 +63,7 @@ namespace beman::execution::detail { struct into_variant_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::sender Sender> auto operator()(Sender&& sender) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sender), - ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender))); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)); } auto operator()() const noexcept { return ::beman::execution::detail::make_sender_adaptor(*this); } diff --git a/include/beman/execution/detail/intrusive_stack.hpp b/include/beman/execution/detail/intrusive_stack.hpp index 276a4d6f..cc258fb8 100644 --- a/include/beman/execution/detail/intrusive_stack.hpp +++ b/include/beman/execution/detail/intrusive_stack.hpp @@ -14,9 +14,6 @@ import std; namespace beman::execution::detail { -template -class atomic_intrusive_stack; - template class intrusive_stack; @@ -24,6 +21,10 @@ class intrusive_stack; template class intrusive_stack { public: + intrusive_stack() = default; + + explicit intrusive_stack(Item* head) noexcept : head_{head} {} + //! @brief Pushes an item to the queue. auto push(Item* item) noexcept -> void { item->*Next = std::exchange(head_, item); } @@ -43,7 +44,6 @@ class intrusive_stack { auto empty() const noexcept -> bool { return !head_; } private: - friend class atomic_intrusive_stack; Item* head_{nullptr}; }; diff --git a/include/beman/execution/detail/let.hpp b/include/beman/execution/detail/let.hpp index 2f3f85e2..23d6e46e 100644 --- a/include/beman/execution/detail/let.hpp +++ b/include/beman/execution/detail/let.hpp @@ -35,7 +35,6 @@ import beman.execution.detail.get_env; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_completion_signatures; import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.join_env; import beman.execution.detail.make_env; @@ -55,7 +54,6 @@ import beman.execution.detail.set_error; import beman.execution.detail.set_stopped; import beman.execution.detail.set_value; import beman.execution.detail.start; -import beman.execution.detail.transform_sender; import beman.execution.detail.type_list; #else #include @@ -69,7 +67,6 @@ import beman.execution.detail.type_list; #include #include #include -#include #include #include #include @@ -87,7 +84,6 @@ import beman.execution.detail.type_list; #include #include #include -#include #include #endif @@ -122,10 +118,7 @@ struct let_t { } template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun> auto operator()(Sender&& sender, Fun&& fun) const { - auto domain(::beman::execution::detail::get_domain_early(sender)); - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender(*this, ::std::forward(fun), std::forward(sender))); + return ::beman::execution::detail::make_sender(*this, ::std::forward(fun), std::forward(sender)); } template diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp index 84341323..25bdf3aa 100644 --- a/include/beman/execution/detail/on.hpp +++ b/include/beman/execution/detail/on.hpp @@ -19,7 +19,6 @@ import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; import beman.execution.detail.get_completion_scheduler; import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_env; import beman.execution.detail.get_scheduler; import beman.execution.detail.join_env; @@ -34,14 +33,12 @@ import beman.execution.detail.sender_for; import beman.execution.detail.set_value; import beman.execution.detail.starts_on; import beman.execution.detail.transform_sender; -import beman.execution.detail.write_env; #else #include #include #include #include #include -#include #include #include #include @@ -53,27 +50,12 @@ import beman.execution.detail.write_env; #include #include #include -#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { struct on_t : ::beman::execution::sender_adaptor_closure { - template <::beman::execution::detail::sender_for OutSndr, typename Env> - auto transform_env(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) { - auto&& data{out_sndr.template get<1>()}; - - if constexpr (::beman::execution::scheduler) - return ::beman::execution::detail::join_env( - ::beman::execution::detail::sched_env(::beman::execution::detail::forward_like(data) - - ), - ::beman::execution::detail::fwd_env(::std::forward(env))); - else - return std::forward(env); - } - template struct env_needs_get_scheduler { using sender_concept = ::beman::execution::sender_t; @@ -84,16 +66,16 @@ struct on_t : ::beman::execution::sender_adaptor_closure { }; template <::beman::execution::detail::sender_for OutSndr, typename Env> - auto transform_sender(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) { - struct not_a_scheduler {}; - // auto&& [_, data, child] = out_sndr; + auto transform_sender(::beman::execution::set_value_t, OutSndr&& out_sndr, const Env& env) const + -> decltype(auto) { + struct not_a_scheduler_t {}; auto&& data = out_sndr.template get<1>(); auto&& child = out_sndr.template get<2>(); if constexpr (::beman::execution::scheduler) { auto sch{::beman::execution::detail::query_with_default( - ::beman::execution::get_scheduler, env, not_a_scheduler{})}; - if constexpr (::std::same_as) { + ::beman::execution::get_scheduler, env, not_a_scheduler_t{})}; + if constexpr (::std::same_as) { return env_needs_get_scheduler{}; } else { return ::beman::execution::continues_on( @@ -103,23 +85,19 @@ struct on_t : ::beman::execution::sender_adaptor_closure { } } else { auto& [sch, closure] = data; - auto orig_sch{::beman::execution::detail::query_with_default( + auto orig_sch{::beman::execution::detail::call_with_default( ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>, + not_a_scheduler_t{}, ::beman::execution::get_env(child), - ::beman::execution::detail::query_with_default( - ::beman::execution::get_scheduler, env, not_a_scheduler{}))}; + env)}; - if constexpr (::std::same_as) { + if constexpr (::std::same_as) { return env_needs_get_scheduler{}; } else { - return ::beman::execution::write_env( - ::beman::execution::continues_on( - ::beman::execution::detail::forward_like(closure)(::beman::execution::continues_on( - ::beman::execution::write_env(::beman::execution::detail::forward_like(child), - ::beman::execution::detail::sched_env(orig_sch)), - sch)), - orig_sch), - ::beman::execution::detail::sched_env(env)); + return ::beman::execution::continues_on( + ::beman::execution::detail::forward_like(closure)(::beman::execution::continues_on( + ::beman::execution::detail::forward_like(child), sch)), + orig_sch); } } } @@ -138,23 +116,16 @@ struct on_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr> auto operator()(Sch&& sch, Sndr&& sndr) const { - auto domain{::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, sch, ::beman::execution::default_domain{})}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender(*this, ::std::forward(sch), ::std::forward(sndr))); + return ::beman::execution::detail::make_sender(*this, ::std::forward(sch), ::std::forward(sndr)); } template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr, ::beman::execution::detail::is_sender_adaptor_closure Closure> auto operator()(Sndr&& sndr, Sch&& sch, Closure&& closure) const { - auto domain{::beman::execution::detail::get_domain_early(sndr)}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, - ::beman::execution::detail::product_type{::std::forward(sch), ::std::forward(closure)}, - ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + *this, + ::beman::execution::detail::product_type{::std::forward(sch), ::std::forward(closure)}, + ::std::forward(sndr)); } template <::beman::execution::scheduler Sch, ::beman::execution::detail::is_sender_adaptor_closure Closure> auto operator()(Sch&& sch, Closure&& closure) const { diff --git a/include/beman/execution/detail/prop.hpp b/include/beman/execution/detail/prop.hpp index a890006c..5918317f 100644 --- a/include/beman/execution/detail/prop.hpp +++ b/include/beman/execution/detail/prop.hpp @@ -52,7 +52,7 @@ struct beman::execution::prop { // auto operator=(prop&&) -> prop& = delete; // auto operator=(const prop&) -> prop& = delete; - constexpr auto query(Query) const noexcept -> const Value& { return this->value_; } + constexpr auto query(Query, auto&&...) const noexcept -> const Value& { return this->value_; } }; // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/query_with_default.hpp b/include/beman/execution/detail/query_with_default.hpp index f6c3b26e..f94f315e 100644 --- a/include/beman/execution/detail/query_with_default.hpp +++ b/include/beman/execution/detail/query_with_default.hpp @@ -26,6 +26,19 @@ query_with_default(Tag, const Env&, Value&& value) noexcept(noexcept(static_cast -> decltype(auto) { return static_cast(std::forward(value)); } + +template + requires requires(const Tag& tag, const Env& env, Args&&... args) { tag(env, ::std::forward(args)...); } +constexpr auto call_with_default(Tag, DefaultValue&&, const Env& env, Args&&... args) noexcept( + noexcept(Tag()(env, ::std::forward(args)...))) -> decltype(auto) { + return Tag()(env, ::std::forward(args)...); +} + +template +constexpr auto call_with_default(Tag, DefaultValue&& value, const Env&, const Args&...) noexcept( + noexcept(static_cast(std::forward(value)))) -> decltype(auto) { + return static_cast(std::forward(value)); +} } // namespace beman::execution::detail // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/sched_attrs.hpp b/include/beman/execution/detail/sched_attrs.hpp deleted file mode 100644 index 1483c5e6..00000000 --- a/include/beman/execution/detail/sched_attrs.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// include/beman/execution/detail/sched_attrs.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SCHED_ATTRS -#define INCLUDED_BEMAN_EXECUTION_DETAIL_SCHED_ATTRS - -#include -#ifdef BEMAN_HAS_IMPORT_STD -import std; -#else -#include -#include -#include -#endif -#ifdef BEMAN_HAS_MODULES -import beman.execution.detail.get_completion_scheduler; -import beman.execution.detail.get_domain; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.set_value; -#else -#include -#include -#include -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace beman::execution::detail { - -template -class sched_attrs { - private: - Scheduler sched; - - public: - template - requires(!::std::same_as>) - explicit sched_attrs(S&& s) : sched(::std::forward(s)) {} - - template - auto query(const ::beman::execution::get_completion_scheduler_t&) const noexcept { - return this->sched; - } - - template - requires requires(Scheduler&& s) { s.query(::beman::execution::get_domain); } - auto query(const ::beman::execution::get_domain_t& q, T = true) const noexcept { - return this->sched.query(q); - } -}; - -template -sched_attrs(Scheduler&&) -> sched_attrs<::std::remove_cvref_t>; -} // namespace beman::execution::detail - -// ---------------------------------------------------------------------------- - -#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_SCHED_ATTRS diff --git a/include/beman/execution/detail/schedule_from.hpp b/include/beman/execution/detail/schedule_from.hpp index cbbb67eb..de361e2b 100644 --- a/include/beman/execution/detail/schedule_from.hpp +++ b/include/beman/execution/detail/schedule_from.hpp @@ -8,244 +8,43 @@ #ifdef BEMAN_HAS_IMPORT_STD import std; #else -#include -#include -#include #include -#include #endif #ifdef BEMAN_HAS_MODULES -import beman.execution.detail.as_tuple; -import beman.execution.detail.basic_sender; import beman.execution.detail.child_type; -import beman.execution.detail.completion_signatures; -import beman.execution.detail.completion_signatures_for; -import beman.execution.detail.completion_signatures_of_t; -import beman.execution.detail.connect; -import beman.execution.detail.connect_result_t; -import beman.execution.detail.decayed_tuple; -import beman.execution.detail.default_domain; -import beman.execution.detail.default_impls; -import beman.execution.detail.env_of_t; -import beman.execution.detail.error_types_of_t; -import beman.execution.detail.fwd_env; import beman.execution.detail.get_completion_signatures; -import beman.execution.detail.get_domain; -import beman.execution.detail.get_env; -import beman.execution.detail.impls_for; -import beman.execution.detail.join_env; import beman.execution.detail.make_sender; -import beman.execution.detail.meta.combine; -import beman.execution.detail.meta.prepend; -import beman.execution.detail.meta.to; -import beman.execution.detail.meta.transform; -import beman.execution.detail.meta.unique; -import beman.execution.detail.query_with_default; -import beman.execution.detail.receiver; -import beman.execution.detail.sched_attrs; -import beman.execution.detail.schedule; -import beman.execution.detail.schedule_result_t; -import beman.execution.detail.scheduler; +import beman.execution.detail.product_type; import beman.execution.detail.sender; -import beman.execution.detail.sender_in; -import beman.execution.detail.set_error; -import beman.execution.detail.set_stopped; -import beman.execution.detail.start; -import beman.execution.detail.transform_sender; #else -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { -struct schedule_from_t { - template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> - auto operator()(Scheduler&& scheduler, Sender&& sender) const { - auto domain{::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, ::std::forward(scheduler), ::std::forward(sender))); - } - - private: - template - struct get_signatures; - template - struct get_signatures< - ::beman::execution::detail::basic_sender<::beman::execution::detail::schedule_from_t, Scheduler, Sender>, - Env> { - using scheduler_sender = decltype(::beman::execution::schedule(::std::declval())); - template - using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>; - using type = ::beman::execution::detail::meta::combine< - decltype(::beman::execution::get_completion_signatures()), - ::beman::execution::error_types_of_t, - ::beman::execution::completion_signatures<::beman::execution::set_error_t( - ::std::exception_ptr)> //-dk:TODO this one should be deduced - >; - }; - public: - template +struct schedule_from_t { + template static consteval auto get_completion_signatures() { - return typename get_signatures, Env...>::type{}; + return ::beman::execution::get_completion_signatures<::beman::execution::detail::child_type, Env...>(); } - struct impls_for : ::beman::execution::detail::default_impls { - template - struct upstream_receiver { - using receiver_concept = ::beman::execution::receiver_t; - State* state; - - auto set_value() && noexcept -> void { - 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 (...) { - ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception()); - } - } - - template - auto set_error(Error&& err) && noexcept -> void { - ::beman::execution::set_error(std::move(state->receiver), std::forward(err)); - } - - auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(std::move(state->receiver)); } - - auto get_env() const noexcept -> decltype(auto) { - return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver)); - } - }; - template - struct state_base { - 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>; - operation_t op_state; - - static constexpr bool nothrow() { - return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval()), - receiver_t{nullptr})); - } - explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow()) - : state_base{rcvr}, - op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {} - }; - - struct get_attrs_impl { - - auto operator()(const auto& data, const auto& child) const noexcept -> decltype(auto) { - return ::beman::execution::detail::join_env( - ::beman::execution::detail::sched_attrs(data), - ::beman::execution::detail::fwd_env(::beman::execution::get_env(child))); - } - }; - static constexpr auto get_attrs{get_attrs_impl{}}; - struct get_state_impl { - template - requires ::beman::execution::sender_in<::beman::execution::detail::child_type, - ::beman::execution::env_of_t> - auto operator()(Sender&& sender, Receiver& receiver) const //-dk:TODO noexcept(see below) - { - auto sch{sender.template get<1>()}; - - using sched_t = ::std::remove_cvref_t; - using variant_t = ::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::detail::meta::combine< - ::beman::execution::completion_signatures_of_t< - ::beman::execution::detail::child_type, - ::beman::execution::env_of_t>, - //-dk:TODO get proper error completion signatures - ::beman::execution::completion_signatures<::beman::execution::set_error_t( - ::std::exception_ptr), - ::beman::execution::set_stopped_t()>>>>>>; - - return state_type(sch, receiver); - }; - }; - static constexpr auto get_state{get_state_impl{}}; - struct complete_impl { - template - auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const noexcept -> void { - using result_t = ::beman::execution::detail::decayed_tuple; - constexpr bool nothrow = ::std::is_nothrow_constructible_v; - - try { - [&]() noexcept(nothrow) { - state.async_result.template emplace(Tag(), std::forward(args)...); - }(); - } catch (...) { - if constexpr (not nothrow) - ::beman::execution::set_error(::std::move(receiver), ::std::current_exception()); - } - - if (state.async_result.index() == 0) - return; - - ::beman::execution::start(state.op_state); - } - }; - static constexpr auto complete{complete_impl{}}; - }; + template <::beman::execution::sender Sender> + auto operator()(Sender&& sender) const { + return ::beman::execution::detail::make_sender( + *this, ::beman::execution::detail::product_type<>{}, ::std::forward(sender)); + } }; } // namespace beman::execution::detail namespace beman::execution { -using schedule_from_t = beman::execution::detail::schedule_from_t; +using schedule_from_t = ::beman::execution::detail::schedule_from_t; inline constexpr ::beman::execution::schedule_from_t schedule_from{}; } // namespace beman::execution diff --git a/include/beman/execution/detail/scheduler.hpp b/include/beman/execution/detail/scheduler.hpp index 5ddd4cde..465304d7 100644 --- a/include/beman/execution/detail/scheduler.hpp +++ b/include/beman/execution/detail/scheduler.hpp @@ -14,18 +14,12 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.almost_scheduler; -import beman.execution.detail.decayed_same_as; -import beman.execution.detail.get_completion_scheduler; -import beman.execution.detail.get_env; import beman.execution.detail.schedule; -import beman.execution.detail.set_value; +import beman.execution.detail.sender; #else #include -#include -#include -#include #include -#include +#include #endif // ---------------------------------------------------------------------------- @@ -33,11 +27,8 @@ import beman.execution.detail.set_value; namespace beman::execution { template concept scheduler = ::beman::execution::detail::almost_scheduler && requires(Scheduler&& sched) { - { - ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>( - ::beman::execution::get_env(::beman::execution::schedule(::std::forward(sched)))) - } -> ::beman::execution::detail::decayed_same_as; -}; + { ::beman::execution::schedule(::std::forward(sched)) } -> ::beman::execution::sender; +} && ::std::equality_comparable<::std::remove_cvref_t> && ::std::copyable<::std::remove_cvref_t>; } // namespace beman::execution // ---------------------------------------------------------------------------- diff --git a/include/beman/execution/detail/split.hpp b/include/beman/execution/detail/split.hpp index a573736d..45b518d3 100644 --- a/include/beman/execution/detail/split.hpp +++ b/include/beman/execution/detail/split.hpp @@ -24,7 +24,6 @@ import beman.execution.detail.connect_result_t; import beman.execution.detail.default_impls; import beman.execution.detail.emplace_from; import beman.execution.detail.error_types_of_t; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_stop_token; import beman.execution.detail.impls_for; import beman.execution.detail.inplace_stop_source; @@ -50,7 +49,6 @@ import beman.execution.detail.value_types_of_t; #include #include #include -#include #include #include #include @@ -366,8 +364,8 @@ struct shared_wrapper { }; struct split_t { - template - auto transform_sender(Sndr&& sndr) const { + template + auto transform_sender(::beman::execution::set_value_t, Sndr&& sndr, const Env&...) const { auto&& child = ::std::forward(sndr).template get<2>(); using child_type = decltype(child); using shared_state = ::beman::execution::detail::impls_for::shared_state; @@ -378,9 +376,7 @@ struct split_t { template requires beman::execution::sender_in::split_env> auto operator()(Sender&& sender) const { - auto domain{::beman::execution::detail::get_domain_early(sender)}; - return ::beman::execution::transform_sender( - domain, ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender))); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)); } private: diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index c7d7c9fc..1719be47 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -12,11 +12,16 @@ import std; #include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.continues_on; import beman.execution.detail.default_domain; +import beman.execution.detail.default_impls; import beman.execution.detail.forward_like; import beman.execution.detail.fwd_env; +import beman.execution.detail.get_completion_domain; import beman.execution.detail.get_domain; +import beman.execution.detail.get_env; import beman.execution.detail.join_env; +import beman.execution.detail.just; import beman.execution.detail.let; import beman.execution.detail.make_sender; import beman.execution.detail.query_with_default; @@ -25,13 +30,20 @@ import beman.execution.detail.schedule; import beman.execution.detail.scheduler; import beman.execution.detail.sender; import beman.execution.detail.sender_for; +import beman.execution.detail.set_value; import beman.execution.detail.transform_sender; #else +#include #include +#include #include #include +#include #include +#include +#include #include +#include #include #include #include @@ -39,39 +51,66 @@ import beman.execution.detail.transform_sender; #include #include #include +#include #include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { + +template +struct starts_on_attrs_t { + Scheduler sch; + ChildEnv child_env; + + template + auto query(::beman::execution::get_completion_domain_t, const Env& rcvr_env) const noexcept { + auto env_for_child = ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(sch), + ::beman::execution::detail::fwd_env(rcvr_env)); + if constexpr (requires { ::beman::execution::get_completion_domain(child_env, env_for_child); }) { + return ::beman::execution::get_completion_domain(child_env, env_for_child); + } else { + return ::beman::execution::default_domain{}; + } + } + + template + requires requires { ::std::as_const(child_env).query(::std::declval(), ::std::declval()...); } + auto query(Q q, Args&&... args) const noexcept { + return ::std::as_const(child_env).query(q, ::std::forward(args)...); + } +}; + struct starts_on_t { template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename Env> - auto transform_env(Sender&& sender, Env&& env) const noexcept { - auto&& scheduler{sender.template get<1>()}; - return ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(scheduler), - ::beman::execution::detail::fwd_env(env)); - } - template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename... Env> - auto transform_sender(Sender&& sender, Env&&...) const noexcept { + auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env&) const noexcept { auto&& scheduler{sender.template get<1>()}; auto&& new_sender{sender.template get<2>()}; return ::beman::execution::let_value( - ::beman::execution::schedule(scheduler), + ::beman::execution::continues_on(::beman::execution::just(), scheduler), [new_sender = ::beman::execution::detail::forward_like(new_sender)]() mutable noexcept( ::std::is_nothrow_move_constructible_v<::std::remove_cvref_t>) { return ::std::move(new_sender); }); } + 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 ::beman::execution::detail::starts_on_attrs_t{ + sch, ::beman::execution::get_env(child)}; + } + }; + static constexpr auto get_attrs{get_attrs_impl{}}; + }; + template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> auto operator()(Scheduler&& scheduler, Sender&& sender) const { - auto domain{::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender( - *this, ::std::forward(scheduler), ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, ::std::forward(scheduler), ::std::forward(sender)); } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/stopped_as_error.hpp b/include/beman/execution/detail/stopped_as_error.hpp index f1ef5965..c5cf8b00 100644 --- a/include/beman/execution/detail/stopped_as_error.hpp +++ b/include/beman/execution/detail/stopped_as_error.hpp @@ -14,7 +14,6 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; import beman.execution.detail.just; import beman.execution.detail.let; import beman.execution.detail.make_sender; @@ -22,10 +21,9 @@ import beman.execution.detail.movable_value; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; -import beman.execution.detail.transform_sender; +import beman.execution.detail.set_value; #else #include -#include #include #include #include @@ -33,13 +31,13 @@ import beman.execution.detail.transform_sender; #include #include #include -#include +#include #endif namespace beman::execution::detail { struct stopped_as_error_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::detail::sender_for Sndr, typename Env> - auto transform_sender(Sndr&& sndr, Env&&) const noexcept { + auto transform_sender(::beman::execution::set_value_t, Sndr&& sndr, Env&&) const noexcept { auto&& data = sndr.template get<1>(); auto&& child = sndr.template get<2>(); using Error = ::std::decay_t; @@ -53,10 +51,8 @@ struct stopped_as_error_t : ::beman::execution::sender_adaptor_closure auto operator()(Sndr&& sndr, Error error) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender( - stopped_as_error_t{}, std::move(error), ::std::forward(sndr))); + return ::beman::execution::detail::make_sender( + stopped_as_error_t{}, std::move(error), ::std::forward(sndr)); } template <::beman::execution::detail::movable_value Error> diff --git a/include/beman/execution/detail/stopped_as_optional.hpp b/include/beman/execution/detail/stopped_as_optional.hpp index 0f78efee..ab1ed114 100644 --- a/include/beman/execution/detail/stopped_as_optional.hpp +++ b/include/beman/execution/detail/stopped_as_optional.hpp @@ -17,37 +17,35 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.child_type; import beman.execution.detail.fwd_env; -import beman.execution.detail.get_domain_early; import beman.execution.detail.just; import beman.execution.detail.let; import beman.execution.detail.make_sender; import beman.execution.detail.sender; import beman.execution.detail.sender_adaptor_closure; import beman.execution.detail.sender_for; +import beman.execution.detail.set_value; import beman.execution.detail.single_sender; import beman.execution.detail.single_sender_value_type; import beman.execution.detail.then; -import beman.execution.detail.transform_sender; #else #include #include -#include #include #include #include #include #include #include +#include #include #include #include -#include #endif namespace beman::execution::detail { struct stopped_as_optional_t : ::beman::execution::sender_adaptor_closure { template <::beman::execution::detail::sender_for Sndr, typename Env> - auto transform_sender(Sndr&& sndr, Env&&) const noexcept { + auto transform_sender(::beman::execution::set_value_t, Sndr&& sndr, Env&&) const noexcept { static_assert( ::beman::execution::detail::single_sender, ::beman::execution::detail::fwd_env>, "sender must be a single sender"); @@ -66,9 +64,7 @@ struct stopped_as_optional_t : ::beman::execution::sender_adaptor_closure auto operator()(Sndr&& sndr) const { - return ::beman::execution::transform_sender( - ::beman::execution::detail::get_domain_early(sndr), - ::beman::execution::detail::make_sender(stopped_as_optional_t{}, {}, ::std::forward(sndr))); + return ::beman::execution::detail::make_sender(stopped_as_optional_t{}, {}, ::std::forward(sndr)); } auto operator()() const noexcept { return ::beman::execution::detail::make_sender_adaptor(*this); } diff --git a/include/beman/execution/detail/sync_wait.hpp b/include/beman/execution/detail/sync_wait.hpp index 253b52d6..037137d9 100644 --- a/include/beman/execution/detail/sync_wait.hpp +++ b/include/beman/execution/detail/sync_wait.hpp @@ -16,29 +16,31 @@ import std; #ifdef BEMAN_HAS_MODULES import beman.execution.detail.apply_sender; import beman.execution.detail.as_except_ptr; +import beman.execution.detail.compl_domain; import beman.execution.detail.connect; import beman.execution.detail.decayed_tuple; +import beman.execution.detail.default_domain; import beman.execution.detail.get_delegation_scheduler; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_scheduler; import beman.execution.detail.receiver; import beman.execution.detail.run_loop; import beman.execution.detail.sender_in; -import beman.execution.detail.sender_in; +import beman.execution.detail.set_value; import beman.execution.detail.start; import beman.execution.detail.value_types_of_t; #else #include #include +#include #include #include +#include #include -#include #include #include #include #include -#include +#include #include #include #endif @@ -115,14 +117,16 @@ struct sync_wait_t { typename ::beman::execution::detail::sync_wait_result_type; { ::beman::execution::apply_sender( - ::beman::execution::detail::get_domain_early(std::forward(sender)), + ::beman::execution::detail::compl_domain<::beman::execution::set_value_t>( + sender, ::beman::execution::detail::sync_wait_env{}), self, ::std::forward(sender)) } -> ::std::same_as<::beman::execution::detail::sync_wait_result_type>; } auto operator()(Sender&& sender) const { - auto domain{::beman::execution::detail::get_domain_early(sender)}; - return ::beman::execution::apply_sender(domain, *this, ::std::forward(sender)); + auto dom = ::beman::execution::detail::compl_domain<::beman::execution::set_value_t>( + sender, ::beman::execution::detail::sync_wait_env{}); + return ::beman::execution::apply_sender(dom, *this, ::std::forward(sender)); } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/detail/sync_wait_with_variant.hpp b/include/beman/execution/detail/sync_wait_with_variant.hpp index cf2753fc..20a6d7dc 100644 --- a/include/beman/execution/detail/sync_wait_with_variant.hpp +++ b/include/beman/execution/detail/sync_wait_with_variant.hpp @@ -16,18 +16,22 @@ import std; import beman.execution.detail.apply_sender; import beman.execution.detail.callable; import beman.execution.detail.call_result_t; -import beman.execution.detail.get_domain_early; +import beman.execution.detail.compl_domain; +import beman.execution.detail.default_domain; import beman.execution.detail.into_variant; import beman.execution.detail.sender_in; +import beman.execution.detail.set_value; import beman.execution.detail.sync_wait; import beman.execution.detail.value_types_of_t; #else #include #include #include -#include +#include +#include #include #include +#include #include #include #endif @@ -59,8 +63,9 @@ struct sync_wait_with_variant_t { template requires requires { typename ::beman::execution::detail::sync_wait_with_variant_result_type; } auto operator()(Sndr&& sndr) const { - return ::beman::execution::apply_sender( - ::beman::execution::detail::get_domain_early(sndr), *this, ::std::forward(sndr)); + auto dom = ::beman::execution::detail::compl_domain<::beman::execution::set_value_t>( + sndr, ::beman::execution::detail::sync_wait_env{}); + return ::beman::execution::apply_sender(dom, *this, ::std::forward(sndr)); } }; diff --git a/include/beman/execution/detail/then.hpp b/include/beman/execution/detail/then.hpp index e6fd17b4..7c6b672b 100644 --- a/include/beman/execution/detail/then.hpp +++ b/include/beman/execution/detail/then.hpp @@ -24,7 +24,6 @@ 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.get_domain_early; import beman.execution.detail.impls_for; import beman.execution.detail.make_sender; import beman.execution.detail.meta.combine; @@ -47,7 +46,6 @@ import beman.execution.detail.transform_sender; #include #include #include -#include #include #include #include @@ -119,10 +117,8 @@ struct then_t : ::beman::execution::sender_adaptor_closure> { auto operator()(Sender&& sender, Fun&& fun) const noexcept(::std::is_nothrow_constructible_v<::std::remove_cvref_t, Sender> && ::std::is_nothrow_constructible_v<::std::remove_cvref_t, Fun>) { - auto domain{::beman::execution::detail::get_domain_early(sender)}; - return ::beman::execution::transform_sender( - domain, - ::beman::execution::detail::make_sender(*this, ::std::forward(fun), ::std::forward(sender))); + return ::beman::execution::detail::make_sender( + *this, ::std::forward(fun), ::std::forward(sender)); } template <::beman::execution::sender Sender, typename Env> requires ::beman::execution::detail::nested_sender_has_affine_on diff --git a/include/beman/execution/detail/transform_sender.hpp b/include/beman/execution/detail/transform_sender.hpp index 491172e5..cd912c42 100644 --- a/include/beman/execution/detail/transform_sender.hpp +++ b/include/beman/execution/detail/transform_sender.hpp @@ -1,5 +1,5 @@ -// include/beman/execution/detail/transform_sender.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// include/beman/execution/detail/transform_sender.hpp _*_C++_*_ +// SPDX_License_Identifier: Apache_2.0 WITH LLVM_exception #ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_TRANSFORM_SENDER #define INCLUDED_BEMAN_EXECUTION_DETAIL_TRANSFORM_SENDER @@ -9,127 +9,80 @@ import std; #else #include +#include #include #endif #ifdef BEMAN_HAS_MODULES +import beman.execution.detail.compl_domain; +import beman.execution.detail.decayed_same_as; import beman.execution.detail.default_domain; +import beman.execution.detail.get_domain; import beman.execution.detail.sender; +import beman.execution.detail.set_value; +import beman.execution.detail.start; #else +#include +#include #include +#include #include +#include +#include #endif // ---------------------------------------------------------------------------- namespace beman::execution::detail { -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain, Sender&& sender, const Env&...) noexcept -> ::beman::execution::sender auto { - return ::std::forward(sender); -} - -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (!::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept -> ::beman::execution::sender - decltype(auto) { - return ::beman::execution::detail::transform_sender( - dom, dom.transform_sender(::std::forward(sender), env...), env...); -} -template - requires(not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && ::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>> -constexpr auto - transform_sender(Domain, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward(sender))) - -> ::beman::execution::sender auto { - return sender; -} +template +struct transform_sndr_recurse { + template + using domain_t = ::std::conditional_t().transform_sender( + ::std::declval(), ::std::declval(), ::std::declval()); + }, Domain, ::beman::execution::default_domain>; -template - requires(not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && - (!::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept(noexcept( - ::beman::execution::default_domain{}.transform_sender(::std::declval(), ::std::declval()...))) - -> ::beman::execution::sender decltype(auto) { - return ::beman::execution::detail::transform_sender( - dom, ::beman::execution::default_domain{}.transform_sender(::std::forward(sender), env...), env...); -} -} // namespace beman::execution::detail + template + using new_sndr_t = + decltype(domain_t().transform_sender(Tag(), ::std::declval(), ::std::declval())); -namespace beman::execution { -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain, Sender&& sender, const Env&...) noexcept -> ::beman::execution::sender - decltype(auto) { - return ::std::forward(sender); -} + constexpr transform_sndr_recurse(Domain, Tag) noexcept {} -template - requires(sizeof...(Env) < 2) && - requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - } && - (!::std::same_as<::std::remove_cvref_t, - std::remove_cvref_t().transform_sender( - ::std::declval(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept -> ::beman::execution::sender - auto { - return ::beman::execution::detail::transform_sender( - dom, dom.transform_sender(::std::forward(sender), env...), env...); -} + template + requires ::beman::execution::detail::decayed_same_as, Sndr> + auto operator()(Sndr&& sndr, const Env& env) const -> decltype(auto) { + return domain_t().transform_sender(Tag(), ::std::forward(sndr), env); + } -template - requires(sizeof...(Env) < 2) && (not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && - ::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>> -constexpr auto - transform_sender(Domain, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward(sender))) - -> ::beman::execution::sender decltype(auto) { - return ::std::forward(sender); -} + template + auto operator()(Sndr&& sndr, const Env& env) const -> decltype(auto) { + auto next_domain = [&] { + if constexpr (::std::same_as) { + static_assert( + ::beman::execution::detail::decayed_same_as); + return ::beman::execution::get_domain(env); + } else { + using compl_domain_t = ::beman::execution::detail::compl_domain_of_t, Env>; + return compl_domain_t(); + } + }(); + const auto next_transform = ::beman::execution::detail::transform_sndr_recurse{next_domain, Tag()}; + return next_transform(domain_t().transform_sender(Tag(), ::std::forward(sndr), env), env); + } +}; +} // namespace beman::execution::detail -template - requires(sizeof...(Env) < 2) && (not requires(Domain dom, Sender&& sender, const Env&... env) { - dom.transform_sender(::std::forward(sender), env...); - }) && - (!::std::same_as<::std::remove_cvref_t, - ::std::remove_cvref_t(), ::std::declval()...))>>) -constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept( - noexcept(::beman::execution::detail::transform_sender( - dom, - ::beman::execution::default_domain{}.transform_sender(::std::declval(), ::std::declval()...), - env...))) -> ::beman::execution::sender decltype(auto) { - return ::beman::execution::detail::transform_sender( - dom, ::beman::execution::default_domain{}.transform_sender(::std::forward(sender), env...), env...); +namespace beman::execution { +template <::beman::execution::sender Sndr, typename Env> +auto transform_sender(Sndr&& sndr, const Env& env) -> ::beman::execution::sender decltype(auto) { + const auto starting_domain = ::beman::execution::get_domain(env); + const auto completion_domain = ::beman::execution::detail::compl_domain(sndr, env); + const auto starting_transform = + ::beman::execution::detail::transform_sndr_recurse(starting_domain, ::beman::execution::start); + const auto complete_transform = + ::beman::execution::detail::transform_sndr_recurse(completion_domain, ::beman::execution::set_value); + return starting_transform(complete_transform(::std::forward(sndr), env), env); } } // namespace beman::execution diff --git a/include/beman/execution/detail/try_query.hpp b/include/beman/execution/detail/try_query.hpp new file mode 100644 index 00000000..60bff1ae --- /dev/null +++ b/include/beman/execution/detail/try_query.hpp @@ -0,0 +1,42 @@ +// include/beman/execution/detail/try_query.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_TRY_QUERY +#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_TRY_QUERY + +#include +#ifdef BEMAN_HAS_IMPORT_STD +import std; +#else +#include +#endif +#if BEMAN_HAS_MODULES +import beman.execution.detail.queryable; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace beman::execution::detail { +template <::beman::execution::detail::queryable Q, typename Tag, typename... Args> + requires requires(const Q& q, Tag&& tag, Args&&... args) { + q.query(::std::forward(tag), ::std::forward(args)...); + } +auto try_query(const Q& q, Tag&& tag, Args&&... args) noexcept -> decltype(auto) { + return q.query(::std::forward(tag), ::std::forward(args)...); +} + +template <::beman::execution::detail::queryable Q, typename Tag, typename... Args> + requires( + not requires(const Q& q, Tag&& tag, Args&&... args) { + q.query(::std::forward(tag), ::std::forward(args)...); + } && requires(const Q& q, Tag&& tag) { q.query(::std::forward(tag)); }) +auto try_query(const Q& q, Tag&& tag, Args&&...) noexcept -> decltype(auto) { + return q.query(::std::forward(tag)); +} +} // namespace beman::execution::detail + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution/detail/when_all.hpp b/include/beman/execution/detail/when_all.hpp index ec6ab4be..37564da5 100644 --- a/include/beman/execution/detail/when_all.hpp +++ b/include/beman/execution/detail/when_all.hpp @@ -33,7 +33,6 @@ import beman.execution.detail.env_of_t; import beman.execution.detail.error_types_of_t; import beman.execution.detail.get_env; import beman.execution.detail.get_domain; -import beman.execution.detail.get_domain_early; import beman.execution.detail.get_stop_token; import beman.execution.detail.impls_for; import beman.execution.detail.inplace_stop_source; @@ -73,7 +72,6 @@ import beman.execution.detail.value_types_of_t; #include #include #include -#include #include #include #include @@ -136,15 +134,9 @@ static_assert(std::same_as<::beman::execution::inplace_stop_token, struct when_all_t { template <::beman::execution::sender... Sender> - requires(0u != sizeof...(Sender)) && (... && beman::execution::detail::valid_when_all_sender) && - requires(Sender&&... s) { - typename ::std::common_type_t; - } + requires(0u != sizeof...(Sender)) && (... && beman::execution::detail::valid_when_all_sender) auto operator()(Sender&&... sender) const { - using common_t = - typename ::std::common_type_t; - return ::beman::execution::transform_sender( - common_t(), ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...)); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...); } private: @@ -186,14 +178,7 @@ struct when_all_t { struct impls_for : ::beman::execution::detail::default_impls { struct get_attrs_impl { - auto operator()(auto&&, auto&&... sender) const { - using common_t = - typename ::std::common_type_t; - if constexpr (::std::same_as) - return ::beman::execution::env<>{}; - else - return ::beman::execution::detail::make_env(::beman::execution::get_domain, common_t{}); - } + auto operator()(auto&&, auto&&...) const { return ::beman::execution::env<>{}; } }; static constexpr auto get_attrs{get_attrs_impl{}}; struct get_env_impl { diff --git a/include/beman/execution/detail/when_all_with_variant.hpp b/include/beman/execution/detail/when_all_with_variant.hpp index 11eaf69d..22c4a7e9 100644 --- a/include/beman/execution/detail/when_all_with_variant.hpp +++ b/include/beman/execution/detail/when_all_with_variant.hpp @@ -13,21 +13,19 @@ import std; #endif #ifdef BEMAN_HAS_MODULES import beman.execution.detail.forward_like; -import beman.execution.detail.get_domain_early; 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.transform_sender; +import beman.execution.detail.set_value; import beman.execution.detail.when_all; #else #include -#include #include #include #include #include -#include +#include #include #endif @@ -35,9 +33,8 @@ import beman.execution.detail.when_all; namespace beman::execution::detail { struct when_all_with_variant_t { - // template <::beman::execution::detail::sender_for Sender> - template <::beman::execution::sender Sender> - auto transform_sender(Sender&& sender, auto&&...) const noexcept { + template <::beman::execution::detail::sender_for Sender, typename Env> + auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env&) const noexcept { return ::std::forward(sender).apply([](auto&&, auto&&, auto&&... child) { return ::beman::execution::when_all( ::beman::execution::into_variant(::beman::execution::detail::forward_like(child))...); @@ -46,10 +43,7 @@ struct when_all_with_variant_t { template <::beman::execution::sender... Sender> auto operator()(Sender&&... sender) const { - using domain_t = - typename ::std::common_type_t; - return ::beman::execution::transform_sender( - domain_t{}, ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...)); + return ::beman::execution::detail::make_sender(*this, {}, ::std::forward(sender)...); } }; } // namespace beman::execution::detail diff --git a/include/beman/execution/execution.hpp b/include/beman/execution/execution.hpp index 5f526386..b0c6f02a 100644 --- a/include/beman/execution/execution.hpp +++ b/include/beman/execution/execution.hpp @@ -24,6 +24,7 @@ import beman.execution.detail.execution_policy; import beman.execution.detail.forwarding_query; import beman.execution.detail.get_allocator; import beman.execution.detail.get_await_completion_adaptor; +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_delegation_scheduler; @@ -32,6 +33,7 @@ import beman.execution.detail.get_forward_progress_guarantee; import beman.execution.detail.get_env; import beman.execution.detail.get_scheduler; import beman.execution.detail.get_stop_token; +import beman.execution.detail.indeterminate_domain; import beman.execution.detail.inline_scheduler; import beman.execution.detail.into_variant; import beman.execution.detail.just; @@ -86,6 +88,7 @@ import beman.execution.detail.write_env; #include #include #include +#include #include #include #include @@ -94,6 +97,7 @@ import beman.execution.detail.write_env; #include #include #include +#include #include #include #include diff --git a/src/beman/execution/CMakeLists.txt b/src/beman/execution/CMakeLists.txt index 674d52c5..a24ace03 100644 --- a/src/beman/execution/CMakeLists.txt +++ b/src/beman/execution/CMakeLists.txt @@ -46,7 +46,8 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/child_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/class_type.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/common.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_domain.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/common_domain.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/compl_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signature.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/completion_signatures_for.hpp @@ -84,22 +85,24 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_allocator.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_await_completion_adaptor.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_awaiter.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_completion_signatures.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_delegation_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_domain.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_domain_early.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_domain_late.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_forward_progress_guarantee.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/get_scheduler.hpp ${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_sched.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/immovable.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/impls_for.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indeterminate_domain.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indices_for.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/indirect_meta_apply.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inline_attrs.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inline_scheduler.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/inplace_stop_source.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/into_variant.hpp @@ -141,7 +144,6 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/receiver.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/receiver_of.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/run_loop.hpp - ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sched_attrs.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/sched_env.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/schedule.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/schedule_from.hpp @@ -190,6 +192,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/tag_of_t.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/then.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/transform_sender.hpp + ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/try_query.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/type_list.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/unspecified_promise.hpp ${PROJECT_SOURCE_DIR}/include/beman/execution/detail/unstoppable.hpp @@ -238,7 +241,8 @@ if(BEMAN_USE_MODULES) check_type_alias_exist.cppm child_type.cppm class_type.cppm - completion_domain.cppm + common_domain.cppm + compl_domain.cppm completion_signature.cppm completion_signatures_for.cppm completion_signatures_of_t.cppm @@ -277,11 +281,10 @@ if(BEMAN_USE_MODULES) get_allocator.cppm get_await_completion_adaptor.cppm get_awaiter.cppm + get_completion_domain.cppm get_completion_scheduler.cppm get_completion_signatures.cppm get_delegation_scheduler.cppm - get_domain_early.cppm - get_domain_late.cppm get_domain.cppm get_env.cppm get_forward_progress_guarantee.cppm @@ -289,10 +292,13 @@ if(BEMAN_USE_MODULES) get_stop_token.cppm has_as_awaitable.cppm has_completions.cppm + hide_sched.cppm immovable.cppm impls_for.cppm + indeterminate_domain.cppm indices_for.cppm indirect_meta_apply.cppm + inline_attrs.cppm inline_scheduler.cppm inplace_stop_source.cppm into_variant.cppm @@ -335,7 +341,6 @@ if(BEMAN_USE_MODULES) receiver_of.cppm receiver.cppm run_loop.cppm - sched_attrs.cppm sched_env.cppm schedule_from.cppm schedule_result_t.cppm @@ -383,6 +388,7 @@ if(BEMAN_USE_MODULES) tag_of_t.cppm then.cppm transform_sender.cppm + try_query.cppm type_list.cppm unspecified_promise.cppm unstoppable.cppm @@ -392,8 +398,8 @@ if(BEMAN_USE_MODULES) valid_specialization.cppm value_types_of_t.cppm variant_or_empty.cppm - when_all_with_variant.cppm when_all.cppm + when_all_with_variant.cppm with_await_transform.cppm with_awaitable_senders.cppm write_env.cppm diff --git a/src/beman/execution/common_domain.cppm b/src/beman/execution/common_domain.cppm new file mode 100644 index 00000000..33e28967 --- /dev/null +++ b/src/beman/execution/common_domain.cppm @@ -0,0 +1,12 @@ +module; +// src/beman/execution/common_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.common_domain; + +namespace beman::execution::detail { +export using beman::execution::detail::common_domain_t; +export using beman::execution::detail::common_domain; +} // namespace beman::execution::detail diff --git a/src/beman/execution/compl_domain.cppm b/src/beman/execution/compl_domain.cppm new file mode 100644 index 00000000..bd4dc9c1 --- /dev/null +++ b/src/beman/execution/compl_domain.cppm @@ -0,0 +1,12 @@ +module; +// src/beman/execution/compl_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.compl_domain; + +namespace beman::execution::detail { +export using beman::execution::detail::compl_domain; +export using beman::execution::detail::compl_domain_of_t; +} // namespace beman::execution::detail diff --git a/src/beman/execution/completion_domain.cppm b/src/beman/execution/completion_domain.cppm deleted file mode 100644 index 64b933bb..00000000 --- a/src/beman/execution/completion_domain.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/completion_domain.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.completion_domain; - -namespace beman::execution::detail { -export using beman::execution::detail::completion_domain; -} // namespace beman::execution::detail diff --git a/src/beman/execution/continues_on.cppm b/src/beman/execution/continues_on.cppm index 38b22d7a..d222dd4e 100644 --- a/src/beman/execution/continues_on.cppm +++ b/src/beman/execution/continues_on.cppm @@ -10,27 +10,3 @@ namespace beman::execution { export using beman::execution::continues_on_t; export using beman::execution::continues_on; } // namespace beman::execution - -namespace beman::execution::detail { -export template -auto get_domain_late( - const ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>& sender, Env&&) { - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -export template -auto get_domain_late( - ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>&& sender, Env&&) { - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -export template -auto get_domain_late( - ::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, T...>& sender, Env&&) { - auto scheduler{sender.template get<1>()}; - return ::beman::execution::detail::query_with_default( - ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{}); -} -} // namespace beman::execution::detail diff --git a/src/beman/execution/execution-detail.cppm b/src/beman/execution/execution-detail.cppm index 568be1bb..36f1328c 100644 --- a/src/beman/execution/execution-detail.cppm +++ b/src/beman/execution/execution-detail.cppm @@ -14,7 +14,7 @@ export import beman.execution.detail.basic_state; export import beman.execution.detail.call_result_t; export import beman.execution.detail.callable; export import beman.execution.detail.child_type; -export import beman.execution.detail.completion_domain; +export import beman.execution.detail.compl_domain; export import beman.execution.detail.completion_signature; export import beman.execution.detail.completion_signatures_for; export import beman.execution.detail.completion_tag; @@ -32,14 +32,14 @@ export import beman.execution.detail.forward_like; export import beman.execution.detail.fwd_env; export import beman.execution.detail.gather_signatures; export import beman.execution.detail.get_awaiter; -export import beman.execution.detail.get_domain_early; -export import beman.execution.detail.get_domain_late; export import beman.execution.detail.has_as_awaitable; export import beman.execution.detail.has_completions; export import beman.execution.detail.immovable; export import beman.execution.detail.impls_for; export import beman.execution.detail.indices_for; export import beman.execution.detail.indirect_meta_apply; +export import beman.execution.detail.inline_attrs; +export import beman.execution.detail.inline_scheduler; export import beman.execution.detail.is_awaitable; export import beman.execution.detail.is_awaiter; export import beman.execution.detail.is_sender; @@ -62,7 +62,6 @@ export import beman.execution.detail.operation_state_task; export import beman.execution.detail.product_type; export import beman.execution.detail.query_with_default; export import beman.execution.detail.queryable; -export import beman.execution.detail.sched_attrs; export import beman.execution.detail.sched_env; export import beman.execution.detail.sender; export import beman.execution.detail.sender_adaptor_closure; diff --git a/src/beman/execution/execution.cppm b/src/beman/execution/execution.cppm index 3de60d3c..3ad8c982 100644 --- a/src/beman/execution/execution.cppm +++ b/src/beman/execution/execution.cppm @@ -20,6 +20,7 @@ export import beman.execution.detail.connect_result_t; // [exec.connect], the co import beman.execution.detail.continues_on; import beman.execution.detail.counting_scope; import beman.execution.detail.default_domain; +export import beman.execution.detail.indeterminate_domain; export import beman.execution.detail.env; export import beman.execution.detail.env_of_t; export import beman.execution.detail.error_types_of_t; // [exec.getcomplsigs], completion signatures @@ -27,6 +28,7 @@ export import beman.execution.detail.execution_policy; import beman.execution.detail.forwarding_query; import beman.execution.detail.get_allocator; import beman.execution.detail.get_await_completion_adaptor; +export import beman.execution.detail.get_completion_domain; export import beman.execution.detail.get_completion_scheduler; export import beman.execution.detail.get_completion_signatures; // [exec.getcomplsigs], completion signatures import beman.execution.detail.get_delegation_scheduler; diff --git a/src/beman/execution/get_completion_domain.cppm b/src/beman/execution/get_completion_domain.cppm new file mode 100644 index 00000000..98d1fc8b --- /dev/null +++ b/src/beman/execution/get_completion_domain.cppm @@ -0,0 +1,12 @@ +module; +// src/beman/execution/get_completion_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.get_completion_domain; + +namespace beman::execution { +export using beman::execution::get_completion_domain_t; +export using beman::execution::get_completion_domain; +} // namespace beman::execution diff --git a/src/beman/execution/get_domain_early.cppm b/src/beman/execution/get_domain_early.cppm deleted file mode 100644 index 05fb99f9..00000000 --- a/src/beman/execution/get_domain_early.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/get_domain_early.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.get_domain_early; - -namespace beman::execution::detail { -export using beman::execution::detail::get_domain_early; -} // namespace beman::execution::detail diff --git a/src/beman/execution/get_domain_late.cppm b/src/beman/execution/get_domain_late.cppm deleted file mode 100644 index 35296e11..00000000 --- a/src/beman/execution/get_domain_late.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/get_domain_late.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.get_domain_late; - -namespace beman::execution::detail { -export using beman::execution::detail::get_domain_late; -} // namespace beman::execution::detail diff --git a/src/beman/execution/hide_sched.cppm b/src/beman/execution/hide_sched.cppm new file mode 100644 index 00000000..2a2dac47 --- /dev/null +++ b/src/beman/execution/hide_sched.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/hide_sched.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.hide_sched; + +namespace beman::execution::detail { +export using beman::execution::detail::hide_sched; +} // namespace beman::execution::detail diff --git a/src/beman/execution/indeterminate_domain.cppm b/src/beman/execution/indeterminate_domain.cppm new file mode 100644 index 00000000..cb66d9b1 --- /dev/null +++ b/src/beman/execution/indeterminate_domain.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/indeterminate_domain.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.indeterminate_domain; + +namespace beman::execution { +export using beman::execution::indeterminate_domain; +} // namespace beman::execution diff --git a/src/beman/execution/inline_attrs.cppm b/src/beman/execution/inline_attrs.cppm new file mode 100644 index 00000000..70bc9e5d --- /dev/null +++ b/src/beman/execution/inline_attrs.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/inline_attrs.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.inline_attrs; + +namespace beman::execution::detail { +export using beman::execution::detail::inline_attrs; +} // namespace beman::execution::detail diff --git a/src/beman/execution/query_with_default.cppm b/src/beman/execution/query_with_default.cppm index 132bdece..bb348f29 100644 --- a/src/beman/execution/query_with_default.cppm +++ b/src/beman/execution/query_with_default.cppm @@ -8,4 +8,5 @@ export module beman.execution.detail.query_with_default; namespace beman::execution::detail { export using beman::execution::detail::query_with_default; +export using beman::execution::detail::call_with_default; } // namespace beman::execution::detail diff --git a/src/beman/execution/sched_attrs.cppm b/src/beman/execution/sched_attrs.cppm deleted file mode 100644 index d55e2eae..00000000 --- a/src/beman/execution/sched_attrs.cppm +++ /dev/null @@ -1,11 +0,0 @@ -module; -// src/beman/execution/sched_attrs.cppm -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include - -export module beman.execution.detail.sched_attrs; - -namespace beman::execution::detail { -export using beman::execution::detail::sched_attrs; -} // namespace beman::execution::detail diff --git a/src/beman/execution/try_query.cppm b/src/beman/execution/try_query.cppm new file mode 100644 index 00000000..f0f4c4ee --- /dev/null +++ b/src/beman/execution/try_query.cppm @@ -0,0 +1,11 @@ +module; +// src/beman/execution/try_query.cppm -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +export module beman.execution.detail.try_query; + +namespace beman::execution::detail { +export using beman::execution::detail::try_query; +} // namespace beman::execution::detail diff --git a/tests/beman/execution/CMakeLists.txt b/tests/beman/execution/CMakeLists.txt index 08530378..0dd5cb4f 100644 --- a/tests/beman/execution/CMakeLists.txt +++ b/tests/beman/execution/CMakeLists.txt @@ -22,10 +22,12 @@ list( exec-general.test exec-getcomplsigs.test exec-get-allocator.test + exec-get-compl-domain.test exec-get-compl-sched.test exec-get-delegation-scheduler.test exec-get-domain.test exec-get-env.test + exec-inline-scheduler.test exec-get-scheduler.test exec-get-stop-token.test exec-into-variant.test @@ -35,13 +37,13 @@ list( exec-opstate-start.test exec-opstate.test exec-prop.test + exec-queries-expos.test exec-read-env.test exec-recv-concepts.test exec-recv.test exec-run-loop-general.test exec-run-loop-types.test exec-sched.test - exec-schedule-from.test exec-schedule.test exec-scope-concepts.test exec-scope-counting.test diff --git a/tests/beman/execution/exec-affine-on.test.cpp b/tests/beman/execution/exec-affine-on.test.cpp index b3cc19bf..efedaba6 100644 --- a/tests/beman/execution/exec-affine-on.test.cpp +++ b/tests/beman/execution/exec-affine-on.test.cpp @@ -162,8 +162,7 @@ TEST(affine_on) { static_assert(test_std::receiver); auto s{test_std::get_scheduler(test_std::get_env(r))}; assert(s == loop.get_scheduler()); - auto st{test_std::transform_sender( - test_std::default_domain(), test_std::affine_on(test_std::just(42)), test_std::get_env(r))}; + auto st{test_std::transform_sender(test_std::affine_on(test_std::just(42)), test_std::get_env(r))}; test_std::connect(std::move(st), std::move(r)); auto s0{test_std::connect(test_std::affine_on(test_std::just(42)), receiver(loop.get_scheduler()))}; diff --git a/tests/beman/execution/exec-connect.test.cpp b/tests/beman/execution/exec-connect.test.cpp index d440d684..41ee5018 100644 --- a/tests/beman/execution/exec-connect.test.cpp +++ b/tests/beman/execution/exec-connect.test.cpp @@ -96,7 +96,7 @@ struct domain_sender { }; struct domain { - auto transform_sender(auto&& sender, auto&&...) const noexcept -> domain_sender { + auto transform_sender(auto&&, auto&& sender, auto&&...) const noexcept -> domain_sender { return domain_sender{sender.value}; } }; @@ -353,9 +353,9 @@ TEST(exec_connect) { static_assert(std::same_as); static_assert(std::same_as); static_assert( - std::same_as); - static_assert( - std::same_as); + std::same_as); + static_assert(std::same_as); static_assert(std::same_as, decltype(test_std::connect(sender{42}, domain_receiver(17)))>); diff --git a/tests/beman/execution/exec-continues-on.test.cpp b/tests/beman/execution/exec-continues-on.test.cpp index 8a025042..e1743e1a 100644 --- a/tests/beman/execution/exec-continues-on.test.cpp +++ b/tests/beman/execution/exec-continues-on.test.cpp @@ -5,10 +5,8 @@ #include #ifdef BEMAN_HAS_MODULES import beman.execution; -import beman.execution.detail.get_domain_late; #else #include -#include #include #endif @@ -78,8 +76,6 @@ auto test_constraints(Scheduler&& scheduler, Sender&& sender) { test::check_type(domain); auto s{test_std::continues_on(::std::forward(sender), ::std::forward(scheduler))}; - auto late{test_detail::get_domain_late(s, test_std::env<>{})}; - //-dk:TODO test::check_type(late); } } diff --git a/tests/beman/execution/exec-domain-default.test.cpp b/tests/beman/execution/exec-domain-default.test.cpp index 57042766..f6260268 100644 --- a/tests/beman/execution/exec-domain-default.test.cpp +++ b/tests/beman/execution/exec-domain-default.test.cpp @@ -36,16 +36,11 @@ struct simple_tag {}; template struct tag { - template - auto transform_sender(Sender&& sender, Env&&...) noexcept(Noexcept) { + template + auto transform_sender(TagParam, Sender&& sender, Env&&...) noexcept(Noexcept) { return simple_sender{sender.value}; } - template - auto transform_env(Sender&&, Env&& e) noexcept { - return env{e.value}; - } - template auto apply_sender(Sender&&, int value) noexcept(Noexcept) { return value; @@ -73,108 +68,72 @@ template auto test_transform_sender(Domain) { static_assert(test_detail::queryable); static_assert(test_std::sender); - static_assert(not requires { Domain::transform_sender(non_sender{}); }); - static_assert(requires { Domain::transform_sender(simple_sender{}); }); - static_assert(requires { Domain::transform_sender(simple_sender{}, env{}); }); - static_assert(not requires { Domain::transform_sender(simple_sender{}, env{}, env{}); }); - static_assert(noexcept(Domain::transform_sender(simple_sender{}))); - static_assert(noexcept(Domain::transform_sender(simple_sender{}, env{}))); - using simple_rvalue_type = decltype(Domain::transform_sender(simple_sender{})); - static_assert(std::same_as); - using simple_env_rvalue_type = decltype(Domain::transform_sender(simple_sender{}, env{})); - static_assert(std::same_as); + static_assert(not requires { Domain::transform_sender(simple_tag{}, non_sender{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, simple_sender{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, simple_sender{}, env{}); }); + static_assert(not requires { Domain::transform_sender(simple_tag{}, simple_sender{}, env{}, env{}); }); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, simple_sender{}))); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, simple_sender{}, env{}))); + using simple_rvalue_type = decltype(Domain::transform_sender(simple_tag{}, simple_sender{})); + static_assert(std::same_as); + using simple_env_rvalue_type = decltype(Domain::transform_sender(simple_tag{}, simple_sender{}, env{})); + static_assert(std::same_as); simple_sender sender; - using simple_lvalue_type = decltype(Domain::transform_sender(sender)); + using simple_lvalue_type = decltype(Domain::transform_sender(simple_tag{}, sender)); static_assert(std::same_as); - using simple_env_lvalue_type = decltype(Domain::transform_sender(sender, env{})); + using simple_env_lvalue_type = decltype(Domain::transform_sender(simple_tag{}, sender, env{})); static_assert(std::same_as); const simple_sender csender; - using simple_clvalue_type = decltype(Domain::transform_sender(csender)); + using simple_clvalue_type = decltype(Domain::transform_sender(simple_tag{}, csender)); static_assert(std::same_as); - using simple_env_clvalue_type = decltype(Domain::transform_sender(csender, env{})); + using simple_env_clvalue_type = decltype(Domain::transform_sender(simple_tag{}, csender, env{})); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(simple_sender{17}, env{})); - ASSERT(&sender == &Domain::transform_sender(sender, env{})); - ASSERT(&csender == &Domain::transform_sender(csender, env{})); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, simple_sender{17}, env{})); + ASSERT(&sender == &Domain::transform_sender(simple_tag{}, sender, env{})); + ASSERT(&csender == &Domain::transform_sender(simple_tag{}, csender, env{})); static_assert(test_std::sender>); static_assert(test_std::sender>); static_assert(std::same_as, test_std::tag_of_t>>); static_assert(std::same_as, test_std::tag_of_t>>); - static_assert(requires { tag().transform_sender(tagged_sender()); }); - static_assert(requires { tag().transform_sender(tagged_sender(), env{}); }); - static_assert(requires { tag().transform_sender(tagged_sender()); }); - static_assert(requires { tag().transform_sender(tagged_sender(), env{}); }); - static_assert(requires { Domain::transform_sender(tagged_sender()); }); - static_assert(requires { Domain::transform_sender(tagged_sender(), env{}); }); - static_assert(not requires { Domain::transform_sender(tagged_sender(), env{}, env{}); }); - static_assert(requires { Domain::transform_sender(tagged_sender()); }); - static_assert(requires { Domain::transform_sender(tagged_sender(), env{}); }); - static_assert(not requires { Domain::transform_sender(tagged_sender(), env{}, env{}); }); - static_assert(noexcept(Domain::transform_sender(tagged_sender()))); - static_assert(noexcept(Domain::transform_sender(tagged_sender(), env{}))); - static_assert(not noexcept(Domain::transform_sender(tagged_sender()))); - static_assert(not noexcept(Domain::transform_sender(tagged_sender(), env{}))); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { tag().transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(not requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}, env{}); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender()); }); + static_assert(requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}); }); + static_assert(not requires { Domain::transform_sender(simple_tag{}, tagged_sender(), env{}, env{}); }); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, tagged_sender()))); + static_assert(noexcept(Domain::transform_sender(simple_tag{}, tagged_sender(), env{}))); + static_assert(not noexcept(Domain::transform_sender(simple_tag{}, tagged_sender()))); + static_assert(not noexcept(Domain::transform_sender(simple_tag{}, tagged_sender(), env{}))); { - using type = decltype(Domain::transform_sender(tagged_sender())); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender())); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender())); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender())); } { - using type = decltype(Domain::transform_sender(tagged_sender(), env{})); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender(), env{})); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); } { - using type = decltype(Domain::transform_sender(tagged_sender())); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender())); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender())); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender())); } { - using type = decltype(Domain::transform_sender(tagged_sender(), env{})); + using type = decltype(Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); static_assert(std::same_as); - ASSERT(simple_sender{17} == Domain::transform_sender(tagged_sender(), env{})); + ASSERT(simple_sender{17} == Domain::transform_sender(simple_tag{}, tagged_sender(), env{})); } //-dk:TODO test returning a non-sender doesn't work } -template -auto test_transform_env(Domain) { - static_assert(test_detail::queryable); - static_assert(test_std::sender); - static_assert(requires { Domain::transform_env(simple_sender{}, env{}); }); - static_assert(noexcept(Domain::transform_env(simple_sender{}, env{}))); - { - using type = decltype(Domain::transform_env(simple_sender{}, env{})); - static_assert(std::same_as); - ASSERT(env{17} == Domain::transform_env(simple_sender{}, env{17})); - } - { - env e{17}; - using type = decltype(Domain::transform_env(simple_sender{}, e)); - static_assert(std::same_as); - ASSERT(&e == &Domain::transform_env(simple_sender{}, e)); - } - { - const env ce{17}; - using type = decltype(Domain::transform_env(simple_sender{}, ce)); - static_assert(std::same_as); - ASSERT(&ce == &Domain::transform_env(simple_sender{}, ce)); - } - - static_assert(test_std::sender>); - static_assert(requires { tag{}.transform_env(tagged_sender(), env{}); }); - static_assert(std::same_as{}.transform_env(tagged_sender(), env{}))>); - static_assert(requires { Domain::transform_env(tagged_sender{}, env{}); }); - static_assert(noexcept(Domain::transform_env(tagged_sender{}, env{}))); - { - using type = decltype(Domain::transform_env(tagged_sender{}, env{})); - static_assert(std::same_as); - ASSERT(env{17} == Domain::transform_env(simple_sender{}, env{17})); - } -} - template auto test_apply_sender(Domain) -> void { static_assert(test_std::sender); @@ -203,6 +162,5 @@ auto test_apply_sender(Domain) -> void { TEST(exec_domain_default) { test_std::default_domain domain{}; test_transform_sender(domain); - test_transform_env(domain); test_apply_sender(domain); } diff --git a/tests/beman/execution/exec-env.test.cpp b/tests/beman/execution/exec-env.test.cpp index 3526161d..be11d331 100644 --- a/tests/beman/execution/exec-env.test.cpp +++ b/tests/beman/execution/exec-env.test.cpp @@ -16,6 +16,28 @@ import beman.execution; // ---------------------------------------------------------------------------- +namespace { +struct extra_arg { + int value{}; +}; + +struct multi_arg_query_t { + constexpr auto operator()(const auto& e) const noexcept(noexcept(e.query(*this))) -> decltype(e.query(*this)) { + return e.query(*this); + } + constexpr auto operator()(const auto& e, extra_arg a) const noexcept(noexcept(e.query(*this, a))) + -> decltype(e.query(*this, a)) { + return e.query(*this, a); + } +}; +constexpr multi_arg_query_t multi_arg_query{}; + +struct multi_arg_env { + auto query(const multi_arg_query_t&) const noexcept { return 42; } + auto query(const multi_arg_query_t&, extra_arg a) const noexcept { return a.value; } +}; +} // namespace + TEST(env) { test_std::inplace_stop_source source{}; [[maybe_unused]] test_std::env<> e0{}; @@ -28,4 +50,15 @@ TEST(env) { assert(s2 == source.get_token()); static_assert(not std::is_assignable_v, test_std::env<>>); + + // P3826R5: env::query now accepts extra arguments (Args&&...) + // The extra args are forwarded to the first matching sub-environment + test_std::env e3{multi_arg_env{}}; + ASSERT(e3.query(multi_arg_query) == 42); + ASSERT(e3.query(multi_arg_query, extra_arg{99}) == 99); + + // Test env with prop that accepts extra args + test_std::env e4{test_std::prop(test_std::get_allocator, std::allocator{}), multi_arg_env{}}; + ASSERT(e4.query(multi_arg_query) == 42); + ASSERT(e4.query(multi_arg_query, extra_arg{7}) == 7); } diff --git a/tests/beman/execution/exec-get-compl-domain.test.cpp b/tests/beman/execution/exec-get-compl-domain.test.cpp new file mode 100644 index 00000000..16b198d6 --- /dev/null +++ b/tests/beman/execution/exec-get-compl-domain.test.cpp @@ -0,0 +1,147 @@ +// tests/beman/execution/exec-get-compl-domain.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_completion_domain; +import beman.execution.detail.set_error; +import beman.execution.detail.set_stopped; +import beman.execution.detail.set_value; +import beman.execution.detail.operation_state; +import beman.execution.detail.sender; +import beman.execution.detail.scheduler; +import beman.execution.detail.scheduler_t; +import beman.execution.detail.get_env; +import beman.execution.detail.get_completion_scheduler; +import beman.execution.detail.schedule; +import beman.execution.detail.get_completion_signatures; +import beman.execution.detail.completion_signatures; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { +struct throwing_domain { + throwing_domain() noexcept(false) = default; +}; +template +struct domain { + int value{}; + auto operator==(const domain&) const -> bool = default; +}; + +template +struct test_env {}; + +template +void test_get_completion_domain_template() { + static_assert(Value == requires { beman::execution::get_completion_domain; }); +} + +template +auto test_get_completion_domain_tag() { + struct queryable_tag { + auto query(test_std::get_completion_domain_t, test_env<0>) const { return domain<0>{42}; } + auto query(test_std::get_completion_domain_t, test_env<1>) const { return domain<1>{42}; } + auto query(test_std::get_completion_domain_t) const { return domain<2>{42}; } + auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } + }; + + static_assert(std::same_as(queryable_tag{}, test_env<0>{})), + domain<0>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<0>{}) == domain<0>{}); + static_assert(std::same_as(queryable_tag{}, test_env<1>{})), + domain<1>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<1>{}) == domain<1>{}); + static_assert(std::same_as(queryable_tag{})), domain<2>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}) == domain<2>{}); + static_assert(std::same_as(queryable_tag{}, test_env<2>{})), + domain<2>>); + ASSERT(beman::execution::get_completion_domain(queryable_tag{}, test_env<2>{}) == domain<2>{}); +} + +template +struct scheduler { + using scheduler_concept = test_std::scheduler_t; + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept {} + }; + struct env { + auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } + }; + struct sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return state{}; + } + auto get_env() const noexcept { return env{}; } + }; + auto schedule() const { return sender{}; } + + bool operator==(const scheduler&) const = default; + + auto query(test_std::get_completion_domain_t, test_env<0>) const { return domain<0>{42}; } + auto query(test_std::get_completion_domain_t, test_env<1>) const { return domain<1>{42}; } + auto query(test_std::get_completion_domain_t) const { return domain<2>{42}; } + auto query(test_std::get_completion_domain_t, test_env<3>) const { return throwing_domain{}; } +}; +static_assert(beman::execution::scheduler>); + +template +auto test_get_completion_domain_tag_via_scheduler() { + struct initial_queryable { + auto query(test_std::get_completion_scheduler_t, test_env<0>) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t, test_env<1>) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t) const noexcept { return scheduler{}; } + auto query(test_std::get_completion_scheduler_t, test_env<2>) const noexcept { return scheduler{}; } + }; + + test_std::get_completion_scheduler(initial_queryable{}); + initial_queryable().query(test_std::get_completion_scheduler, test_env<0>{}); +} + +auto test_void_defaults_to_set_value() { + struct queryable_void_default { + auto query(test_std::get_completion_domain_t) const { return domain<0>{17}; } + }; + static_assert(requires { beman::execution::get_completion_domain(queryable_void_default{}); }); +} +} // namespace + +TEST(exec_get_compl_domain) { + test_get_completion_domain_template(); + test_get_completion_domain_template(); + test_get_completion_domain_template(); + test_get_completion_domain_template(); + + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + test_get_completion_domain_tag(); + + test_get_completion_domain_tag_via_scheduler(); + + test_void_defaults_to_set_value(); +} diff --git a/tests/beman/execution/exec-get-compl-sched.test.cpp b/tests/beman/execution/exec-get-compl-sched.test.cpp index 2ffb7c11..75df8615 100644 --- a/tests/beman/execution/exec-get-compl-sched.test.cpp +++ b/tests/beman/execution/exec-get-compl-sched.test.cpp @@ -60,6 +60,20 @@ template auto test_tag(Env&& env) -> void { static_assert(Expect == requires { test_std::get_completion_scheduler(env); }); } + +struct extra_env { + int extra_value{}; +}; + +struct env_with_extra_args { + int value{}; + auto query(const test_std::get_completion_scheduler_t&) const noexcept { + return scheduler{this->value}; + } + auto query(const test_std::get_completion_scheduler_t&, extra_env e) const noexcept { + return scheduler{this->value + e.extra_value}; + } +}; } // namespace TEST(exec_get_compl_sched) { @@ -95,4 +109,9 @@ TEST(exec_get_compl_sched) { ASSERT(test_std::get_completion_scheduler(e) == scheduler{19}); ASSERT(test_std::get_completion_scheduler(e) == scheduler{20}); ASSERT(test_std::get_completion_scheduler(e) == scheduler{18}); + + env_with_extra_args ewa{10}; + ASSERT(test_std::get_completion_scheduler(ewa) == scheduler{10}); + ASSERT(test_std::get_completion_scheduler(ewa, extra_env{5}) == + scheduler{15}); } diff --git a/tests/beman/execution/exec-get-domain.test.cpp b/tests/beman/execution/exec-get-domain.test.cpp index 759e3231..98dc9605 100644 --- a/tests/beman/execution/exec-get-domain.test.cpp +++ b/tests/beman/execution/exec-get-domain.test.cpp @@ -34,13 +34,54 @@ struct overloaded_get_domain { auto query(const test_std::get_domain_t&) noexcept -> void = delete; }; -template +template auto test_get_domain(Object&& object) { - static_assert(Expect == requires { test_std::get_domain(object); }); if constexpr (requires { test_std::get_domain(object); }) { static_assert(std::same_as); } } + +struct sched_domain {}; + +struct test_sched_sender; +struct test_sched_env; + +struct test_scheduler { + using scheduler_concept = test_std::scheduler_t; + auto schedule() const -> test_sched_sender; + auto operator==(const test_scheduler&) const -> bool = default; + auto query(test_std::get_completion_domain_t) const noexcept { return sched_domain{}; } +}; + +struct test_sched_state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept {} +}; + +struct test_sched_env { + auto query(test_std::get_completion_scheduler_t) const noexcept { return test_scheduler{}; } +}; + +struct test_sched_sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return test_sched_state{}; + } + auto get_env() const noexcept { return test_sched_env{}; } +}; + +inline auto test_scheduler::schedule() const -> test_sched_sender { return {}; } + +static_assert(test_std::scheduler); + +// Env that has get_scheduler but no get_domain +struct env_with_scheduler { + auto query(test_std::get_scheduler_t) const noexcept { return test_scheduler{}; } +}; } // namespace TEST(exec_get_domain) { @@ -48,12 +89,14 @@ TEST(exec_get_domain) { static_assert(test_std::forwarding_query(test_std::get_domain)); - test_get_domain(no_get_domain{}); - test_get_domain(non_const_get_domain{}); - test_get_domain(non_const_get_domain{}); - test_get_domain(has_get_domain{42}); - test_get_domain(has_get_domain{42}); - test_get_domain(overloaded_get_domain{}); + test_get_domain(no_get_domain{}); // falling back to `default_domain` + test_get_domain(non_const_get_domain{}); // falling back to `default_domain` + test_get_domain(non_const_get_domain{}); // falling back to `default_domain` + test_get_domain(has_get_domain{42}); + test_get_domain(has_get_domain{42}); + test_get_domain(overloaded_get_domain{}); static_assert(42 == test_std::get_domain(has_get_domain{42}).value); + + test_get_domain(env_with_scheduler{}); } diff --git a/tests/beman/execution/exec-get-scheduler.test.cpp b/tests/beman/execution/exec-get-scheduler.test.cpp index e71575cf..0e9b884e 100644 --- a/tests/beman/execution/exec-get-scheduler.test.cpp +++ b/tests/beman/execution/exec-get-scheduler.test.cpp @@ -14,8 +14,13 @@ import beman.execution; namespace { struct scheduler { - int value{}; - auto operator==(const scheduler&) const -> bool = default; + using scheduler_concept = test_std::scheduler_t; + struct sender { + using sender_concept = test_std::sender_t; + }; + int value{}; + auto operator==(const scheduler&) const -> bool = default; + static auto schedule() noexcept -> sender { return {}; } }; struct env { @@ -25,6 +30,7 @@ struct env { } // namespace TEST(exec_get_scheduler) { + static_assert(test_std::scheduler); static_assert(std::same_as); static_assert(test_std::forwarding_query(test_std::get_scheduler)); env e{17}; diff --git a/tests/beman/execution/exec-getcomplsigs.test.cpp b/tests/beman/execution/exec-getcomplsigs.test.cpp index 20a15976..6b1296ea 100644 --- a/tests/beman/execution/exec-getcomplsigs.test.cpp +++ b/tests/beman/execution/exec-getcomplsigs.test.cpp @@ -5,7 +5,6 @@ #include #ifdef BEMAN_HAS_MODULES import beman.execution; -import beman.execution.detail.get_domain_late; //-dk:TODO remove when get_domain_late is removed #else #include #endif @@ -80,15 +79,8 @@ auto test_get_completion_signatures() { }); static_assert(std::same_as); - static_assert( - std::same_as{}, env_with_domain{}))>); static_assert(std::same_as>(), env_with_domain{}), - no_signatures_sender{}, - env_with_domain{}))>); + decltype(test_std::transform_sender(no_signatures_sender{}, env_with_domain{}))>); static_assert(std::same_as())>); static_assert(requires { diff --git a/tests/beman/execution/exec-inline-scheduler.test.cpp b/tests/beman/execution/exec-inline-scheduler.test.cpp new file mode 100644 index 00000000..ffacb3d4 --- /dev/null +++ b/tests/beman/execution/exec-inline-scheduler.test.cpp @@ -0,0 +1,224 @@ +// tests/beman/execution/exec-inline-scheduler.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution; +import beman.execution.detail; +#else +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { + +struct test_receiver { + using receiver_concept = test_std::receiver_t; + bool& called; + auto set_value() && noexcept -> void { called = true; } + auto get_env() const noexcept { return test_std::env{}; } +}; + +struct custom_scheduler { + using scheduler_concept = test_std::scheduler_t; + int id{}; + + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept -> void {} + }; + struct env { + int id{}; + auto query(test_std::get_completion_scheduler_t) const noexcept { + return custom_scheduler{id}; + } + }; + struct sender { + using sender_concept = test_std::sender_t; + int id{}; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return state{}; + } + auto get_env() const noexcept { return env{id}; } + }; + auto schedule() const { return sender{id}; } + auto operator==(const custom_scheduler&) const -> bool = default; +}; + +struct custom_domain { + auto operator==(const custom_domain&) const -> bool = default; +}; + +struct sched_with_domain { + using scheduler_concept = test_std::scheduler_t; + + struct state { + using operation_state_concept = test_std::operation_state_t; + auto start() noexcept -> void {} + }; + struct sender { + using sender_concept = test_std::sender_t; + static consteval auto get_completion_signatures() { + return test_std::completion_signatures(); + } + template + auto connect(R&&) const { + return state{}; + } + }; + auto schedule() const { return sender{}; } + auto operator==(const sched_with_domain&) const -> bool = default; + auto query(test_std::get_domain_t) const noexcept { return custom_domain{}; } +}; + +// Receiver whose env provides a scheduler +struct sched_env_receiver { + using receiver_concept = test_std::receiver_t; + bool& called; + + struct env { + auto query(test_std::get_scheduler_t) const noexcept { return custom_scheduler{42}; } + }; + auto set_value() && noexcept -> void { called = true; } + auto get_env() const noexcept { return env{}; } +}; + +struct domain_env_receiver { + using receiver_concept = test_std::receiver_t; + bool& called; + + struct env { + auto query(test_std::get_scheduler_t) const noexcept { return sched_with_domain{}; } + }; + auto set_value() && noexcept -> void { called = true; } + auto get_env() const noexcept { return env{}; } +}; + +auto test_scheduler_concept() { + static_assert(test_std::scheduler); + static_assert(test_std::scheduler); + static_assert(test_std::scheduler); + static_assert(test_std::scheduler); +} + +auto test_schedule_returns_sender() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + static_assert(test_std::sender); + + // Completion signatures: set_value_t() + using sigs = test_std::completion_signatures; + static_assert(std::same_as); +} + +auto test_equality() { + test_std::inline_scheduler s1; + test_std::inline_scheduler s2; + + // All inline_schedulers are equal + ASSERT(s1 == s2); + ASSERT(!(s1 != s2)); +} + +auto test_copyable() { + static_assert(std::copyable); + + test_std::inline_scheduler s1; + test_std::inline_scheduler s2 = s1; + ASSERT(s1 == s2); +} + +auto test_connect_and_start() { + bool called = false; + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto op = test_std::connect(sndr, test_receiver{called}); + static_assert(test_std::operation_state); + ASSERT(!called); + test_std::start(op); + ASSERT(called); +} + +auto test_sender_env_is_inline_attrs() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto attrs = test_std::get_env(sndr); + static_assert(std::same_as>); +} + +auto test_inline_attrs_completion_scheduler() { + auto attrs = test_detail::inline_attrs{}; + + struct test_env { + auto query(test_std::get_scheduler_t) const noexcept { return custom_scheduler{42}; } + }; + + auto sched = attrs.query(test_std::get_completion_scheduler, test_env{}); + static_assert(std::same_as); + ASSERT(sched == custom_scheduler{42}); +} + +auto test_inline_attrs_completion_domain() { + auto attrs = test_detail::inline_attrs{}; + + struct domain_env { + auto query(test_std::get_domain_t) const noexcept { return custom_domain{}; } + }; + + auto dom = attrs.query(test_std::get_completion_domain, domain_env{}); + static_assert(std::same_as); +} + +auto test_connect_with_scheduler_env() { + bool called = false; + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto op = test_std::connect(sndr, sched_env_receiver{called}); + ASSERT(!called); + test_std::start(op); + ASSERT(called); +} + +auto test_get_completion_scheduler_with_env() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto attrs = test_std::get_env(sndr); + + struct test_env { + auto query(test_std::get_scheduler_t) const noexcept { return custom_scheduler{7}; } + }; + + auto sched = test_std::get_completion_scheduler(attrs, test_env{}); + static_assert(std::same_as); + ASSERT(sched == custom_scheduler{7}); +} + +auto test_get_completion_domain_with_env() { + auto sndr = test_std::schedule(test_std::inline_scheduler{}); + auto attrs = test_std::get_env(sndr); + + struct test_env { + auto query(test_std::get_domain_t) const noexcept { return custom_domain{}; } + }; + + auto dom = test_std::get_completion_domain(attrs, test_env{}); + static_assert(std::same_as); +} + +} // namespace + +TEST(exec_inline_scheduler) { + test_scheduler_concept(); + test_schedule_returns_sender(); + test_equality(); + test_copyable(); + test_connect_and_start(); + test_sender_env_is_inline_attrs(); + test_inline_attrs_completion_scheduler(); + test_inline_attrs_completion_domain(); + test_connect_with_scheduler_env(); + test_get_completion_scheduler_with_env(); + test_get_completion_domain_with_env(); +} diff --git a/tests/beman/execution/exec-on.test.cpp b/tests/beman/execution/exec-on.test.cpp index dd875e27..3661a542 100644 --- a/tests/beman/execution/exec-on.test.cpp +++ b/tests/beman/execution/exec-on.test.cpp @@ -42,15 +42,9 @@ auto test_interface(Sch sch, Sndr sndr, Closure closure) -> void { test::use(sndr1, sndr2, sndr3); } -template OutSndr> -auto test_transform_env(OutSndr out_sndr) -> void { - auto e{test_std::on.transform_env(out_sndr, test_std::env<>{})}; - test::use(e); -} - template OutSndr> auto test_transform_sender(OutSndr out_sndr) -> void { - auto s{test_std::on.transform_sender(std::move(out_sndr), test_std::env<>{})}; + auto s{test_std::on.transform_sender(test_std::set_value, std::move(out_sndr), test_std::env<>{})}; static_assert(test_std::sender); auto ts{std::move(s) | test_std::then([](auto&&...) {})}; static_assert(test_std::sender); @@ -75,10 +69,6 @@ TEST(exec_on) { static_assert(not test_detail::is_sender_adaptor_closure); test_interface(pool.get_scheduler(), test_std::just(), test_std::then([] {})); - test_transform_env(test_detail::make_sender(test_std::on, pool.get_scheduler(), test_std::just())); - test_transform_env(test_detail::make_sender( - test_std::on, test_detail::product_type{pool.get_scheduler(), test_std::then([] {})}, test_std::just())); - test_transform_sender(test_detail::make_sender(test_std::on, pool.get_scheduler(), test_std::just())); test_transform_sender(test_detail::make_sender( test_std::on, test_detail::product_type{pool.get_scheduler(), test_std::then([] {})}, test_std::just())); diff --git a/tests/beman/execution/exec-prop.test.cpp b/tests/beman/execution/exec-prop.test.cpp index 40810315..ef97abb3 100644 --- a/tests/beman/execution/exec-prop.test.cpp +++ b/tests/beman/execution/exec-prop.test.cpp @@ -45,4 +45,12 @@ TEST(exec_prop) { [[maybe_unused]] decltype(p0) p2(p0); static_assert(not std::is_assignable_v); static_assert(not std::is_assignable_v>); + + // P3826R5: prop::query now accepts extra arguments (auto&&...) + // The extra arguments are ignored but allowed + auto p3{test_std::prop(test_query, 99)}; + ASSERT(p3.query(test_query) == 99); + ASSERT(p3.query(test_query, 1) == 99); + ASSERT(p3.query(test_query, 1, 2) == 99); + ASSERT(p3.query(test_query, 1, 2, 3) == 99); } diff --git a/tests/beman/execution/exec-queries-expos.test.cpp b/tests/beman/execution/exec-queries-expos.test.cpp new file mode 100644 index 00000000..06acee24 --- /dev/null +++ b/tests/beman/execution/exec-queries-expos.test.cpp @@ -0,0 +1,96 @@ +// tests/beman/execution/exec-queries-expos.test.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#ifdef BEMAN_HAS_MODULES +import beman.execution.detail.get_domain; +import beman.execution.detail.get_scheduler; +import beman.execution.detail.hide_sched; +import beman.execution.detail.try_query; +#else +#include +#include +#include +#include +#endif + +// ---------------------------------------------------------------------------- + +namespace { +template <::std::size_t> +struct arg { + int value{}; +}; +template <::std::size_t> +struct get_arg {}; + +struct test_queryable { + int query(get_arg<0>) const noexcept { return 42; } + + int query(get_arg<1>) const noexcept { return 43; } + int query(get_arg<1>, arg<0>) const noexcept { return 44; } + + int query(get_arg<2>, arg<0>) const noexcept { return 45; } + int query(get_arg<2>, arg<0>, arg<1>) const noexcept { return 46; } + + int query(test_std::get_domain_t) const noexcept { return 47; } + int query(test_std::get_domain_t, arg<0>) const noexcept { return 48; } + int query(test_std::get_domain_t, arg<0>, arg<1>) const noexcept { return 49; } + + int query(test_std::get_scheduler_t) const noexcept { return 50; } + int query(test_std::get_scheduler_t, arg<0>) const noexcept { return 51; } + int query(test_std::get_scheduler_t, arg<0>, arg<1>) const noexcept { return 52; } +}; + +template +auto test_try_query_exists(int expect, Q q, Tag&& tag, Args&&... args) -> void { + static_assert(Value == + requires { test_detail::try_query(q, ::std::forward(tag), ::std::forward(args)...); }); + if constexpr (Value) { + ASSERT(expect == test_detail::try_query(q, ::std::forward(tag), ::std::forward(args)...)); + } +} + +auto test_try_query() -> void { + test_try_query_exists(42, test_queryable{}, get_arg<0>{}); + test_try_query_exists(42, test_queryable{}, get_arg<0>{}, arg<0>{}); + test_try_query_exists(42, test_queryable{}, get_arg<0>{}, arg<0>{}, arg<1>{}); + + test_try_query_exists(43, test_queryable{}, get_arg<1>{}); + test_try_query_exists(44, test_queryable{}, get_arg<1>{}, arg<0>{}); + test_try_query_exists(43, test_queryable{}, get_arg<1>{}, arg<0>{}, arg<1>{}); + + test_try_query_exists(0, test_queryable{}, get_arg<2>{}); + test_try_query_exists(45, test_queryable{}, get_arg<2>{}, arg<0>{}); + test_try_query_exists(46, test_queryable{}, get_arg<2>{}, arg<0>{}, arg<1>{}); +} + +template +auto test_hide_query_exists(int expect, Q q, Tag&& tag, Args&&... args) -> void { + static_assert(Value == requires { + test_detail::hide_sched(q).query(::std::forward(tag), ::std::forward(args)...); + }); + if constexpr (Value) { + ASSERT(expect == test_detail::hide_sched(q).query(::std::forward(tag), ::std::forward(args)...)); + } +} + +auto test_hide_query() -> void { + test_hide_query_exists(42, test_queryable{}, get_arg<0>{}); + test_hide_query_exists(44, test_queryable{}, get_arg<1>{}, arg<0>{}); + test_hide_query_exists(46, test_queryable{}, get_arg<2>{}, arg<0>{}, arg<1>{}); + + test_hide_query_exists(47, test_queryable{}, test_std::get_domain); + test_hide_query_exists(48, test_queryable{}, test_std::get_domain, arg<0>{}); + test_hide_query_exists(49, test_queryable{}, test_std::get_domain, arg<0>{}, arg<1>{}); + + test_hide_query_exists(50, test_queryable{}, test_std::get_scheduler); + test_hide_query_exists(51, test_queryable{}, test_std::get_scheduler, arg<0>{}); + test_hide_query_exists(52, test_queryable{}, test_std::get_scheduler, arg<0>{}, arg<1>{}); +} +} // namespace + +TEST(exec_queries_expos) { + test_try_query(); + test_hide_query(); +} diff --git a/tests/beman/execution/exec-sched.test.cpp b/tests/beman/execution/exec-sched.test.cpp index 363791a9..70d5312d 100644 --- a/tests/beman/execution/exec-sched.test.cpp +++ b/tests/beman/execution/exec-sched.test.cpp @@ -5,6 +5,7 @@ #ifdef BEMAN_HAS_MODULES import beman.execution; #else +#include #include #endif @@ -72,10 +73,10 @@ struct scheduler { auto operator==(const scheduler&) const -> bool = default; }; -struct bad_completion_scheduler { +struct indirect_completion_scheduler { using scheduler_concept = test_std::scheduler_t; auto schedule() -> sender> { return {}; } - auto operator==(const bad_completion_scheduler&) const -> bool = default; + auto operator==(const indirect_completion_scheduler&) const -> bool = default; }; template @@ -106,6 +107,6 @@ TEST(exec_sched) { test_scheduler(); test_scheduler(); test_scheduler(); - test_scheduler(); + test_scheduler(); test_scheduler(); } diff --git a/tests/beman/execution/exec-schedule-from.test.cpp b/tests/beman/execution/exec-schedule-from.test.cpp deleted file mode 100644 index 924b9e75..00000000 --- a/tests/beman/execution/exec-schedule-from.test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// src/beman/execution/tests/exec-schedule-from.test.cpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#ifdef BEMAN_HAS_MODULES -import beman.execution; -import beman.execution.detail; -#else -#include -#include -#endif - -// ---------------------------------------------------------------------------- - -namespace { -struct non_scheduler {}; -struct non_sender {}; - -struct scheduler { - struct env { - auto query(const test_std::get_completion_scheduler_t&) const noexcept -> scheduler { - return {}; - } - }; - struct sender { - template - struct state { - using operation_state_concept = test_std::operation_state_t; - std::remove_cvref_t receiver; - auto start() & noexcept -> void { test_std::set_value(::std::move(this->receiver)); } - }; - using sender_concept = test_std::sender_t; - template - static consteval auto get_completion_signatures() -> test_std::completion_signatures { - return {}; - } - auto get_env() const noexcept -> env { return {}; } - template - auto connect(Receiver&& receiver) -> state { - return {std::forward(receiver)}; - } - }; - using scheduler_concept = test_std::scheduler_t; - auto schedule() -> sender { return {}; } - auto operator==(const scheduler&) const -> bool = default; -}; -struct sender { - using sender_concept = test_std::sender_t; - template - static consteval auto get_completion_signatures() -> test_std::completion_signatures { - return {}; - } - - template - struct state { - using operation_state_concept = test_std::operation_state_t; - std::remove_cvref_t receiver; - auto start() & noexcept -> void { test_std::set_value(::std::move(this->receiver)); } - }; - template - auto connect(Receiver&& receiver) -> state { - return {std::forward(receiver)}; - } -}; - -template -auto test_constraints(Scheduler&& scheduler, Sender&& sender) { - static_assert(Expect == requires { test_std::schedule_from(scheduler, sender); }); - static_assert(Expect == requires { - test_std::schedule_from(::std::forward(scheduler), ::std::forward(sender)); - }); -} - -template -auto test_use(Scheduler&& scheduler, Sender&& sender) { - auto s{test_std::schedule_from(::std::forward(scheduler), ::std::forward(sender))}; - - static_assert(test_std::sender); - test_std::sync_wait(std::move(s)); -} -} // namespace - -TEST(exec_schedule_from) { - static_assert(std::same_as); - static_assert(not test_std::scheduler); - static_assert(test_std::scheduler); - static_assert(not test_std::sender); - static_assert(test_std::sender); - - test_constraints(non_scheduler{}, non_sender{}); - test_constraints(non_scheduler{}, sender{}); - test_constraints(scheduler{}, non_sender{}); - test_constraints(scheduler{}, sender{}); - - test_use(scheduler{}, sender{}); -} diff --git a/tests/beman/execution/exec-snd-expos.test.cpp b/tests/beman/execution/exec-snd-expos.test.cpp index 67de17a6..852cd7ca 100644 --- a/tests/beman/execution/exec-snd-expos.test.cpp +++ b/tests/beman/execution/exec-snd-expos.test.cpp @@ -22,12 +22,9 @@ import beman.execution.detail; #include #include #include -#include #include #include #include -#include -#include #include #include #include @@ -260,30 +257,6 @@ auto test_join_env() -> void { ASSERT(cenv.query(custom_query<2>, 13) == 30); } -auto test_sched_attrs() -> void { - scheduler sched{17}; - ASSERT(sched.query(test_std::get_domain) == domain{17}); - - auto attrs{test_detail::sched_attrs(sched)}; - static_assert(test_detail::queryable); - - auto sched_error{attrs.query(test_std::get_completion_scheduler)}; - static_assert(::std::same_as); - ASSERT(sched_error == sched); - - auto sched_stopped{attrs.query(test_std::get_completion_scheduler)}; - static_assert(::std::same_as); - ASSERT(sched_stopped == sched); - - auto sched_value{attrs.query(test_std::get_completion_scheduler)}; - static_assert(::std::same_as); - ASSERT(sched_value == sched); - - auto dom{attrs.query(test_std::get_domain)}; - static_assert(::std::same_as); - ASSERT(dom == domain{17}); -} - auto test_sched_env() -> void { scheduler sched{17}; ASSERT(sched.query(test_std::get_domain) == domain{17}); @@ -389,11 +362,6 @@ auto test_completion_domain() -> void { static_assert(std::same_as( cd::env{})))>); - static_assert(std::same_as{})))>); - static_assert(std::same_as{})))>); - static_assert(std::same_as{})))>); - static_assert( - std::same_as{})))>); } auto test_query_with_default() -> void { @@ -401,7 +369,8 @@ auto test_query_with_default() -> void { static_assert(std::same_as); ASSERT(result1.value == 43); - auto result2{test_detail::query_with_default(test_std::get_domain, test_std::env<>(), default_domain{74})}; + auto result2{ + test_detail::query_with_default(test_std::get_completion_domain<>, test_std::env<>(), default_domain{74})}; static_assert(std::same_as); ASSERT(result2.default_value == 74); } @@ -411,11 +380,9 @@ auto test_get_domain_early() -> void { using sender_concept = test_std::sender_t; }; static_assert(test_std::sender); - static_assert(std::same_as); namespace cd = completion_domain; static_assert(test_std::sender>); - static_assert(std::same_as{}))>); struct sender_with_domain { using sender_concept = test_std::sender_t; @@ -428,15 +395,12 @@ auto test_get_domain_early() -> void { static_assert(test_std::sender); static_assert(std::same_as); static_assert(std::same_as); - static_assert( - std::same_as); } template auto test_get_domain_late(auto sender, auto env) -> void { static_assert(test_std::sender); static_assert(test_detail::queryable); - static_assert(std::same_as); } struct get_domain_late_scheduler { @@ -446,6 +410,11 @@ struct get_domain_late_scheduler { auto query(const test_std::get_completion_scheduler_t&) const noexcept -> get_domain_late_scheduler { return {}; } + + template + auto query(const test_std::get_completion_domain_t&) const noexcept -> dom { + return {}; + } }; struct sender { using sender_concept = test_std::sender_t; @@ -496,8 +465,8 @@ auto test_get_domain_late() -> void { }; static_assert(test_std::sender); static_assert(std::same_as); - static_assert( - std::same_as); + static_assert(std::same_as{}))>); test_get_domain_late(scheduler_sender{}, test_std::env<>{}); struct env_sender { @@ -1145,8 +1114,7 @@ auto test_basic_sender() -> void { static_assert(test_std::sender); static_assert(std::same_as>); static_assert( - std::same_as); + std::same_as); using basic_sender = test_detail::basic_sender; static_assert(test_std::sender); @@ -1161,8 +1129,7 @@ auto test_basic_sender() -> void { static_assert(std::same_as>); static_assert( - std::same_as); + std::same_as); static_assert(test_std::dependent_sender); // According to https://eel.is/c++draft/exec#adapt.general-3.5, basic_sender shall be a dependent-sender static_assert(test_std::dependent_sender); @@ -1340,7 +1307,6 @@ TEST(exec_snd_expos) { test_fwd_env(); test_make_env(); test_join_env(); - test_sched_attrs(); test_sched_env(); test_completion_domain(); test_query_with_default(); diff --git a/tests/beman/execution/exec-snd-transform.test.cpp b/tests/beman/execution/exec-snd-transform.test.cpp index 2a1a2497..a57ee78b 100644 --- a/tests/beman/execution/exec-snd-transform.test.cpp +++ b/tests/beman/execution/exec-snd-transform.test.cpp @@ -6,11 +6,9 @@ #include #ifdef BEMAN_HAS_MODULES import beman.execution; +import beman.execution.detail; #else -#include -#include #include -#include #endif // ---------------------------------------------------------------------------- @@ -18,7 +16,6 @@ import beman.execution; namespace { enum class kind : unsigned char { dom, tag }; struct env {}; -struct empty_domain {}; template struct final_sender { @@ -33,8 +30,8 @@ struct sender; template struct tag { - template - auto transform_sender(Sender sndr, Env&&...) const noexcept { + template + auto transform_sender(TagParam, Sender sndr, Env&&...) const noexcept { if constexpr (1 < I) return sender{{}, sndr.value}; else @@ -52,18 +49,21 @@ struct sender { }; struct special_domain { - template + template requires std::same_as, final_sender> - auto transform_sender(Sender&& sndr, auto&&...) const -> decltype(auto) { + auto transform_sender(TagParam, Sender&& sndr, auto&&...) const -> decltype(auto) { return std::forward(sndr); } - template + template requires std::same_as, final_sender> - auto transform_sender(Sender&& sndr, auto&&...) const { + auto transform_sender(TagParam, Sender&& sndr, auto&&...) const { return final_sender{sndr.value}; } - auto transform_sender(auto&& sndr, auto&&...) const { - using index_type = std::remove_cvref_t::index_type; + template + requires(!std::same_as, final_sender> && + !std::same_as, final_sender>) + auto transform_sender(TagParam, Sndr&& sndr, auto&&...) const { + using index_type = std::remove_cvref_t::index_type; if constexpr (1 < index_type::value) return sender{{}, sndr.value}; else @@ -71,84 +71,138 @@ struct special_domain { } }; -template -auto test_transform_sender(Dom&& dom, Sender&& sndr) { - auto value{sndr.value}; - static_assert(test_std::sender>); - static_assert(requires { test_std::transform_sender(dom, std::forward(sndr)); }); - if constexpr (requires { test_std::transform_sender(dom, std::forward(sndr)); }) { - static_assert(std::same_as(sndr)))>); - static_assert(Noexcept == noexcept(test_std::transform_sender(dom, std::forward(sndr)))); - ASSERT(value == test_std::transform_sender(dom, std::forward(sndr)).value); - } -} +template +struct compl_domain_attrs { + auto query(test_std::get_completion_domain_t) const noexcept { return Domain{}; } +}; + +template +struct domain_sender { + using sender_concept = test_std::sender_t; + using is_basic_sender_tag = void; + using index_type = std::integral_constant; + tag t; + int value{}; + auto get_env() const noexcept { return compl_domain_attrs{}; } +}; -template -auto test_transform_sender_env(Dom&& dom, Sender&& sndr) { - auto value{sndr.value}; - static_assert(requires { test_std::transform_sender(dom, std::forward(sndr), env{}); }); - if constexpr (requires { test_std::transform_sender(dom, std::forward(sndr), env{}); }) { - static_assert( - std::same_as(sndr), env{}))>); - static_assert(Noexcept == noexcept(test_std::transform_sender(dom, std::forward(sndr), env{}))); - ASSERT(value == test_std::transform_sender(dom, std::forward(sndr), env{}).value); +struct start_domain { + template + requires std::same_as, final_sender> + auto transform_sender(test_std::start_t, Sndr&& sndr, const auto&) const { + return final_sender{sndr.value}; } +}; + +template +struct starting_domain_env { + auto query(test_std::get_domain_t) const noexcept { return Domain{}; } +}; + +auto test_indeterminate_domain_transform() { + test_std::indeterminate_domain<> idom; + static_assert(requires { idom.transform_sender(test_std::set_value, final_sender{42}, env{}); }); + auto result = idom.transform_sender(test_std::set_value, final_sender{42}, env{}); + static_assert(test_std::sender); + ASSERT(result.value == 42); - static_assert(not requires { test_std::transform_sender(dom, std::forward(sndr), env{}, env{}); }); + test_std::indeterminate_domain idom2; + auto result2 = idom2.transform_sender(test_std::set_value, final_sender{17}, env{}); + ASSERT(result2.value == 17); } } // namespace TEST(exec_snd_transform) { - test_transform_sender&&>(empty_domain{}, final_sender{42}); - test_transform_sender_env&&>(empty_domain{}, final_sender{42}); - final_sender fs{42}; - test_transform_sender&>(empty_domain{}, fs); - test_transform_sender_env&>(empty_domain{}, fs); - const final_sender cfs{42}; - test_transform_sender&>(empty_domain{}, cfs); - test_transform_sender_env&>(empty_domain{}, cfs); - static_assert(std::same_as, test_std::tag_of_t>>); static_assert(std::same_as, test_std::tag_of_t>>); - static_assert(std::same_as, decltype(tag<1>{}.transform_sender(sender<1>{{}, 0}))>); - static_assert(std::same_as, decltype(tag<1>{}.transform_sender(sender<1>{{}, 0}, env{}))>); - static_assert(std::same_as, - decltype(test_std::default_domain{}.transform_sender(sender<1>{{}, 0}))>); + using Tag1 = std::integral_constant; + using Tag2 = std::integral_constant; + static_assert( + std::same_as, decltype(tag<1>{}.transform_sender(Tag1{}, sender<1>{{}, 0}))>); + static_assert( + std::same_as, decltype(tag<1>{}.transform_sender(Tag1{}, sender<1>{{}, 0}, env{}))>); + static_assert(std::same_as, decltype(tag<2>{}.transform_sender(Tag2{}, sender<2>{{}, 0}))>); static_assert(std::same_as, - decltype(test_std::default_domain{}.transform_sender(sender<1>{{}, 0}, env{}))>); + decltype(test_std::default_domain{}.transform_sender(Tag1{}, sender<1>{{}, 0}))>); + static_assert( + std::same_as, + decltype(test_std::default_domain{}.transform_sender(Tag1{}, sender<1>{{}, 0}, env{}))>); + + // Identity: final senders (no tag customization) pass through unchanged + { + static_assert(requires { test_std::transform_sender(final_sender{42}, env{}); }); + final_sender r = test_std::transform_sender(final_sender{42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + { + final_sender r = test_std::transform_sender(final_sender{42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } - static_assert(std::same_as, decltype(tag<2>{}.transform_sender(sender<2>{{}, 0}))>); - static_assert(std::same_as, decltype(tag<2>{}.transform_sender(sender<2>{{}, 0}, env{}))>); + // Single-step recursive reduction through default completion domain + { + final_sender r = test_std::transform_sender(sender<1>{{}, 42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } - test_transform_sender>(empty_domain{}, sender<1>{{}, 42}); - test_transform_sender_env>(empty_domain{}, sender<1>{{}, 42}); - test_transform_sender>(empty_domain{}, sender<2>{{}, 42}); - test_transform_sender_env>(empty_domain{}, sender<2>{{}, 42}); - test_transform_sender>(empty_domain{}, sender<5>{{}, 42}); - test_transform_sender_env>(empty_domain{}, sender<5>{{}, 42}); + // Multi-step recursive reduction + { + final_sender r = test_std::transform_sender(sender<2>{{}, 17}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 17); + } + { + final_sender r = test_std::transform_sender(sender<3>{{}, 42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + { + final_sender r = test_std::transform_sender(sender<5>{{}, 99}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 99); + } - static_assert(std::same_as&&, - decltype(special_domain{}.transform_sender(final_sender{}))>); - static_assert( - std::same_as, decltype(special_domain{}.transform_sender(final_sender{}))>); - static_assert( - std::same_as, decltype(special_domain{}.transform_sender(sender<1>{{}, 42}))>); - static_assert(std::same_as, decltype(special_domain{}.transform_sender(sender<2>{{}, 42}))>); - test_transform_sender&&>(special_domain{}, final_sender{42}); - test_transform_sender_env&&>(special_domain{}, final_sender{42}); - final_sender fd{42}; - test_transform_sender&>(special_domain{}, fd); - test_transform_sender_env&>(special_domain{}, fd); - const final_sender cfd{42}; - test_transform_sender&>(special_domain{}, cfd); - test_transform_sender_env&>(special_domain{}, cfd); - test_transform_sender>(special_domain{}, final_sender{42}); - test_transform_sender_env>(special_domain{}, final_sender{42}); - test_transform_sender>(special_domain{}, sender<1>{{}, 42}); - test_transform_sender_env>(special_domain{}, sender<1>{{}, 42}); - test_transform_sender>(special_domain{}, sender<2>{{}, 42}); - test_transform_sender_env>(special_domain{}, sender<2>{{}, 42}); - test_transform_sender>(special_domain{}, sender<5>{{}, 42}); - test_transform_sender_env>(special_domain{}, sender<5>{{}, 42}); + { + final_sender r = test_std::transform_sender(domain_sender<1, special_domain>{{}, 42}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + { + final_sender r = test_std::transform_sender(domain_sender<2, special_domain>{{}, 17}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 17); + } + { + final_sender r = test_std::transform_sender(domain_sender<5, special_domain>{{}, 99}, env{}); + static_assert(test_std::sender); + ASSERT(r.value == 99); + } + + { + final_sender r = test_std::transform_sender(sender<1>{{}, 42}, starting_domain_env{}); + static_assert(test_std::sender); + static_assert(std::same_as>); + ASSERT(r.value == 42); + } + { + // Multi-step completion, then starting domain + final_sender r = test_std::transform_sender(sender<3>{{}, 77}, starting_domain_env{}); + static_assert(std::same_as>); + ASSERT(r.value == 77); + } + + // Both custom completion and starting domains + { + final_sender r = + test_std::transform_sender(domain_sender<1, special_domain>{{}, 42}, starting_domain_env{}); + static_assert(test_std::sender); + ASSERT(r.value == 42); + } + + // indeterminate_domain + test_indeterminate_domain_transform(); } diff --git a/tests/beman/execution/exec-when-all.test.cpp b/tests/beman/execution/exec-when-all.test.cpp index 6bf697fe..a605da33 100644 --- a/tests/beman/execution/exec-when-all.test.cpp +++ b/tests/beman/execution/exec-when-all.test.cpp @@ -206,7 +206,7 @@ auto test_when_all() -> void { test_when_all_available(multi_sender()); test_when_all_available(multi_sender()); test_when_all_available(domain_sender>(), domain_sender>()); - test_when_all_available(domain_sender>(), domain_sender>()); + test_when_all_available(domain_sender>(), domain_sender>()); test_when_all_breathing(); diff --git a/tests/beman/execution/execution-module.test.cpp b/tests/beman/execution/execution-module.test.cpp index b11e998f..340ea46d 100644 --- a/tests/beman/execution/execution-module.test.cpp +++ b/tests/beman/execution/execution-module.test.cpp @@ -101,10 +101,7 @@ TEST(execution_modules) { test::use_template(); // [exec.snd.transform], sender transformations - test_std::transform_sender(test_std::default_domain{}, test_std::just()); - - // [exec.snd.transform.env], environment transformations - //-dk:TODO test_std::transform_env(test_std::default_domain{}, test_std::just(), test_std::env<>{}); + // test_std::transform_sender(test_std::default_domain{}, test_std::just()); // [exec.snd.apply], sender algorithm application //-dk:TODO test_std::apply_sender(test_std::default_domain{}, test_std::just_t{}, test_std::just()); diff --git a/tests/beman/execution/execution-syn.test.cpp b/tests/beman/execution/execution-syn.test.cpp index d3711046..ccd37e29 100644 --- a/tests/beman/execution/execution-syn.test.cpp +++ b/tests/beman/execution/execution-syn.test.cpp @@ -8,6 +8,17 @@ import beman.execution; import beman.execution.detail; #else +#include +#include +#include +#include +#include +#include +//-dk:TODO #include +#include +#include +#include +#include #include #include #include @@ -31,6 +42,28 @@ import beman.execution.detail; namespace { auto use(auto&&) -> void {} + +auto test_queries() -> void { + // std + static_assert( + std::same_as>); + static_assert(std::same_as>); + static_assert(std::same_as>); + + // std::execution + static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert(std::same_as>); + static_assert( + std::same_as, + std::remove_cvref_t)>>); + static_assert(std::same_as, + std::remove_cvref_t)>>); + static_assert(std::same_as>); +} + struct scheduler { struct env { template @@ -381,9 +414,15 @@ auto test_sender_adaptor() -> void { auto test_as_awaitable() -> void { static_assert(std::same_as); } + +auto test_exec_env() -> void { + test::type_exists>(); + test::type_exists>(); +} } // namespace TEST(execution_syn) { + test_queries(); test_schedule_result_t(); test_env_of_t(); test_decayed_tuple(); @@ -397,4 +436,5 @@ TEST(execution_syn) { test_sender_adaptor_closure(); test_sender_adaptor(); test_as_awaitable(); + test_exec_env(); }