From f17525c8522360fada3b84433fac53e492fa6e50 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Mon, 12 Oct 2026 21:36:28 +0000 Subject: [PATCH] port `[de]materialize` cmplsigs computation to consteval --- include/exec/materialize.hpp | 293 +++++++++++++++++++---------------- 1 file changed, 158 insertions(+), 135 deletions(-) diff --git a/include/exec/materialize.hpp b/include/exec/materialize.hpp index 6ff354c36..bf34a2f28 100644 --- a/include/exec/materialize.hpp +++ b/include/exec/materialize.hpp @@ -17,224 +17,247 @@ #pragma once #include "../stdexec/execution.hpp" +#include "completion_signatures.hpp" namespace experimental::execution { - namespace __materialize + struct materialize_t; + struct dematerialize_t; + + struct DEMATERIALIZE_EXPECTS_VALUE_COMPLETIONS_WHERE_THE_FIRST_VALUE_IS_A_COMPLETION_TAG; + struct AN_ERROR_COMPLETION_REQUIRES_EXACTLY_ONE_ARGUMENT; + struct A_STOPPED_COMPLETION_REQUIRES_EXACTLY_ZERO_ARGUMENTS; + + namespace _materialize { using namespace STDEXEC; - template - struct __receiver + template + struct _receiver { - public: using receiver_concept = STDEXEC::receiver_tag; - constexpr __receiver(_Receiver&& __upstream) - : __upstream_{static_cast<_Receiver&&>(__upstream)} - {} - - template - constexpr void set_value(_As&&... __as) noexcept + template + constexpr void set_value(Args&&... args) noexcept { - STDEXEC::set_value(static_cast<_Receiver&&>(__upstream_), + STDEXEC::set_value(static_cast(rcvr_), set_value_t(), - static_cast<_As&&>(__as)...); + static_cast(args)...); } - template - constexpr void set_error(_Error&& __err) noexcept + template + constexpr void set_error(Error&& err) noexcept { - STDEXEC::set_value(static_cast<_Receiver&&>(__upstream_), + STDEXEC::set_value(static_cast(rcvr_), set_error_t(), - static_cast<_Error&&>(__err)); + static_cast(err)); } constexpr void set_stopped() noexcept { - STDEXEC::set_value(static_cast<_Receiver&&>(__upstream_), set_stopped_t()); + STDEXEC::set_value(static_cast(rcvr_), set_stopped_t()); } [[nodiscard]] - constexpr auto get_env() const noexcept -> env_of_t<_Receiver> + constexpr auto get_env() const noexcept -> env_of_t { - return STDEXEC::get_env(__upstream_); + return STDEXEC::get_env(rcvr_); } - private: - _Receiver __upstream_; + Receiver rcvr_; }; - template - struct __sender + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE _receiver(Receiver) -> _receiver; + + template + static constexpr auto _materialize_cmplsigs = []() noexcept { - public: - using sender_concept = STDEXEC::sender_tag; + return completion_signatures(); + }; - template <__decays_to<_Sender> _Sndr> - constexpr explicit __sender(_Sndr&& __sender) - : __sndr_{static_cast<_Sndr&&>(__sender)} - {} + template + struct _sender + { + using sender_concept = STDEXEC::sender_tag; - template <__decays_to<__sender> _Self, class _Receiver> - requires sender_to<__copy_cvref_t<_Self, _Sender>, __materialize::__receiver<_Receiver>> - STDEXEC_EXPLICIT_THIS_BEGIN(auto connect)(this _Self&& __self, _Receiver __rcvr) noexcept( - __nothrow_connectable<__copy_cvref_t<_Self, _Sender>, __materialize::__receiver<_Receiver>>) - -> connect_result_t<__copy_cvref_t<_Self, _Sender>, __materialize::__receiver<_Receiver>> + template <__decays_to<_sender> Self, class Receiver> + STDEXEC_EXPLICIT_THIS_BEGIN(auto connect)(this Self&& self, Receiver rcvr) + noexcept(__nothrow_connectable<__copy_cvref_t, _receiver>) + -> connect_result_t<__copy_cvref_t, _receiver> { - return STDEXEC::connect(static_cast<_Self&&>(__self).__sndr_, - __materialize::__receiver<_Receiver>{ - static_cast<_Receiver&&>(__rcvr)}); + return STDEXEC::connect(static_cast(self).sndr_, + _receiver{static_cast(rcvr)}); } STDEXEC_EXPLICIT_THIS_END(connect) - template - using __materialize_value = completion_signatures; - - template - using __materialize_error = completion_signatures; - - template - using __completions_t = __transform_reduce_completion_signatures_t< - __completion_signatures_of_t<__copy_cvref_t<_Self, _Sender>, _Env...>, - __materialize_value, - __materialize_error, - completion_signatures, - __mconcat<__qq>::__f>; - - template <__decays_to<__sender> _Self, class... _Env> - static consteval auto get_completion_signatures() -> __completions_t<_Self, _Env...> + template <__decays_to<_sender> Self, class... Env> + static consteval auto get_completion_signatures() { - return {}; + return exec::transform_completion_signatures( + STDEXEC::get_completion_signatures<__copy_cvref_t, Env...>(), + _materialize_cmplsigs, + _materialize_cmplsigs, + _materialize_cmplsigs); } - private: - _Sender __sndr_; - }; - - struct __materialize_t - { - template - constexpr auto operator()(_Sender&& __sndr) const noexcept(__nothrow_decay_copyable<_Sender>) - -> __sender<__decay_t<_Sender>> + [[nodiscard]] + constexpr auto get_env() const noexcept -> env_of_t { - return __sender<__decay_t<_Sender>>{static_cast<_Sender&&>(__sndr)}; + return STDEXEC::get_env(sndr_); } - STDEXEC_ATTRIBUTE(always_inline) - auto operator()() const noexcept - { - return __closure(*this); - } + Sender sndr_; }; - } // namespace __materialize - inline constexpr __materialize::__materialize_t materialize; + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE _sender(Sender) -> _sender; + } // namespace _materialize - namespace __dematerialize + namespace _dematerialize { using namespace STDEXEC; - template - struct __receiver + template + struct _receiver { - public: using receiver_concept = STDEXEC::receiver_tag; - constexpr __receiver(_Receiver&& __upstream) - : __upstream_{static_cast<_Receiver&&>(__upstream)} - {} - - template <__completion_tag _Tag, class... _Args> - requires __callable<_Tag, _Receiver, _Args...> - void set_value(_Tag, _Args&&... __args) noexcept + template <__completion_tag Tag, class... Args> + requires __callable + void set_value(Tag, Args&&... args) noexcept { - _Tag()(static_cast<_Receiver&&>(__upstream_), static_cast<_Args&&>(__args)...); + Tag()(static_cast(rcvr_), static_cast(args)...); } template constexpr void set_error(Error&& err) noexcept { - STDEXEC::set_error(static_cast<_Receiver&&>(__upstream_), static_cast(err)); + STDEXEC::set_error(static_cast(rcvr_), static_cast(err)); } constexpr void set_stopped() noexcept { - STDEXEC::set_stopped(static_cast<_Receiver&&>(__upstream_)); + STDEXEC::set_stopped(static_cast(rcvr_)); } [[nodiscard]] - constexpr auto get_env() const noexcept -> env_of_t<_Receiver> + constexpr auto get_env() const noexcept -> env_of_t { - return STDEXEC::get_env(__upstream_); + return STDEXEC::get_env(rcvr_); } - private: - _Receiver __upstream_; + Receiver rcvr_; }; - template - struct __sender + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE _receiver(Receiver) -> _receiver; + + static constexpr auto _dematerialize_cmplsigs = []() { - public: - using sender_concept = STDEXEC::sender_tag; + using tag_t = __decay_t; + if constexpr (!__completion_tag) + { + return exec::throw_compile_time_error< + _WHAT_(_INVALID_ARGUMENT_), + _WHY_(DEMATERIALIZE_EXPECTS_VALUE_COMPLETIONS_WHERE_THE_FIRST_VALUE_IS_A_COMPLETION_TAG), + _WHERE_(_IN_ALGORITHM_, dematerialize_t), + __if_c<__same_as, _WITH_ARGUMENTS_(), _WITH_ARGUMENTS_(Tag, Args...)>>(); + } + else if constexpr (tag_t() == set_error && sizeof...(Args) != 1) + { + return exec::throw_compile_time_error< // + _WHAT_(_INVALID_ARGUMENT_), + _WHY_(AN_ERROR_COMPLETION_REQUIRES_EXACTLY_ONE_ARGUMENT), + _WHERE_(_IN_ALGORITHM_, dematerialize_t), + _WITH_ARGUMENTS_(Args...)>(); + } + else if constexpr (tag_t() == set_stopped && sizeof...(Args) != 0) + { + return exec::throw_compile_time_error< // + _WHAT_(_INVALID_ARGUMENT_), + _WHY_(A_STOPPED_COMPLETION_REQUIRES_EXACTLY_ZERO_ARGUMENTS), + _WHERE_(_IN_ALGORITHM_, dematerialize_t), + _WITH_ARGUMENTS_(Args...)>(); + } + else + { + return completion_signatures(); + } + }; - template <__decays_to<_Sender> _Sndr> - constexpr explicit __sender(_Sndr&& __sndr) noexcept(__nothrow_decay_copyable<_Sndr>) - : __sndr_{static_cast<_Sndr&&>(__sndr)} - {} + template + struct _sender + { + using sender_concept = STDEXEC::sender_tag; - template <__decays_to<__sender> _Self, class _Receiver> - requires sender_to<__copy_cvref_t<_Self, _Sender>, __dematerialize::__receiver<_Receiver>> - STDEXEC_EXPLICIT_THIS_BEGIN(auto connect)(this _Self&& __self, _Receiver __rcvr) noexcept( - __nothrow_connectable<__copy_cvref_t<_Self, _Sender>, - __dematerialize::__receiver<_Receiver>>) - -> connect_result_t<__copy_cvref_t<_Self, _Sender>, __dematerialize::__receiver<_Receiver>> + template <__decays_to<_sender> Self, class Receiver> + requires sender_to<__copy_cvref_t, _receiver> + STDEXEC_EXPLICIT_THIS_BEGIN(auto connect)(this Self&& self, Receiver rcvr) + noexcept(__nothrow_connectable<__copy_cvref_t, _receiver>) + -> connect_result_t<__copy_cvref_t, _receiver> { - return STDEXEC::connect(static_cast<_Self&&>(__self).__sndr_, - __dematerialize::__receiver<_Receiver>{ - static_cast<_Receiver&&>(__rcvr)}); + return STDEXEC::connect(static_cast(self).sndr_, + _receiver{static_cast(rcvr)}); } STDEXEC_EXPLICIT_THIS_END(connect) - template - requires __completion_tag<__decay_t<_Tag>> - using __dematerialize_value = completion_signatures<__decay_t<_Tag>(_Args...)>; - - template - using __completions_t = __transform_completion_signatures_t< - __completion_signatures_of_t<__copy_cvref_t<_Self, _Sender>, _Env...>, - completion_signatures<>, - __mtry_q<__dematerialize_value>::template __f>; + template <__decays_to<_sender> Self, class... Env> + static consteval auto get_completion_signatures() + { + return exec::transform_completion_signatures( + STDEXEC::get_completion_signatures<__copy_cvref_t, Env...>(), + _dematerialize_cmplsigs); + } - template <__decays_to<__sender> _Self, class... _Env> - static consteval auto get_completion_signatures() -> __completions_t<_Self, _Env...> + [[nodiscard]] + constexpr auto get_env() const noexcept -> env_of_t { - return {}; + return STDEXEC::get_env(sndr_); } - private: - _Sender __sndr_; + Sender sndr_; }; - struct __dematerialize_t + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE _sender(Sender) -> _sender; + } // namespace _dematerialize + + struct materialize_t + { + template + constexpr auto operator()(Sender&& sndr) const // + noexcept(STDEXEC::__nothrow_decay_copyable) { - template - constexpr auto operator()(_Sender&& __sndr) const noexcept(__nothrow_decay_copyable<_Sender>) - -> __sender<__decay_t<_Sender>> - { - return __sender<__decay_t<_Sender>>(static_cast<_Sender&&>(__sndr)); - } + return _materialize::_sender{static_cast(sndr)}; + } - STDEXEC_ATTRIBUTE(always_inline) - constexpr auto operator()() const noexcept - { - return __closure(*this); - } - }; - } // namespace __dematerialize + STDEXEC_ATTRIBUTE(always_inline) + auto operator()() const noexcept + { + return STDEXEC::__closure(*this); + } + }; + + inline constexpr materialize_t materialize{}; + + struct dematerialize_t + { + template + constexpr auto operator()(Sender&& sndr) const // + noexcept(STDEXEC::__nothrow_decay_copyable) + { + return _dematerialize::_sender{static_cast(sndr)}; + } + + STDEXEC_ATTRIBUTE(always_inline) + constexpr auto operator()() const noexcept + { + return STDEXEC::__closure(*this); + } + }; - inline constexpr __dematerialize::__dematerialize_t dematerialize; + inline constexpr dematerialize_t dematerialize{}; } // namespace experimental::execution namespace exec = experimental::execution;