diff --git a/include/beman/execution26/detail/get_domain_early.hpp b/include/beman/execution26/detail/get_domain_early.hpp new file mode 100644 index 00000000..2ea79d5a --- /dev/null +++ b/include/beman/execution26/detail/get_domain_early.hpp @@ -0,0 +1,40 @@ +// include/beman/execution26/detail/get_domain_early.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_GET_DOMAIN_EARLY +#define INCLUDED_BEMAN_EXECUTION26_DETAIL_GET_DOMAIN_EARLY + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution26::detail +{ + template + constexpr auto get_domain_early(Sender const& sender) noexcept + { + if constexpr (requires{ + ::beman::execution26::get_domain( + ::beman::execution26::get_env(sender) + ); + }) + return decltype( + ::beman::execution26::get_domain( + ::beman::execution26::get_env(sender) + ) + ){}; + else if constexpr (requires{ + ::beman::execution26::detail::completion_domain(sender); + }) + return decltype(::beman::execution26::detail::completion_domain(sender)){}; + else + return ::beman::execution26::default_domain{}; + } +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution26/detail/make_sender.hpp b/include/beman/execution26/detail/make_sender.hpp new file mode 100644 index 00000000..d3394ab6 --- /dev/null +++ b/include/beman/execution26/detail/make_sender.hpp @@ -0,0 +1,35 @@ +// include/beman/execution26/detail/make_sender.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_MAKE_SENDER +#define INCLUDED_BEMAN_EXECUTION26_DETAIL_MAKE_SENDER + +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution26::detail +{ + struct make_sender_empty {}; + + template + requires ::std::semiregular + && ::beman::execution26::detail::movable_value + && (::beman::execution26::sender && ...) + constexpr auto make_sender(Tag tag, Data&& data, Child&&... child) + { + return ::beman::execution26::detail::basic_sender< + Tag, ::std::decay_t, ::std::decay_t... + >{tag, ::std::forward(data), child...}; + } +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution26/detail/sender_adaptor.hpp b/include/beman/execution26/detail/sender_adaptor.hpp new file mode 100644 index 00000000..0572b814 --- /dev/null +++ b/include/beman/execution26/detail/sender_adaptor.hpp @@ -0,0 +1,61 @@ +// include/beman/execution26/detail/sender_adaptor.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_SENDER_ADAPTOR +#define INCLUDED_BEMAN_EXECUTION26_DETAIL_SENDER_ADAPTOR + +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution26::detail +{ + template + struct sender_adaptor + : ::beman::execution26::detail::product_type< + ::std::decay_t, ::std::decay_t, ::std::decay_t...> + , ::beman::execution26::sender_adaptor_closure> + { + template <::beman::execution26::sender Sender> + static auto apply(Sender&& sender, auto&& self) + { + using base_type = ::beman::execution26::detail::product_type< + ::std::decay_t, ::std::decay_t, ::std::decay_t...>; + static constexpr ::beman::execution26::detail::sender_any_t at{}; + if constexpr (requires{ base_type{ at, at, at, at }; }) + { + auto&&[adaptor, arg0, arg1, arg2] = self; + return adaptor(::std::forward(sender), arg0, arg1, arg2); + } + if constexpr (requires{ base_type{ at, at, at }; }) + { + auto&&[adaptor, arg0, arg1] = self; + return adaptor(::std::forward(sender), arg0, arg1); + } + else if constexpr (requires{ base_type{ at, at }; }) + { + auto&&[adaptor, arg0] = self; + return adaptor(::std::forward(sender), arg0); + } + } + template <::beman::execution26::sender Sender> + auto operator()(Sender&& sender) + { + return apply(::std::forward(sender), *this); + } + template <::beman::execution26::sender Sender> + auto operator()(Sender&& sender) const + { + return apply(::std::forward(sender), *this); + } + }; +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/include/beman/execution26/detail/sender_adaptor_closure.hpp b/include/beman/execution26/detail/sender_adaptor_closure.hpp new file mode 100644 index 00000000..6eb64cb9 --- /dev/null +++ b/include/beman/execution26/detail/sender_adaptor_closure.hpp @@ -0,0 +1,46 @@ +// include/beman/execution26/detail/sender_adaptor_closure.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef INCLUDED_BEMAN_EXECUTION26_DETAIL_SENDER_ADAPTOR_CLOSURE +#define INCLUDED_BEMAN_EXECUTION26_DETAIL_SENDER_ADAPTOR_CLOSURE + +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +namespace beman::execution26::detail::pipeable +{ + struct sender_adaptor_closure_base {}; +} + +namespace beman::execution26 +{ + template + struct sender_adaptor_closure + : ::beman::execution26::detail::pipeable::sender_adaptor_closure_base + { + }; +} + +namespace beman::execution26::detail::pipeable +{ + template <::beman::execution26::sender Sender, typename Adaptor> + requires (not ::beman::execution26::sender) + && ::std::derived_from<::std::decay_t, + ::beman::execution26::sender_adaptor_closure<::std::decay_t>> + && requires(Sender&& sender, Adaptor&& adaptor) + { + { adaptor(::std::forward(sender)) } -> ::beman::execution26::sender; + } + auto operator| (Sender&& sender, Adaptor&& adaptor) + { + return adaptor(::std::forward(sender)); + } +} + +// ---------------------------------------------------------------------------- + +#endif diff --git a/src/beman/execution26/tests/exec-snd-expos.pass.cpp b/src/beman/execution26/tests/exec-snd-expos.pass.cpp index cc8dc265..7f402fb8 100644 --- a/src/beman/execution26/tests/exec-snd-expos.pass.cpp +++ b/src/beman/execution26/tests/exec-snd-expos.pass.cpp @@ -1,6 +1,7 @@ // src/beman/execution26/tests/exe-snd-expos.pass.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -332,6 +334,17 @@ namespace auto operator== (scheduler const&) const -> bool = default; }; + template <> + struct env + { + template + auto query(test_std::get_completion_scheduler_t const&) const noexcept + -> scheduler + { + return {}; + } + }; + template <> struct env { @@ -407,8 +420,52 @@ namespace assert(result2.default_value == 74); } + auto test_get_domain_early() -> void + { + struct plain_sender + { + using sender_concept = test_std::sender_t; + }; + static_assert(test_std::sender); + static_assert(std::same_as< + test_std::default_domain, + decltype(test_detail::get_domain_early(plain_sender{})) + >); + + namespace cd = completion_domain; + static_assert(test_std::sender>); + static_assert(std::same_as< + cd::domain, + decltype(test_detail::get_domain_early(cd::sender{})) + >); + + struct sender_with_domain + { + using sender_concept = test_std::sender_t; + struct domain {}; + struct env + { + auto query(test_std::get_domain_t const&) const noexcept -> domain { return {}; } + }; + auto get_env() const noexcept -> env { return {}; } + }; + static_assert(test_std::sender); + static_assert(std::same_as< + sender_with_domain::env, + decltype(test_std::get_env(sender_with_domain{})) + >); + static_assert(std::same_as< + sender_with_domain::domain, + decltype(test_std::get_domain(sender_with_domain::env{})) + >); + static_assert(std::same_as< + sender_with_domain::domain, + decltype(test_detail::get_domain_early(sender_with_domain{})) + >); + } + template - auto test_get_domain_late(auto sender, auto env) + auto test_get_domain_late(auto sender, auto env) -> void { static_assert(test_std::sender); static_assert(test_detail::queryable); @@ -451,6 +508,7 @@ namespace { using sender_concept = test_std::sender_t; }; + static_assert(test_std::sender); test_get_domain_late(no_domain_sender{}, test_std::empty_env{}); struct scheduler_env @@ -1175,6 +1233,31 @@ namespace basic_sender::indices_for >); } + + template + auto test_make_sender() -> void + { + { + auto sender{test_detail::make_sender(tag{}, {})}; + static_assert(test_std::sender); + } + { + auto sender{test_detail::make_sender(tag{}, int{17})}; + static_assert(test_std::sender); + static_assert(std::same_as, decltype(sender)>); + } + { + static_assert(not requires{ test_detail::make_sender(tag{}, int{17}, T()); }); + } + { + auto sender{test_detail::make_sender(tag{}, int{17}, sender0{})}; + static_assert(test_std::sender); + static_assert(std::same_as< + test_detail::basic_sender, + decltype(sender) + >); + } + } } auto main() -> int @@ -1186,6 +1269,7 @@ auto main() -> int test_sched_env(); test_completion_domain(); test_query_with_default(); + test_get_domain_early(); test_get_domain_late(); test_default_impls(); test_impls_for(); @@ -1202,4 +1286,5 @@ auto main() -> int test_basic_operation(); test_completion_signatures_for(); test_basic_sender(); + test_make_sender(); } \ No newline at end of file diff --git a/src/beman/execution26/tests/execution-syn.pass.cpp b/src/beman/execution26/tests/execution-syn.pass.cpp index cce6850a..a88a3b99 100644 --- a/src/beman/execution26/tests/execution-syn.pass.cpp +++ b/src/beman/execution26/tests/execution-syn.pass.cpp @@ -1,6 +1,8 @@ // src/beman/execution26/tests/execution-syn.pass.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include +#include #include #include #include @@ -20,6 +22,7 @@ namespace { + auto use(auto&&) -> void {} struct scheduler { struct env @@ -377,6 +380,72 @@ namespace static_assert(not test_detail::decays_to); static_assert(not test_detail::decays_to); } + + template + struct adapted_sender + { + using sender_concept = test_std::sender_t; + }; + + struct closure_t + : test_std::sender_adaptor_closure + { + template + auto operator()(Sender&&) const -> adapted_sender + { + return {}; + } + }; + constexpr closure_t closure{}; + + auto test_sender_adaptor_closure() -> void + { + use(test_std::sender_adaptor_closure{}); + struct sender + { + using sender_concept = test_std::sender_t; + }; + static_assert(test_std::sender); + + static_assert(test_std::sender>); + static_assert(not test_std::sender); + + auto direct{closure(sender{})}; + static_assert(std::same_as, decltype(direct)>); + auto via_op{sender{} | closure }; + static_assert(std::same_as, decltype(via_op)>); + } + + struct arg_closure_t + { + template + auto operator()(Sender&&, int) const -> adapted_sender + { + return {}; + } + auto operator()(int value) const + { + return test_detail::sender_adaptor{{*this, value}, {}}; + } + }; + constexpr arg_closure_t arg_closure{}; + + auto test_sender_adaptor() -> void + { + struct sender + { + using sender_concept = test_std::sender_t; + }; + static_assert(test_std::sender); + + auto closure{arg_closure(17)}; + static_assert(std::same_as< + test_detail::sender_adaptor, decltype(closure)>); + auto direct{closure(sender{})}; + static_assert(std::same_as, decltype(direct)>); + auto via_op{sender{} | closure }; + static_assert(std::same_as, decltype(via_op)>); + } } auto main() -> int @@ -391,4 +460,6 @@ auto main() -> int test_single_sender(); test_conect_result_t(); test_decays_to(); + test_sender_adaptor_closure(); + test_sender_adaptor(); }