From dfd2b85da1c9272986ccc138d6862681857d3bfa Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 8 Oct 2026 05:34:46 +0000 Subject: [PATCH 1/4] remove unnecessary `__make_sexpr` helper --- include/exec/ensure_started.hpp | 8 ++--- include/exec/fork_join.hpp | 6 ++-- include/exec/into_tuple.hpp | 2 +- include/exec/repeat_n.hpp | 2 +- include/exec/repeat_until.hpp | 4 +-- include/exec/sequence/ignore_all_values.hpp | 2 +- include/exec/split.hpp | 6 ++-- include/exec/timed_scheduler.hpp | 27 +++++++------- include/exec/unless_stop_requested.hpp | 2 +- include/stdexec/__detail/__affine.hpp | 2 +- include/stdexec/__detail/__associate.hpp | 5 +-- include/stdexec/__detail/__basic_sender.hpp | 36 +++---------------- include/stdexec/__detail/__bulk.hpp | 7 ++-- include/stdexec/__detail/__continues_on.hpp | 5 +-- .../stdexec/__detail/__counting_scopes.hpp | 4 +-- include/stdexec/__detail/__finally.hpp | 7 ++-- include/stdexec/__detail/__into_variant.hpp | 2 +- include/stdexec/__detail/__just.hpp | 6 ++-- include/stdexec/__detail/__let.hpp | 2 +- include/stdexec/__detail/__on.hpp | 10 +++--- include/stdexec/__detail/__read_env.hpp | 2 +- include/stdexec/__detail/__schedule_from.hpp | 2 +- .../__detail/__sender_introspection.hpp | 1 + include/stdexec/__detail/__sequence.hpp | 2 +- include/stdexec/__detail/__spawn_future.hpp | 3 +- include/stdexec/__detail/__starts_on.hpp | 5 +-- include/stdexec/__detail/__stop_when.hpp | 5 +-- .../stdexec/__detail/__stopped_as_error.hpp | 5 +-- .../__detail/__stopped_as_optional.hpp | 2 +- include/stdexec/__detail/__sync_wait.hpp | 18 +++++----- include/stdexec/__detail/__then.hpp | 2 +- include/stdexec/__detail/__transfer_just.hpp | 6 ++-- include/stdexec/__detail/__upon_error.hpp | 2 +- include/stdexec/__detail/__upon_stopped.hpp | 3 +- include/stdexec/__detail/__when_all.hpp | 21 ++++++----- include/stdexec/__detail/__write_env.hpp | 3 +- .../exec/sequence/test_write_env_sequence.cpp | 2 +- test/test_common/scope_helpers.hpp | 2 +- 38 files changed, 109 insertions(+), 122 deletions(-) diff --git a/include/exec/ensure_started.hpp b/include/exec/ensure_started.hpp index 6f1041882..26dc704f8 100644 --- a/include/exec/ensure_started.hpp +++ b/include/exec/ensure_started.hpp @@ -51,10 +51,10 @@ namespace experimental::execution } else { - return STDEXEC::transform_sender( - STDEXEC::__make_sexpr(static_cast<_Env&&>(__env), - static_cast<_CvSender&&>(__sndr)), - __env); + return STDEXEC::transform_sender(STDEXEC::__sexpr{ensure_started_t(), + static_cast<_Env&&>(__env), + static_cast<_CvSender&&>(__sndr)}, + __env); } } diff --git a/include/exec/fork_join.hpp b/include/exec/fork_join.hpp index f093df9f5..7082bd56a 100644 --- a/include/exec/fork_join.hpp +++ b/include/exec/fork_join.hpp @@ -287,9 +287,9 @@ namespace experimental::execution constexpr auto operator()(Sndr&& sndr, Closures&&... closures) const // -> STDEXEC::__well_formed_sender auto { - return STDEXEC::__make_sexpr(STDEXEC::__tuple{static_cast( - closures)...}, - static_cast(sndr)); + return STDEXEC::__sexpr{fork_join_t(), + STDEXEC::__tuple{static_cast(closures)...}, + static_cast(sndr)}; } template diff --git a/include/exec/into_tuple.hpp b/include/exec/into_tuple.hpp index 2a7fd6f7c..fa881ce47 100644 --- a/include/exec/into_tuple.hpp +++ b/include/exec/into_tuple.hpp @@ -113,7 +113,7 @@ namespace experimental::execution template constexpr auto operator()(_Sender &&__sndr) const { - return __make_sexpr({}, static_cast<_Sender &&>(__sndr)); + return __sexpr{into_tuple_t(), __(), static_cast<_Sender &&>(__sndr)}; } STDEXEC_ATTRIBUTE(always_inline) diff --git a/include/exec/repeat_n.hpp b/include/exec/repeat_n.hpp index e899c5150..aa40d3e25 100644 --- a/include/exec/repeat_n.hpp +++ b/include/exec/repeat_n.hpp @@ -260,7 +260,7 @@ namespace experimental::execution constexpr auto operator()(_Sender &&__sndr, std::size_t __count) const // -> STDEXEC::__well_formed_sender auto { - return STDEXEC::__make_sexpr(__count, static_cast<_Sender &&>(__sndr)); + return STDEXEC::__sexpr{repeat_n_t(), __count, static_cast<_Sender &&>(__sndr)}; } STDEXEC_ATTRIBUTE(always_inline) diff --git a/include/exec/repeat_until.hpp b/include/exec/repeat_until.hpp index 9849e64c6..b25929004 100644 --- a/include/exec/repeat_until.hpp +++ b/include/exec/repeat_until.hpp @@ -343,7 +343,7 @@ namespace experimental::execution template constexpr auto operator()(_Sender &&__sndr) const -> STDEXEC::__well_formed_sender auto { - return STDEXEC::__make_sexpr({}, static_cast<_Sender &&>(__sndr)); + return STDEXEC::__sexpr{repeat_until_t(), STDEXEC::__(), static_cast<_Sender &&>(__sndr)}; } STDEXEC_ATTRIBUTE(always_inline) @@ -360,7 +360,7 @@ namespace experimental::execution template constexpr auto operator()(_Sender &&__sndr) const -> STDEXEC::__well_formed_sender auto { - return STDEXEC::__make_sexpr({}, static_cast<_Sender &&>(__sndr)); + return STDEXEC::__sexpr{repeat_t(), STDEXEC::__(), static_cast<_Sender &&>(__sndr)}; } STDEXEC_ATTRIBUTE(always_inline) diff --git a/include/exec/sequence/ignore_all_values.hpp b/include/exec/sequence/ignore_all_values.hpp index 0ca0e9ddb..59293ee52 100644 --- a/include/exec/sequence/ignore_all_values.hpp +++ b/include/exec/sequence/ignore_all_values.hpp @@ -301,7 +301,7 @@ namespace experimental::execution template auto operator()(_Sender&& __sndr) const { - return __make_sexpr(__(), static_cast<_Sender&&>(__sndr)); + return __sexpr{ignore_all_values_t(), __(), static_cast<_Sender&&>(__sndr)}; } STDEXEC_ATTRIBUTE(always_inline) diff --git a/include/exec/split.hpp b/include/exec/split.hpp index a35cda860..221531cfa 100644 --- a/include/exec/split.hpp +++ b/include/exec/split.hpp @@ -35,9 +35,9 @@ namespace experimental::execution auto operator()(_CvSender&& __sndr, _Env&& __env = {}) const -> STDEXEC::__well_formed_sender auto { - return STDEXEC::transform_sender(STDEXEC::__make_sexpr(static_cast<_Env&&>(__env), - static_cast<_CvSender&&>( - __sndr)), + return STDEXEC::transform_sender(STDEXEC::__sexpr{split_t(), + static_cast<_Env&&>(__env), + static_cast<_CvSender&&>(__sndr)}, __env); } diff --git a/include/exec/timed_scheduler.hpp b/include/exec/timed_scheduler.hpp index 86de81096..4ef4e5534 100644 --- a/include/exec/timed_scheduler.hpp +++ b/include/exec/timed_scheduler.hpp @@ -212,17 +212,18 @@ namespace experimental::execution auto operator()(_Scheduler &&__sched, const duration_of_t<_Scheduler> &__duration) const noexcept { + using __sched_t = __decay_t<_Scheduler>; using __native_sender_t = __call_result_t<__schedule_at_base_t, _Scheduler, time_point_of_t<_Scheduler> const &>; - return __make_sexpr<__timed_scheduler_fallback::__tag>( - __timed_scheduler_fallback::__data, __native_sender_t>{ - __sched}, + return __sexpr{ + __timed_scheduler_fallback::__tag(), + __timed_scheduler_fallback::__data<__sched_t, __native_sender_t>{__sched}, let_value(just(), [__sched, __duration]() noexcept( - __nothrow_callable> - &&__nothrow_callable) - { return schedule_at(__sched, now(__sched) + __duration); })); + __nothrow_callable> + &&__nothrow_callable) + { return schedule_at(__sched, now(__sched) + __duration); })}; } }; } // namespace __schedule_after @@ -277,16 +278,16 @@ namespace experimental::execution auto operator()(_Scheduler &&__sched, const time_point_of_t<_Scheduler> &__time_point) const noexcept(noexcept(schedule_after(__sched, __time_point - now(__sched)))) { + using __sched_t = __decay_t<_Scheduler>; using __native_sender_t = __call_result_t<__schedule_after_base_t, _Scheduler, duration_of_t<_Scheduler> const &>; - return __make_sexpr<__timed_scheduler_fallback::__tag>( - __timed_scheduler_fallback::__data, __native_sender_t>{ - __sched}, - let_value(just(), - [__sched, __time_point]() noexcept( - noexcept(schedule_after(__sched, __time_point - now(__sched)))) - { return schedule_after(__sched, __time_point - now(__sched)); })); + return __sexpr{__timed_scheduler_fallback::__tag(), + __timed_scheduler_fallback::__data<__sched_t, __native_sender_t>{__sched}, + let_value(just(), + [__sched, __time_point]() noexcept( + noexcept(schedule_after(__sched, __time_point - now(__sched)))) + { return schedule_after(__sched, __time_point - now(__sched)); })}; } }; } // namespace __schedule_at diff --git a/include/exec/unless_stop_requested.hpp b/include/exec/unless_stop_requested.hpp index 0ebcc7f1c..bab6ade27 100644 --- a/include/exec/unless_stop_requested.hpp +++ b/include/exec/unless_stop_requested.hpp @@ -83,7 +83,7 @@ namespace experimental::execution [[nodiscard]] constexpr __well_formed_sender auto operator()(_Sender&& __sndr) const { - return __make_sexpr({}, static_cast<_Sender&&>(__sndr)); + return __sexpr{unless_stop_requested_t(), __(), static_cast<_Sender&&>(__sndr)}; } }; diff --git a/include/stdexec/__detail/__affine.hpp b/include/stdexec/__detail/__affine.hpp index 0ee56019e..7230bcf7c 100644 --- a/include/stdexec/__detail/__affine.hpp +++ b/include/stdexec/__detail/__affine.hpp @@ -66,7 +66,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender &&__sndr) const -> __well_formed_sender auto { - return __make_sexpr({}, static_cast<_Sender &&>(__sndr)); + return __sexpr{affine_t(), __(), static_cast<_Sender &&>(__sndr)}; } constexpr auto operator()() const noexcept diff --git a/include/stdexec/__detail/__associate.hpp b/include/stdexec/__detail/__associate.hpp index e998353ee..824b1ada8 100644 --- a/include/stdexec/__detail/__associate.hpp +++ b/include/stdexec/__detail/__associate.hpp @@ -165,8 +165,9 @@ namespace STDEXEC _Token, _Sender>) -> __well_formed_sender auto { - return __make_sexpr( - __associate_data(static_cast<_Token&&>(__token), static_cast<_Sender&&>(__sndr))); + return __sexpr{associate_t(), + __associate_data(static_cast<_Token&&>(__token), + static_cast<_Sender&&>(__sndr))}; } template diff --git a/include/stdexec/__detail/__basic_sender.hpp b/include/stdexec/__detail/__basic_sender.hpp index ab89a3d8c..9d823f450 100644 --- a/include/stdexec/__detail/__basic_sender.hpp +++ b/include/stdexec/__detail/__basic_sender.hpp @@ -332,9 +332,6 @@ namespace STDEXEC struct __sexpr_impl : __sexpr_defaults {}; - template - using __sexpr_t = __sexpr; - //! A dummy type used only for diagnostic purposes. //! See `__sexpr` for the implementation of P2300's _`basic-sender`_. STDEXEC_MODULE_EXPORT_AUTHORING @@ -355,14 +352,15 @@ namespace STDEXEC //! P2300's [_`basic-sender`_](https://eel.is/c++draft/exec#snd.expos-24), //! but is not an exact implementation. Note: The struct named //! `__basic_sender` is just a dummy type and is also not _`basic-sender`_. + STDEXEC_MODULE_EXPORT_AUTHORING template - struct __sexpr : __minvoke> + struct __sexpr : __mcall1> { using sender_concept = sender_tag; using __desc_t = decltype(_DescriptorFn()); using __tag_t = __desc_t::__tag; - using __base_t = __minvoke<__desc_t, __qq<__tuple>>; + using __base_t = __mcall1<__desc_t, __qq<__tuple>>; using __get_attrs_t = __mtypeof<__sexpr_impl<__tag_t>::__get_attrs>; using __attrs_t = __apply_result_t<__get_attrs_t, __base_t const &>; @@ -450,32 +448,6 @@ namespace STDEXEC } // anonymous namespace # endif - ////////////////////////////////////////////////////////////////////////////// - // __make_sexpr - //! A tagged function-object - //! Takes data and children and - //! returns `__sexpr_t<_Tag, _Data, _Child...>{_Tag(), data, children...}`. - namespace __detail - { - template - struct __make_sexpr_t - { - template - constexpr auto operator()(_Data&& __data = {}, _Child&&... __child) const - noexcept(__nothrow_decay_copyable<_Data, _Child...>) - -> __sexpr_t<_Tag, __decay_t<_Data>, __decay_t<_Child>...> - { - return { - {_Tag(), static_cast<_Data&&>(__data), static_cast<_Child&&>(__child)...} - }; - } - }; - } // namespace __detail - - STDEXEC_MODULE_EXPORT_AUTHORING - template - inline constexpr __detail::__make_sexpr_t<_Tag> __make_sexpr{}; - // The __demangle_t utility defined below is used to pretty-print the type // names of senders in compiler diagnostics. namespace __detail @@ -484,7 +456,7 @@ namespace STDEXEC using __basic_sender_t = __basic_sender<_Tag, _Data, __demangle_t<_Child>...>::type; template - extern __mtype<__minvoke>> + extern __mtype<__mcall1>> __demangle_v<__sexpr<_Descriptor>>; } // namespace __detail } // namespace STDEXEC diff --git a/include/stdexec/__detail/__bulk.hpp b/include/stdexec/__detail/__bulk.hpp index 11aa2f29b..8cb524d3e 100644 --- a/include/stdexec/__detail/__bulk.hpp +++ b/include/stdexec/__detail/__bulk.hpp @@ -141,8 +141,11 @@ namespace STDEXEC constexpr auto operator()(_Sender&& __sndr, _Policy&& __pol, _Shape __shape, _Fun __fun) const -> __well_formed_sender auto { - return __make_sexpr<_AlgoTag>(__data{__pol, __shape, static_cast<_Fun&&>(__fun)}, - static_cast<_Sender&&>(__sndr)); + return __sexpr{ + _AlgoTag(), + __data{__pol, __shape, static_cast<_Fun&&>(__fun)}, + static_cast<_Sender&&>(__sndr) + }; } template diff --git a/include/stdexec/__detail/__continues_on.hpp b/include/stdexec/__detail/__continues_on.hpp index f1f805c07..23db12d7d 100644 --- a/include/stdexec/__detail/__continues_on.hpp +++ b/include/stdexec/__detail/__continues_on.hpp @@ -474,8 +474,9 @@ namespace STDEXEC constexpr auto operator()(_Sender&& __sndr, _Scheduler __sched) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Scheduler&&>(__sched), - schedule_from(static_cast<_Sender&&>(__sndr))); + return __sexpr{continues_on_t(), + static_cast<_Scheduler&&>(__sched), + schedule_from(static_cast<_Sender&&>(__sndr))}; } //! @brief Construct a sender-adaptor closure that, when applied to a diff --git a/include/stdexec/__detail/__counting_scopes.hpp b/include/stdexec/__detail/__counting_scopes.hpp index c62ed8919..035e9054d 100644 --- a/include/stdexec/__detail/__counting_scopes.hpp +++ b/include/stdexec/__detail/__counting_scopes.hpp @@ -796,7 +796,7 @@ namespace STDEXEC sender auto join() noexcept { // [exec.simple.counting.mem] paragraph 4 - return __make_sexpr<__counting_scopes::__scope_join_t>(this); + return __sexpr{__counting_scopes::__scope_join_t(), this}; } private: @@ -869,7 +869,7 @@ namespace STDEXEC [[nodiscard]] sender auto join() noexcept { - return __make_sexpr<__counting_scopes::__scope_join_t>(this); + return __sexpr{__counting_scopes::__scope_join_t(), this}; } void request_stop() noexcept diff --git a/include/stdexec/__detail/__finally.hpp b/include/stdexec/__detail/__finally.hpp index d83599163..22ccae963 100644 --- a/include/stdexec/__detail/__finally.hpp +++ b/include/stdexec/__detail/__finally.hpp @@ -57,9 +57,10 @@ namespace STDEXEC constexpr auto operator()(_Initial&& __initial, _Final&& __final) const // -> __well_formed_sender auto { - return __make_sexpr<__finally_t>({}, - static_cast<_Initial&&>(__initial), - static_cast<_Final&&>(__final)); + return __sexpr{__finally_t(), + __(), + static_cast<_Initial&&>(__initial), + static_cast<_Final&&>(__final)}; } template diff --git a/include/stdexec/__detail/__into_variant.hpp b/include/stdexec/__detail/__into_variant.hpp index f95b77172..bb815c24f 100644 --- a/include/stdexec/__detail/__into_variant.hpp +++ b/include/stdexec/__detail/__into_variant.hpp @@ -203,7 +203,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr) const -> __well_formed_sender auto { - return __make_sexpr(__(), static_cast<_Sender&&>(__sndr)); + return __sexpr{into_variant_t(), __(), static_cast<_Sender&&>(__sndr)}; } //! @brief Construct a sender-adaptor closure that, when applied to a diff --git a/include/stdexec/__detail/__just.hpp b/include/stdexec/__detail/__just.hpp index 45e804d42..25ebbc9e3 100644 --- a/include/stdexec/__detail/__just.hpp +++ b/include/stdexec/__detail/__just.hpp @@ -173,7 +173,7 @@ namespace STDEXEC STDEXEC_ATTRIBUTE(host, device) constexpr auto operator()(_Ts&&... __ts) const noexcept(__nothrow_decay_copyable<_Ts...>) { - return __make_sexpr(__tuple{static_cast<_Ts&&>(__ts)...}); + return __sexpr{just_t(), __tuple{static_cast<_Ts&&>(__ts)...}}; } }; @@ -234,7 +234,7 @@ namespace STDEXEC STDEXEC_ATTRIBUTE(host, device) constexpr auto operator()(_Error&& __err) const noexcept(__nothrow_decay_copyable<_Error>) { - return __make_sexpr(__tuple{static_cast<_Error&&>(__err)}); + return __sexpr{just_error_t(), __tuple{static_cast<_Error&&>(__err)}}; } }; @@ -288,7 +288,7 @@ namespace STDEXEC STDEXEC_ATTRIBUTE(host, device) constexpr auto operator()() const noexcept { - return __make_sexpr<_Tag>(__tuple{}); + return __sexpr{_Tag(), __tuple{}}; } }; diff --git a/include/stdexec/__detail/__let.hpp b/include/stdexec/__detail/__let.hpp index bddac89e8..97a555bdb 100644 --- a/include/stdexec/__detail/__let.hpp +++ b/include/stdexec/__detail/__let.hpp @@ -516,7 +516,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr, _Fun __fn) const -> __well_formed_sender auto { - return __make_sexpr<_LetTag>(static_cast<_Fun&&>(__fn), static_cast<_Sender&&>(__sndr)); + return __sexpr{_LetTag(), static_cast<_Fun&&>(__fn), static_cast<_Sender&&>(__sndr)}; } template diff --git a/include/stdexec/__detail/__on.hpp b/include/stdexec/__detail/__on.hpp index 4e48e093c..6071a30b8 100644 --- a/include/stdexec/__detail/__on.hpp +++ b/include/stdexec/__detail/__on.hpp @@ -301,7 +301,7 @@ namespace STDEXEC constexpr auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Scheduler&&>(__sched), static_cast<_Sender&&>(__sndr)); + return __sexpr{on_t(), static_cast<_Scheduler&&>(__sched), static_cast<_Sender&&>(__sndr)}; } //! @brief Form 2: run @c __sndr in place, hop to @c __sched, apply @@ -325,9 +325,11 @@ namespace STDEXEC constexpr auto operator()(_Sender&& __sndr, _Scheduler&& __sched, _Closure&& __clsur) const -> __well_formed_sender auto { - return __make_sexpr(__tuple{static_cast<_Scheduler&&>(__sched), - static_cast<_Closure&&>(__clsur)}, - static_cast<_Sender&&>(__sndr)); + return __sexpr{ + on_t(), + __tuple{static_cast<_Scheduler&&>(__sched), static_cast<_Closure&&>(__clsur)}, + static_cast<_Sender&&>(__sndr) + }; } //! @brief Pipe form of Form 2: construct a sender-adaptor closure that, diff --git a/include/stdexec/__detail/__read_env.hpp b/include/stdexec/__detail/__read_env.hpp index ae52f95de..af8e503c8 100644 --- a/include/stdexec/__detail/__read_env.hpp +++ b/include/stdexec/__detail/__read_env.hpp @@ -165,7 +165,7 @@ namespace STDEXEC template constexpr auto operator()(_Query) const noexcept { - return __make_sexpr<__read_env_t>(_Query()); + return __sexpr{__read_env_t(), _Query()}; } }; diff --git a/include/stdexec/__detail/__schedule_from.hpp b/include/stdexec/__detail/__schedule_from.hpp index f1f8259d1..7bbd048bd 100644 --- a/include/stdexec/__detail/__schedule_from.hpp +++ b/include/stdexec/__detail/__schedule_from.hpp @@ -42,7 +42,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr) const { - return __make_sexpr({}, static_cast<_Sender&&>(__sndr)); + return __sexpr{schedule_from_t(), __(), static_cast<_Sender&&>(__sndr)}; } }; diff --git a/include/stdexec/__detail/__sender_introspection.hpp b/include/stdexec/__detail/__sender_introspection.hpp index 45c64aee7..0fbfe11de 100644 --- a/include/stdexec/__detail/__sender_introspection.hpp +++ b/include/stdexec/__detail/__sender_introspection.hpp @@ -41,6 +41,7 @@ STDEXEC_PRAGMA_IGNORE_GNU("-Wc++26-extensions") namespace STDEXEC { # if STDEXEC_USE_MODULES() + STDEXEC_MODULE_EXPORT_AUTHORING template struct __sexpr; # else diff --git a/include/stdexec/__detail/__sequence.hpp b/include/stdexec/__detail/__sequence.hpp index d2849b45e..28a703b18 100644 --- a/include/stdexec/__detail/__sequence.hpp +++ b/include/stdexec/__detail/__sequence.hpp @@ -465,7 +465,7 @@ namespace STDEXEC constexpr auto operator()(_Senders &&...__sndrs) const // noexcept(__nothrow_decay_copyable<_Senders...>) -> __well_formed_sender auto { - return __make_sexpr<__sequence_t>({}, static_cast<_Senders &&>(__sndrs)...); + return __sexpr{__sequence_t(), __(), static_cast<_Senders &&>(__sndrs)...}; } template diff --git a/include/stdexec/__detail/__spawn_future.hpp b/include/stdexec/__detail/__spawn_future.hpp index f466a7a98..83c8aa0f3 100644 --- a/include/stdexec/__detail/__spawn_future.hpp +++ b/include/stdexec/__detail/__spawn_future.hpp @@ -934,8 +934,7 @@ namespace STDEXEC } }; - return __make_sexpr( - std::unique_ptr<__spawn_future_state_t, __abandoner>(__op)); + return __sexpr{spawn_future_t(), std::unique_ptr<__spawn_future_state_t, __abandoner>(__op)}; } }; diff --git a/include/stdexec/__detail/__starts_on.hpp b/include/stdexec/__detail/__starts_on.hpp index ac1962cd3..ad8209523 100644 --- a/include/stdexec/__detail/__starts_on.hpp +++ b/include/stdexec/__detail/__starts_on.hpp @@ -196,8 +196,9 @@ namespace STDEXEC constexpr auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Scheduler&&>(__sched), - static_cast<_Sender&&>(__sndr)); + return __sexpr{starts_on_t(), + static_cast<_Scheduler&&>(__sched), + static_cast<_Sender&&>(__sndr)}; } template <__decay_copyable _Sender> diff --git a/include/stdexec/__detail/__stop_when.hpp b/include/stdexec/__detail/__stop_when.hpp index db08af057..abec35ec4 100644 --- a/include/stdexec/__detail/__stop_when.hpp +++ b/include/stdexec/__detail/__stop_when.hpp @@ -72,8 +72,9 @@ namespace STDEXEC constexpr auto operator()(_Sender&& __sndr, _Token&& __token) const noexcept(__nothrow_decay_copyable<_Sender> && __nothrow_decay_copyable<_Token>) { - return __make_sexpr<__stop_when_t>(static_cast<_Token&&>(__token), - static_cast<_Sender&&>(__sndr)); + return __sexpr{__stop_when_t(), + static_cast<_Token&&>(__token), + static_cast<_Sender&&>(__sndr)}; } }; diff --git a/include/stdexec/__detail/__stopped_as_error.hpp b/include/stdexec/__detail/__stopped_as_error.hpp index 2d1efa6d6..1371bdc12 100644 --- a/include/stdexec/__detail/__stopped_as_error.hpp +++ b/include/stdexec/__detail/__stopped_as_error.hpp @@ -145,8 +145,9 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr, _Error __err) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Error&&>(__err), - static_cast<_Sender&&>(__sndr)); + return __sexpr{stopped_as_error_t(), + static_cast<_Error&&>(__err), + static_cast<_Sender&&>(__sndr)}; } //! @brief Construct a sender-adaptor closure for the pipe form. diff --git a/include/stdexec/__detail/__stopped_as_optional.hpp b/include/stdexec/__detail/__stopped_as_optional.hpp index e4ba34da8..a8c2f05bd 100644 --- a/include/stdexec/__detail/__stopped_as_optional.hpp +++ b/include/stdexec/__detail/__stopped_as_optional.hpp @@ -246,7 +246,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr) const -> __well_formed_sender auto { - return __make_sexpr(__(), static_cast<_Sender&&>(__sndr)); + return __sexpr{stopped_as_optional_t(), __(), static_cast<_Sender&&>(__sndr)}; } //! @brief Construct a sender-adaptor closure for the pipe form. diff --git a/include/stdexec/__detail/__sync_wait.hpp b/include/stdexec/__detail/__sync_wait.hpp index 935c8bd65..07456e3d3 100644 --- a/include/stdexec/__detail/__sync_wait.hpp +++ b/include/stdexec/__detail/__sync_wait.hpp @@ -388,23 +388,23 @@ STDEXEC_P2300_NAMESPACE_BEGIN(this_thread) STDEXEC_CONSTEXPR_CXX23 auto apply_sender(_CvSender&& __sndr) const // -> std::optional> { - STDEXEC::__sync_wait::__state __local_state{}; - std::optional> __result{}; + using __values_t = STDEXEC::__sync_wait::__value_tuple_for_t<_CvSender>; + using __receiver_t = STDEXEC::__sync_wait::__receiver_t<_CvSender>; + auto __state = STDEXEC::__sync_wait::__state{}; + auto __result = std::optional<__values_t>{}; // Launch the sender with a continuation that will fill in the __result optional or set the - // exception_ptr in __local_state. - [[maybe_unused]] + // exception_ptr in __state. auto __op = STDEXEC::connect(static_cast<_CvSender&&>(__sndr), - STDEXEC::__sync_wait::__receiver_t<_CvSender>{&__local_state, - &__result}); + __receiver_t{&__state, &__result}); STDEXEC::start(__op); // Wait for the variant to be filled in. - __local_state.__loop_.run(); + __state.__loop_.run(); - if (__local_state.__eptr_) + if (__state.__eptr_) { - std::rethrow_exception(static_cast(__local_state.__eptr_)); + std::rethrow_exception(static_cast(__state.__eptr_)); } return __result; diff --git a/include/stdexec/__detail/__then.hpp b/include/stdexec/__detail/__then.hpp index aef1714e0..975eaefbb 100644 --- a/include/stdexec/__detail/__then.hpp +++ b/include/stdexec/__detail/__then.hpp @@ -215,7 +215,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)); + return __sexpr{then_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; } //! @brief Construct a sender-adaptor closure that, when applied to a diff --git a/include/stdexec/__detail/__transfer_just.hpp b/include/stdexec/__detail/__transfer_just.hpp index 497bb5967..72ef2daf1 100644 --- a/include/stdexec/__detail/__transfer_just.hpp +++ b/include/stdexec/__detail/__transfer_just.hpp @@ -50,8 +50,10 @@ namespace STDEXEC constexpr auto operator()(_Scheduler&& __sched, _Values&&... __vals) const -> __well_formed_sender auto { - return __make_sexpr<__transfer_just_t>( - __tuple{static_cast<_Scheduler&&>(__sched), static_cast<_Values&&>(__vals)...}); + return __sexpr{ + __transfer_just_t(), + __tuple{static_cast<_Scheduler&&>(__sched), static_cast<_Values&&>(__vals)...} + }; } template diff --git a/include/stdexec/__detail/__upon_error.hpp b/include/stdexec/__detail/__upon_error.hpp index f43f206e3..2d7bd50b5 100644 --- a/include/stdexec/__detail/__upon_error.hpp +++ b/include/stdexec/__detail/__upon_error.hpp @@ -215,7 +215,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)); + return __sexpr{upon_error_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; } //! @brief Construct a sender-adaptor closure that, when applied to a diff --git a/include/stdexec/__detail/__upon_stopped.hpp b/include/stdexec/__detail/__upon_stopped.hpp index af20234f5..7f32013ba 100644 --- a/include/stdexec/__detail/__upon_stopped.hpp +++ b/include/stdexec/__detail/__upon_stopped.hpp @@ -182,8 +182,7 @@ namespace STDEXEC requires __callable<_Fun> auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Fun&&>(__fun), - static_cast<_Sender&&>(__sndr)); + return __sexpr{upon_stopped_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; } //! @brief Construct a sender-adaptor closure that, when applied to a diff --git a/include/stdexec/__detail/__when_all.hpp b/include/stdexec/__detail/__when_all.hpp index 671fcf499..878170504 100644 --- a/include/stdexec/__detail/__when_all.hpp +++ b/include/stdexec/__detail/__when_all.hpp @@ -198,10 +198,11 @@ namespace STDEXEC noexcept(__nothrow_decay_copyable<_Sender0, _Sender1, _Senders...>) -> __well_formed_sender auto { - return __make_sexpr(__(), - static_cast<_Sender0&&>(__sndr0), - static_cast<_Sender1&&>(__sndr1), - static_cast<_Senders&&>(__sndrs)...); + return __sexpr{when_all_t(), + __(), + static_cast<_Sender0&&>(__sndr0), + static_cast<_Sender1&&>(__sndr1), + static_cast<_Senders&&>(__sndrs)...}; } }; @@ -264,7 +265,7 @@ namespace STDEXEC template constexpr auto operator()(_Senders&&... __sndrs) const -> __well_formed_sender auto { - return __make_sexpr(__(), static_cast<_Senders&&>(__sndrs)...); + return __sexpr{when_all_with_variant_t(), __(), static_cast<_Senders&&>(__sndrs)...}; } template @@ -305,8 +306,9 @@ namespace STDEXEC constexpr auto operator()(_Scheduler __sched, _Senders&&... __sndrs) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Scheduler&&>(__sched), - static_cast<_Senders&&>(__sndrs)...); + return __sexpr{transfer_when_all_t(), + static_cast<_Scheduler&&>(__sched), + static_cast<_Senders&&>(__sndrs)...}; } template @@ -350,8 +352,9 @@ namespace STDEXEC constexpr auto operator()(_Scheduler&& __sched, _Senders&&... __sndrs) const -> __well_formed_sender auto { - return __make_sexpr(static_cast<_Scheduler&&>(__sched), - static_cast<_Senders&&>(__sndrs)...); + return __sexpr{transfer_when_all_with_variant_t(), + static_cast<_Scheduler&&>(__sched), + static_cast<_Senders&&>(__sndrs)...}; } template diff --git a/include/stdexec/__detail/__write_env.hpp b/include/stdexec/__detail/__write_env.hpp index fe794f166..9d225311d 100644 --- a/include/stdexec/__detail/__write_env.hpp +++ b/include/stdexec/__detail/__write_env.hpp @@ -69,8 +69,7 @@ namespace STDEXEC template constexpr auto operator()(_Sender&& __sndr, _Env __env) const { - return __make_sexpr<__write_env_t>(static_cast<_Env&&>(__env), - static_cast<_Sender&&>(__sndr)); + return __sexpr{__write_env_t(), static_cast<_Env&&>(__env), static_cast<_Sender&&>(__sndr)}; } template diff --git a/test/exec/sequence/test_write_env_sequence.cpp b/test/exec/sequence/test_write_env_sequence.cpp index 9b8aea31d..a21de1284 100644 --- a/test/exec/sequence/test_write_env_sequence.cpp +++ b/test/exec/sequence/test_write_env_sequence.cpp @@ -110,7 +110,7 @@ namespace template auto my_adapt(Sndr&& sndr) { - return STDEXEC::__make_sexpr(STDEXEC::env<>{}, static_cast(sndr)); + return STDEXEC::__sexpr{my_adapt_t(), STDEXEC::env<>{}, static_cast(sndr)}; } struct my_adapt_impl : STDEXEC::__sexpr_defaults diff --git a/test/test_common/scope_helpers.hpp b/test/test_common/scope_helpers.hpp index 9499e020a..ab487234f 100644 --- a/test/test_common/scope_helpers.hpp +++ b/test/test_common/scope_helpers.hpp @@ -44,7 +44,7 @@ namespace noexcept(std::is_nothrow_constructible_v, Sender> && std::is_nothrow_constructible_v, Env>) { - return ex::__make_sexpr(std::forward(env), std::forward(sender)); + return ex::__sexpr{with_attrs_t(), std::forward(env), std::forward(sender)}; } }; From 857bc438555411871b9d006a1ff5af4195db4925 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 8 Oct 2026 21:10:33 +0000 Subject: [PATCH 2/4] give up mangling tparams of `__sexpr` --- include/exec/detail/basic_sequence.hpp | 102 +++---- include/exec/detail/shared.hpp | 2 +- include/exec/fork_join.hpp | 7 +- include/exec/into_tuple.hpp | 2 +- include/exec/libdispatch_queue.hpp | 14 +- include/exec/repeat_n.hpp | 2 +- include/exec/repeat_until.hpp | 6 +- include/exec/sequence/merge_each.hpp | 6 +- include/exec/sequence/transform_each.hpp | 7 +- include/exec/sequence_senders.hpp | 24 +- include/exec/static_thread_pool.hpp | 14 +- include/exec/thread_pool_base.hpp | 2 +- include/exec/when_any.hpp | 2 +- include/nvexec/nvtx.cuh | 7 - include/nvexec/stream/algorithm_base.cuh | 8 - include/nvexec/stream/bulk.cuh | 11 - include/nvexec/stream/common.cuh | 2 +- include/nvexec/stream/continues_on.cuh | 8 - include/nvexec/stream/ensure_started.cuh | 7 - include/nvexec/stream/launch.cuh | 7 - include/nvexec/stream/let_xxx.cuh | 7 - include/nvexec/stream/reduce.cuh | 7 - include/nvexec/stream/schedule_from.cuh | 7 - include/nvexec/stream/split.cuh | 7 - include/nvexec/stream/then.cuh | 7 - include/nvexec/stream/upon_error.cuh | 7 - include/nvexec/stream/upon_stopped.cuh | 7 - include/nvexec/stream/when_all.cuh | 7 - include/stdexec/__detail/__affine.hpp | 4 +- include/stdexec/__detail/__basic_sender.hpp | 207 +++++-------- .../__detail/__basic_sender_macros.hpp | 29 -- include/stdexec/__detail/__config.hpp | 5 - .../stdexec/__detail/__counting_scopes.hpp | 2 +- include/stdexec/__detail/__debug.hpp | 2 +- include/stdexec/__detail/__diagnostics.hpp | 15 +- include/stdexec/__detail/__finally.hpp | 2 +- .../__detail/__get_completion_signatures.hpp | 2 +- include/stdexec/__detail/__let.hpp | 4 +- include/stdexec/__detail/__on.hpp | 5 +- .../stdexec/__detail/__parallel_scheduler.hpp | 2 +- include/stdexec/__detail/__prologue.hpp | 3 + .../stdexec/__detail/__sender_concepts.hpp | 4 +- .../__detail/__sender_introspection.hpp | 285 ++++-------------- include/stdexec/__detail/__sequence.hpp | 11 +- include/stdexec/__detail/__starts_on.hpp | 2 +- .../stdexec/__detail/__stopped_as_error.hpp | 2 +- .../__detail/__stopped_as_optional.hpp | 2 +- .../stdexec/__detail/__structured_apply.hpp | 168 +++++++++++ .../__detail/__structured_binding_size.hpp | 69 +++++ include/stdexec/__detail/__sync_wait.hpp | 2 +- include/stdexec/__detail/__task_scheduler.hpp | 2 +- include/stdexec/__detail/__transfer_just.hpp | 2 +- include/stdexec/__detail/__typeinfo.hpp | 26 +- include/stdexec/__detail/__when_all.hpp | 9 +- include/stdexec/functional.hpp | 19 ++ test/CMakeLists.txt | 1 - .../concepts/test_concept_scheduler.cpp | 5 +- test/stdexec/detail/test_demangle.cpp | 39 --- 58 files changed, 497 insertions(+), 729 deletions(-) delete mode 100644 include/stdexec/__detail/__basic_sender_macros.hpp create mode 100644 include/stdexec/__detail/__structured_apply.hpp create mode 100644 include/stdexec/__detail/__structured_binding_size.hpp delete mode 100644 test/stdexec/detail/test_demangle.cpp diff --git a/include/exec/detail/basic_sequence.hpp b/include/exec/detail/basic_sequence.hpp index 3b9cc47ac..83be659fb 100644 --- a/include/exec/detail/basic_sequence.hpp +++ b/include/exec/detail/basic_sequence.hpp @@ -21,10 +21,6 @@ #if STDEXEC_USE_MODULES() && !defined(STDEXEC_IN_MODULE_PURVIEW) import stdexec; #else -# include "../../stdexec/__detail/__basic_sender.hpp" -# include "../../stdexec/__detail/__meta.hpp" - -# include "../../stdexec/__detail/__basic_sender_macros.hpp" # include "../sequence_senders.hpp" # include "../../stdexec/__detail/__prologue.hpp" @@ -33,48 +29,42 @@ namespace experimental::execution { ////////////////////////////////////////////////////////////////////////////// // __seqexpr - template - struct __basic_sequence_sender - {}; - - namespace + template + struct __seqexpr : STDEXEC::__tuple<_Tag, _Data, _Child...> { - template - struct __seqexpr - : STDEXEC::__minvoke> - { - using sender_concept = sequence_sender_tag; - using __desc_t = decltype(_DescriptorFn()); - using __tag_t = __desc_t::__tag; + using sender_concept = sequence_sender_tag; + using __tag_t = _Tag; + using __data_t = _Data; + using __children_t = STDEXEC::__tuple<_Child...>; - STDEXEC_ATTRIBUTE(always_inline) - static constexpr auto __tag() noexcept -> __tag_t - { - return {}; - } + STDEXEC_ATTRIBUTE(always_inline) + static constexpr auto __tag() noexcept -> __tag_t + { + return {}; + } - template - auto get_env() const noexcept -> decltype(_Self::__tag().get_env(*this)) - { - static_assert(noexcept(_Self::__tag().get_env(*this))); - return _Self::__tag().get_env(*this); - } + template + auto get_env() const noexcept -> decltype(_Self::__tag().get_env(*this)) + { + static_assert(noexcept(_Self::__tag().get_env(*this))); + return _Self::__tag().get_env(*this); + } - template - static consteval auto get_completion_signatures() - { - static_assert(STDEXEC::__decays_to_derived_from<_Self, __seqexpr>); - return __tag_t::template get_completion_signatures<_Self, _Env...>(); - } + template + static consteval auto get_completion_signatures() + { + static_assert(STDEXEC::__decays_to_derived_from<_Self, __seqexpr>); + return __tag_t::template get_completion_signatures<_Self, _Env...>(); + } - template - static consteval auto get_item_types() - { - static_assert(STDEXEC::__decays_to_derived_from<_Self, __seqexpr>); - return __tag_t::template get_item_types<_Self, _Env...>(); - } + template + static consteval auto get_item_types() + { + static_assert(STDEXEC::__decays_to_derived_from<_Self, __seqexpr>); + return __tag_t::template get_item_types<_Self, _Env...>(); + } - // clang-format off + // clang-format off template static constexpr auto __static_subscribe(_Self&& __self, _Receiver __rcvr) STDEXEC_AUTO_RETURN ( @@ -92,16 +82,12 @@ namespace experimental::execution ( __tag_t::subscribe(*this, static_cast<_Receiver&&>(__rcvr)) ) - // clang-format on - }; - - template - STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __seqexpr(_Tag, _Data, _Child...) - -> __seqexpr; - } // namespace + // clang-format on + }; template - using __seqexpr_t = __seqexpr; + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE + __seqexpr(_Tag, _Data, _Child...) -> __seqexpr<_Tag, _Data, _Child...>; namespace __mkseqexpr { @@ -111,32 +97,18 @@ namespace experimental::execution template constexpr auto operator()(_Data __data = {}, _Children... __children) const { - return __seqexpr_t<_Tag, _Data, _Children...>{_Tag(), - static_cast<_Data&&>(__data), - static_cast<_Children&&>(__children)...}; + return __seqexpr<_Tag, _Data, _Children...>{_Tag(), + static_cast<_Data&&>(__data), + static_cast<_Children&&>(__children)...}; } }; } // namespace __mkseqexpr - template - using __basic_sequence_sender_t = - __basic_sequence_sender<_Tag, _Data, STDEXEC::__demangle_t<_Child>...>; - template inline constexpr __mkseqexpr::make_sequence_expr_t<_Tag, _Domain> make_sequence_expr{}; } // namespace experimental::execution namespace exec = experimental::execution; -namespace STDEXEC::__detail -{ - template - extern decltype(_DescriptorFn()) __desc_of_v>; - - template - extern __mtype<__minvoke>> - __demangle_v>; -} // namespace STDEXEC::__detail - # include "../../stdexec/__detail/__epilogue.hpp" #endif diff --git a/include/exec/detail/shared.hpp b/include/exec/detail/shared.hpp index 9cbfa5765..f9ce5fbf3 100644 --- a/include/exec/detail/shared.hpp +++ b/include/exec/detail/shared.hpp @@ -477,7 +477,7 @@ namespace experimental::execution::__shared { return STDEXEC::__throw_compile_time_error<_WHAT_(_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_), _WHERE_(_IN_ALGORITHM_, _Tag), - _WITH_PRETTY_SENDER_<_CvChild>>(); + _WITH_SENDER_<_CvChild>>(); } } diff --git a/include/exec/fork_join.hpp b/include/exec/fork_join.hpp index 7082bd56a..921c84d86 100644 --- a/include/exec/fork_join.hpp +++ b/include/exec/fork_join.hpp @@ -259,10 +259,9 @@ namespace experimental::execution } else { - return STDEXEC::__throw_compile_time_error< - INVALID_ARGUMENTS_TO_FORK_JOIN, - __children_of>, - __fn_t<_WITH_ENVIRONMENT_, Env>...>(); + return STDEXEC::__throw_compile_time_error>, + __fn_t<_WITH_ENVIRONMENT_, Env>...>(); } } diff --git a/include/exec/into_tuple.hpp b/include/exec/into_tuple.hpp index fa881ce47..5efdf2ef9 100644 --- a/include/exec/into_tuple.hpp +++ b/include/exec/into_tuple.hpp @@ -34,7 +34,7 @@ namespace experimental::execution __mexception<_WHAT_(_INVALID_ARGUMENT_), _WHY_(_THE_INPUT_SENDER_MUST_HAVE_AT_EXACTLY_ONE_POSSIBLE_VALUE_COMPLETION_), _WHERE_(_IN_ALGORITHM_, into_tuple_t), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_(_Env)>; template diff --git a/include/exec/libdispatch_queue.hpp b/include/exec/libdispatch_queue.hpp index 7b7262dec..d37a994d8 100644 --- a/include/exec/libdispatch_queue.hpp +++ b/include/exec/libdispatch_queue.hpp @@ -146,7 +146,7 @@ namespace experimental::execution STDEXEC::_WHERE_(STDEXEC::_IN_ALGORITHM_, STDEXEC::tag_of_t), STDEXEC::_TO_FIX_THIS_ERROR_( ADD_A_CONTINUES_ON_TRANSITION_TO_THE_LIBDISPATCH_SCHEDULER_BEFORE_THE_BULK_ALGORITHM), - STDEXEC::_WITH_PRETTY_SENDER_, + STDEXEC::_WITH_SENDER_, STDEXEC::_WITH_ENVIRONMENT_(Env)>(); } } @@ -323,12 +323,12 @@ namespace experimental::execution using arg_pack_t = __tuple &...>; if constexpr (!__decay_copyable) { - return exec::throw_compile_time_error< - _WHAT_(_PREDECESSOR_RESULTS_ARE_NOT_DECAY_COPYABLE_), - _WHERE_(_IN_ALGORITHM_, bulk_tag_t), - _WITH_ARGUMENTS_(Args...), - _WITH_PRETTY_SENDER_<__copy_cvref_t>, - _WITH_ENVIRONMENT_(Env...)>(); + return exec::throw_compile_time_error<_WHAT_( + _PREDECESSOR_RESULTS_ARE_NOT_DECAY_COPYABLE_), + _WHERE_(_IN_ALGORITHM_, bulk_tag_t), + _WITH_ARGUMENTS_(Args...), + _WITH_SENDER_<__copy_cvref_t>, + _WITH_ENVIRONMENT_(Env...)>(); } else if constexpr (__nothrow_applicable && __nothrow_decay_copyable) diff --git a/include/exec/repeat_n.hpp b/include/exec/repeat_n.hpp index aa40d3e25..c82478dd8 100644 --- a/include/exec/repeat_n.hpp +++ b/include/exec/repeat_n.hpp @@ -220,7 +220,7 @@ namespace experimental::execution _WHAT_(_INVALID_ARGUMENT_), _WHERE_(_IN_ALGORITHM_, repeat_n_t), _WHY_(_THE_INPUT_SENDER_MUST_HAVE_VOID_VALUE_COMPLETION_), - _WITH_PRETTY_SENDER_<__child_t &>>(); + _WITH_SENDER_<__child_t &>>(); }, // transform for set_error completions: decay_arguments(), diff --git a/include/exec/repeat_until.hpp b/include/exec/repeat_until.hpp index b25929004..c703479dd 100644 --- a/include/exec/repeat_until.hpp +++ b/include/exec/repeat_until.hpp @@ -243,7 +243,7 @@ namespace experimental::execution _WHAT_(_INVALID_ARGUMENT_), _WHERE_(_IN_ALGORITHM_, repeat_until_t), _WHY_(_EXPECTING_A_SENDER_OF_ONE_VALUE_THAT_IS_CONVERTIBLE_TO_BOOL_), - _WITH_PRETTY_SENDER_<_Child>>(); + _WITH_SENDER_<_Child>>(); } else if constexpr ((__is_bool_constant<_Args, false> && ...)) { @@ -298,7 +298,7 @@ namespace experimental::execution if constexpr (__is_dependent) { return exec::throw_compile_time_error>(); + _WITH_SENDER_<__child_t>>(); } else { @@ -386,7 +386,7 @@ namespace experimental::execution { return __not_a_sender<_WHAT_(_INVALID_ARGUMENT_, _EXPECTING_A_SENDER_OF_VOID_), _WHERE_(_IN_ALGORITHM_, repeat_until_t), - _WITH_PRETTY_SENDER_<__child_t>, + _WITH_SENDER_<__child_t>, _WITH_ENVIRONMENT_(_Env)>(); } } diff --git a/include/exec/sequence/merge_each.hpp b/include/exec/sequence/merge_each.hpp index 89cdf6146..52675ac87 100644 --- a/include/exec/sequence/merge_each.hpp +++ b/include/exec/sequence/merge_each.hpp @@ -812,12 +812,12 @@ namespace experimental::execution template using __f = std::conditional_t< sizeof...(_Env) == 0 && sizeof...(_Args) == 1 && (dependent_sender<_Args> && ...), - STDEXEC::__mexception...>, + STDEXEC::__mexception...>, STDEXEC::__mexception<_WHAT_(_INVALID_ARGUMENT_), _WHERE_(_IN_ALGORITHM_, merge_each_t), _WHY_(_MERGE_WITH_REQUIRES_A_SEQUENCE_OF_SEQUENCES_), - _WITH_PRETTY_SEQUENCE_<_Sequence>, - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SEQUENCE_<_Sequence>, + _WITH_SENDER_<_Sender>, __fn_t<_WITH_ENVIRONMENT_, _Env>..., _WITH_ARGUMENTS_(_Args...)>>; }; diff --git a/include/exec/sequence/transform_each.hpp b/include/exec/sequence/transform_each.hpp index ca1ca923e..ddd696da4 100644 --- a/include/exec/sequence/transform_each.hpp +++ b/include/exec/sequence/transform_each.hpp @@ -45,9 +45,6 @@ namespace experimental::execution struct _WITH_ITEM_SENDER_ {}; - template - using _WITH_PRETTY_ITEM_SENDER_ = _WITH_ITEM_SENDER_(STDEXEC::__demangle_t<_Sender>); - namespace __transform_each { using namespace STDEXEC; @@ -187,10 +184,10 @@ namespace experimental::execution if constexpr (!__callable<__closure_t, _ItemSender>) { return exec::__invalid_item_types<_TRANSFORM_EACH_ADAPTOR_INVOCATION_FAILED_<_Self>, - _WITH_PRETTY_SEQUENCE_<__child_of<_Self>>, + _WITH_SEQUENCE_<__child_of<_Self>>, __fn_t<_WITH_ENVIRONMENT_, _Env>..., _WITH_ADAPTOR_<__data_of<_Self>>, - _WITH_PRETTY_ITEM_SENDER_<_ItemSender>>(); + _WITH_ITEM_SENDER_(_ItemSender)>(); } else { diff --git a/include/exec/sequence_senders.hpp b/include/exec/sequence_senders.hpp index 17dd704a5..b7ed8aba3 100644 --- a/include/exec/sequence_senders.hpp +++ b/include/exec/sequence_senders.hpp @@ -105,12 +105,6 @@ namespace experimental::execution struct _WITH_SEQUENCES_ {}; - template - using _WITH_PRETTY_SEQUENCE_ = _WITH_SEQUENCE_>; - - template - using _WITH_PRETTY_SEQUENCES_ = _WITH_SEQUENCES_...>; - STDEXEC_MODULE_EXPORT struct sequence_sender_tag : STDEXEC::sender_tag {}; @@ -315,9 +309,9 @@ namespace experimental::execution // Without this, wrapping a sequence sender in a transparent adaptor (e.g. // `write_env`) would hide the sequence semantics from downstream // sequence-aware algorithms. See issue #2053. - template - requires __transparent_sequence_adaptor> - inline constexpr bool enable_sequence_sender> = true; + template + requires __transparent_sequence_adaptor> + inline constexpr bool enable_sequence_sender> = true; STDEXEC_MODULE_EXPORT template @@ -350,7 +344,7 @@ namespace experimental::execution using __unrecognized_sequence_error_t = STDEXEC::__mexception, + _WITH_SEQUENCE_<_Sequence>, STDEXEC::_WITH_ENVIRONMENT_(_Env)...>; ////////////////////////////////////////////////////////////////////////////// @@ -517,8 +511,8 @@ namespace experimental::execution template constexpr auto __check_item(_Item*) -> STDEXEC::__mexception, - _WITH_PRETTY_SEQUENCE_<_Sequence>>; + STDEXEC::_WITH_SENDER_<_Item>, + _WITH_SEQUENCE_<_Sequence>>; template requires STDEXEC::__well_formed_sender<_Item> @@ -541,7 +535,7 @@ namespace experimental::execution -> STDEXEC::__mexception), STDEXEC::_WITH_TYPE_<_Items>, - _WITH_PRETTY_SEQUENCE_<_Sequence>>; + _WITH_SEQUENCE_<_Sequence>>; template auto __check_items(exec::item_types<_Items...>*) @@ -569,7 +563,7 @@ namespace experimental::execution auto __check_sequence(_Sequence*) -> STDEXEC::__mexception>; + _WITH_SEQUENCE_<_Sequence>>; template requires(!STDEXEC::__merror<_Sequence>) && STDEXEC::__minvocable_q<__item_types_of_t, _Sequence> @@ -741,7 +735,7 @@ namespace experimental::execution template constexpr auto __try_item(_Item*) -> STDEXEC::__mexception, + STDEXEC::_WITH_SENDER_<_Item>, STDEXEC::_WITH_RECEIVER_(_Receiver)>; template diff --git a/include/exec/static_thread_pool.hpp b/include/exec/static_thread_pool.hpp index 8495c1641..b4d570a49 100644 --- a/include/exec/static_thread_pool.hpp +++ b/include/exec/static_thread_pool.hpp @@ -307,7 +307,7 @@ namespace experimental::execution STDEXEC::_WHERE_(STDEXEC::_IN_ALGORITHM_, tag_of_t), STDEXEC::_TO_FIX_THIS_ERROR_( ADD_A_CONTINUES_ON_TRANSITION_TO_THE_STATIC_THREAD_POOL_SCHEDULER_BEFORE_THE_BULK_ALGORITHM), - STDEXEC::_WITH_PRETTY_SENDER_, + STDEXEC::_WITH_SENDER_, STDEXEC::_WITH_ENVIRONMENT_(Env)>(); } } @@ -331,7 +331,7 @@ namespace experimental::execution STDEXEC::_WHERE_(STDEXEC::_IN_ALGORITHM_, exec::iterate_t), STDEXEC::_TO_FIX_THIS_ERROR_( ADD_A_CONTINUES_ON_TRANSITION_TO_THE_STATIC_THREAD_POOL_SCHEDULER_BEFORE_THE_ITERATE_ALGORITHM), - STDEXEC::_WITH_PRETTY_SENDER_, + STDEXEC::_WITH_SENDER_, STDEXEC::_WITH_ENVIRONMENT_(Env)>(); } } @@ -1313,11 +1313,11 @@ namespace experimental::execution { if constexpr (!__nothrow_decay_copyable) { - return exec::throw_compile_time_error< - _WHAT_(_PREDECESSOR_RESULTS_ARE_NOT_DECAY_COPYABLE_), - _WHERE_(_IN_ALGORITHM_, bulk_t), - _WITH_PRETTY_SENDER_<__copy_cvref_t>, - _WITH_ENVIRONMENT_(Env...)>(); + return exec::throw_compile_time_error<_WHAT_( + _PREDECESSOR_RESULTS_ARE_NOT_DECAY_COPYABLE_), + _WHERE_(_IN_ALGORITHM_, bulk_t), + _WITH_SENDER_<__copy_cvref_t>, + _WITH_ENVIRONMENT_(Env...)>(); } else if constexpr (!__callable&...>) { diff --git a/include/exec/thread_pool_base.hpp b/include/exec/thread_pool_base.hpp index 1317b0d92..5fead9b6e 100644 --- a/include/exec/thread_pool_base.hpp +++ b/include/exec/thread_pool_base.hpp @@ -131,7 +131,7 @@ namespace experimental::execution STDEXEC::_WHERE_(STDEXEC::_IN_ALGORITHM_, STDEXEC::tag_of_t), STDEXEC::_TO_FIX_THIS_ERROR_( ADD_A_CONTINUES_ON_TRANSITION_TO_THE_POOL_SCHEDULER_BEFORE_THE_BULK_ALGORITHM), - STDEXEC::_WITH_PRETTY_SENDER_, + STDEXEC::_WITH_SENDER_, STDEXEC::_WITH_ENVIRONMENT_(Env)>(); } } diff --git a/include/exec/when_any.hpp b/include/exec/when_any.hpp index 7eb262882..2bde0e1d7 100644 --- a/include/exec/when_any.hpp +++ b/include/exec/when_any.hpp @@ -284,7 +284,7 @@ namespace experimental::execution static consteval auto get_completion_signatures() { return STDEXEC::__throw_compile_time_error<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, - _WITH_PRETTY_SENDERS_<_Senders>...>(); + _WITH_SENDERS_<_Senders>...>(); } private: diff --git a/include/nvexec/nvtx.cuh b/include/nvexec/nvtx.cuh index 45b817025..15cecd107 100644 --- a/include/nvexec/nvtx.cuh +++ b/include/nvexec/nvtx.cuh @@ -193,11 +193,4 @@ namespace nv::execution namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/algorithm_base.cuh b/include/nvexec/stream/algorithm_base.cuh index b49b5d568..65e557506 100644 --- a/include/nvexec/stream/algorithm_base.cuh +++ b/include/nvexec/stream/algorithm_base.cuh @@ -142,11 +142,3 @@ namespace nv::execution::_strm::__algo_range_init_fun } // namespace nv::execution::_strm::__algo_range_init_fun namespace nvexec = nv::execution; - -namespace STDEXEC::__detail -{ - template - extern __mtype, InitT, Fun, __demangle_t>> - __demangle_v>; -} // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/bulk.cuh b/include/nvexec/stream/bulk.cuh index 9a885cf86..ce2f394e6 100644 --- a/include/nvexec/stream/bulk.cuh +++ b/include/nvexec/stream/bulk.cuh @@ -437,15 +437,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - inline constexpr __mtype, Shape, Fun>> - __demangle_v>{}; - - template - inline constexpr __mtype, Shape, Fun>> - __demangle_v>{}; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/common.cuh b/include/nvexec/stream/common.cuh index 8364c813d..1fc2fa9cd 100644 --- a/include/nvexec/stream/common.cuh +++ b/include/nvexec/stream/common.cuh @@ -130,7 +130,7 @@ namespace nv::execution return __not_a_sender<_WHAT_(CANNOT_DISPATCH_THIS_ALGORITHM_TO_THE_CUDA_STREAM_SCHEDULER), _WHY_(BECAUSE_THERE_IS_NO_CUDA_STREAM_SCHEDULER_IN_THE_ENVIRONMENT), _WHERE_(_IN_ALGORITHM_, Tag), - _WITH_PRETTY_SENDER_, + _WITH_SENDER_, _WITH_ENVIRONMENT_(Env)>{}; } } // namespace _strm diff --git a/include/nvexec/stream/continues_on.cuh b/include/nvexec/stream/continues_on.cuh index 657f49821..193119f99 100644 --- a/include/nvexec/stream/continues_on.cuh +++ b/include/nvexec/stream/continues_on.cuh @@ -287,12 +287,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -// Decode the sender name for diagnostics: -namespace STDEXEC::__detail -{ - template - extern __mtype>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/ensure_started.cuh b/include/nvexec/stream/ensure_started.cuh index 665976502..9a5612c44 100644 --- a/include/nvexec/stream/ensure_started.cuh +++ b/include/nvexec/stream/ensure_started.cuh @@ -449,11 +449,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/launch.cuh b/include/nvexec/stream/launch.cuh index 37b1a1881..246625505 100644 --- a/include/nvexec/stream/launch.cuh +++ b/include/nvexec/stream/launch.cuh @@ -205,11 +205,4 @@ namespace nv::execution namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype, Fun>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/let_xxx.cuh b/include/nvexec/stream/let_xxx.cuh index 8dc355cc0..13dc70b4c 100644 --- a/include/nvexec/stream/let_xxx.cuh +++ b/include/nvexec/stream/let_xxx.cuh @@ -340,11 +340,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype, Fun, SetTag>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/reduce.cuh b/include/nvexec/stream/reduce.cuh index b1ec38b56..86e209384 100644 --- a/include/nvexec/stream/reduce.cuh +++ b/include/nvexec/stream/reduce.cuh @@ -162,11 +162,4 @@ namespace nv::execution namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype, Init, Fun>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/schedule_from.cuh b/include/nvexec/stream/schedule_from.cuh index 4d45d6734..d3f20f72b 100644 --- a/include/nvexec/stream/schedule_from.cuh +++ b/include/nvexec/stream/schedule_from.cuh @@ -202,10 +202,3 @@ namespace nv::execution } // namespace nv::execution namespace nvexec = nv::execution; - -namespace STDEXEC::__detail -{ - template - extern __mtype>> - __demangle_v>; -} // namespace STDEXEC::__detail diff --git a/include/nvexec/stream/split.cuh b/include/nvexec/stream/split.cuh index b599117ec..0a53bd06f 100644 --- a/include/nvexec/stream/split.cuh +++ b/include/nvexec/stream/split.cuh @@ -426,11 +426,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/then.cuh b/include/nvexec/stream/then.cuh index 44e3a53b7..5f1740716 100644 --- a/include/nvexec/stream/then.cuh +++ b/include/nvexec/stream/then.cuh @@ -225,11 +225,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype, Fun>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/upon_error.cuh b/include/nvexec/stream/upon_error.cuh index 9bd367bbe..a56aef9af 100644 --- a/include/nvexec/stream/upon_error.cuh +++ b/include/nvexec/stream/upon_error.cuh @@ -213,11 +213,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype, Fun>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/upon_stopped.cuh b/include/nvexec/stream/upon_stopped.cuh index 85121582d..5a848e6fd 100644 --- a/include/nvexec/stream/upon_stopped.cuh +++ b/include/nvexec/stream/upon_stopped.cuh @@ -206,11 +206,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype, Fun>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/when_all.cuh b/include/nvexec/stream/when_all.cuh index 49e8efd27..284d47dc7 100644 --- a/include/nvexec/stream/when_all.cuh +++ b/include/nvexec/stream/when_all.cuh @@ -567,11 +567,4 @@ namespace nv::execution::_strm namespace nvexec = nv::execution; -namespace STDEXEC::__detail -{ - template - extern __mtype...>> - __demangle_v>; -} // namespace STDEXEC::__detail - STDEXEC_PRAGMA_POP() diff --git a/include/stdexec/__detail/__affine.hpp b/include/stdexec/__detail/__affine.hpp index 7230bcf7c..f0f81f21a 100644 --- a/include/stdexec/__detail/__affine.hpp +++ b/include/stdexec/__detail/__affine.hpp @@ -111,7 +111,7 @@ namespace STDEXEC _WHAT_(_CANNOT_MAKE_SENDER_AFFINE_TO_THE_STARTING_SCHEDULER_), _WHY_(_THE_CURRENT_EXECUTION_ENVIRONMENT_DOESNT_HAVE_A_SCHEDULER_), _WHERE_(_IN_ALGORITHM_, affine_t), - _WITH_PRETTY_SENDER_<__cv_child_t>, + _WITH_SENDER_<__cv_child_t>, _WITH_ENVIRONMENT_(_Env)>{}; } else if constexpr (!__infallible_scheduler<__sched_t, __unstoppable_env_t<_Env>>) @@ -123,7 +123,7 @@ namespace STDEXEC _WHAT_(_CANNOT_MAKE_SENDER_AFFINE_TO_THE_STARTING_SCHEDULER_), _WHY_(_THE_SCHEDULER_IN_THE_CURRENT_EXECUTION_ENVIRONMENT_IS_NOT_INFALLIBLE_), _WHERE_(_IN_ALGORITHM_, affine_t), - _WITH_PRETTY_SENDER_<__cv_child_t>, + _WITH_SENDER_<__cv_child_t>, _WITH_SCHEDULER_(__sched_t)>{}; } else diff --git a/include/stdexec/__detail/__basic_sender.hpp b/include/stdexec/__detail/__basic_sender.hpp index 9d823f450..b95960c5f 100644 --- a/include/stdexec/__detail/__basic_sender.hpp +++ b/include/stdexec/__detail/__basic_sender.hpp @@ -25,7 +25,6 @@ import stdexec; # include "__execution_fwd.hpp" -# include "__basic_sender_macros.hpp" # include "__completion_signatures_of.hpp" # include "__concepts.hpp" # include "__connect.hpp" @@ -52,22 +51,6 @@ namespace STDEXEC ////////////////////////////////////////////////////////////////////////////// // Generic __sender type -# if defined(STDEXEC_DEMANGLE_SENDER_NAMES) - STDEXEC_MODULE_EXPORT_AUTHORING - template - inline constexpr auto __descriptor_fn_v = _Descriptor{}; -# else - STDEXEC_MODULE_EXPORT_AUTHORING - template - inline constexpr auto __descriptor_fn_v = _DescriptorFn; -# endif - - template - consteval auto __descriptor_fn() noexcept - { - return __descriptor_fn_v<__desc<_Tag, _Data, _Child...>>; - } - STDEXEC_MODULE_EXPORT_AUTHORING template struct __sexpr_impl; @@ -101,7 +84,7 @@ namespace STDEXEC using __env_type_t = __result_of<__sexpr_impl<_Tag>::__get_env, _Index, _State const &>; template - using __child_indices_t = STDEXEC::__desc_of_t<_Sexpr>::__indices; + using __child_indices_t = __decay_t<_Sexpr>::__indices_t; template struct __state @@ -299,8 +282,7 @@ namespace STDEXEC template struct __opstate { - using __desc_t = __decay_t<_Sexpr>::__desc_t; - using __tag_t = __desc_t::__tag; + using __tag_t = __decay_t<_Sexpr>::__tag_t; using __state_t = __detail::__state_type_t<_Sexpr, _Receiver>; using __connect_t = __detail::__connect<__tag_t, __detail::__child_indices_t<_Sexpr>>; using __child_ops_t = __apply_result_t<__connect_t, _Sexpr, __state_t&>; @@ -332,133 +314,102 @@ namespace STDEXEC struct __sexpr_impl : __sexpr_defaults {}; - //! A dummy type used only for diagnostic purposes. - //! See `__sexpr` for the implementation of P2300's _`basic-sender`_. + //! A struct template to aid in creating senders. This struct resembles + //! P2300's [_`basic-sender`_](https://eel.is/c++draft/exec#snd.expos-24), + //! but is not an exact implementation. STDEXEC_MODULE_EXPORT_AUTHORING template - struct __basic_sender + struct __sexpr : __tuple<_Tag, _Data, _Child...> { - struct type - { - using sender_concept = sender_tag; - }; - }; + using sender_concept = sender_tag; -# if !STDEXEC_USE_MODULES() - namespace - { -# endif - //! A struct template to aid in creating senders. This struct resembles - //! P2300's [_`basic-sender`_](https://eel.is/c++draft/exec#snd.expos-24), - //! but is not an exact implementation. Note: The struct named - //! `__basic_sender` is just a dummy type and is also not _`basic-sender`_. - STDEXEC_MODULE_EXPORT_AUTHORING - template - struct __sexpr : __mcall1> - { - using sender_concept = sender_tag; + using __tag_t = _Tag; + using __data_t = _Data; + using __children_t = __mlist<_Child...>; + using __indices_t = __make_indices; + using __base_t = __tuple<_Tag, _Data, _Child...>; + using __get_attrs_t = __mtypeof<__sexpr_impl<__tag_t>::__get_attrs>; + using __attrs_t = __apply_result_t<__get_attrs_t, __base_t const &>; - using __desc_t = decltype(_DescriptorFn()); - using __tag_t = __desc_t::__tag; - using __base_t = __mcall1<__desc_t, __qq<__tuple>>; - using __get_attrs_t = __mtypeof<__sexpr_impl<__tag_t>::__get_attrs>; - using __attrs_t = __apply_result_t<__get_attrs_t, __base_t const &>; + STDEXEC_ATTRIBUTE(nodiscard, always_inline) + constexpr auto get_env() const noexcept -> __attrs_t + { + return __apply(__sexpr_impl<__tag_t>::__get_attrs, __c_upcast<__base_t>(*this)); + } - STDEXEC_ATTRIBUTE(nodiscard, always_inline) - constexpr auto get_env() const noexcept -> __attrs_t + template + static consteval auto get_completion_signatures() + { + using namespace __detail; + static_assert(STDEXEC_IS_BASE_OF(__sexpr, __decay_t<_Self>)); + using __self_t = __copy_cvref_t<_Self, __sexpr>; + if constexpr (__has_get_completion_signatures_v<__tag_t, __self_t, _Env...>) { - return __apply(__sexpr_impl<__tag_t>::__get_attrs, __c_upcast<__base_t>(*this)); + return __sexpr_impl<__tag_t>::template __get_completion_signatures<__self_t, _Env...>(); } - - template - static consteval auto get_completion_signatures() + else if constexpr (__has_get_completion_signatures_v<__tag_t, __self_t>) { - using namespace __detail; - static_assert(STDEXEC_IS_BASE_OF(__sexpr, __decay_t<_Self>)); - using __self_t = __copy_cvref_t<_Self, __sexpr>; - if constexpr (__has_get_completion_signatures_v<__tag_t, __self_t, _Env...>) - { - return __sexpr_impl<__tag_t>::template __get_completion_signatures<__self_t, _Env...>(); - } - else if constexpr (__has_get_completion_signatures_v<__tag_t, __self_t>) - { - return __sexpr_impl<__tag_t>::template __get_completion_signatures<__self_t>(); - } - else if constexpr (sizeof...(_Env) == 0) - { - return __throw_dependent_sender_error<_Self>(); - } - else - { - return STDEXEC::__throw_compile_time_error( - __unrecognized_sender_error_t<_Self, _Env...>()); - } + return __sexpr_impl<__tag_t>::template __get_completion_signatures<__self_t>(); } - - // Non-standard extension: - template - STDEXEC_ATTRIBUTE(nodiscard, always_inline) - static constexpr auto __static_connect(_Self&& __self, _Receiver __rcvr) noexcept( - __noexcept_of<__sexpr_impl<__tag_t>::__connect, __copy_cvref_t<_Self, __sexpr>, _Receiver>) - -> __result_of<__sexpr_impl<__tag_t>::__connect, __copy_cvref_t<_Self, __sexpr>, _Receiver> + else if constexpr (sizeof...(_Env) == 0) { - static_assert(STDEXEC_IS_BASE_OF(__sexpr, __decay_t<_Self>)); - return __sexpr_impl<__tag_t>::__connect(STDEXEC::__c_upcast<__sexpr>( - static_cast<_Self&&>(__self)), - static_cast<_Receiver&&>(__rcvr)); + return __throw_dependent_sender_error<_Self>(); } - - template - STDEXEC_ATTRIBUTE(nodiscard, always_inline) - constexpr auto connect(_Receiver __rcvr) && noexcept( - __noexcept_of<__sexpr_impl<__tag_t>::__connect, __sexpr, _Receiver>) - -> __result_of<__sexpr_impl<__tag_t>::__connect, __sexpr, _Receiver> + else { - return __sexpr_impl<__tag_t>::__connect(static_cast<__sexpr&&>(*this), - static_cast<_Receiver&&>(__rcvr)); + return STDEXEC::__throw_compile_time_error(__unrecognized_sender_error_t<_Self, _Env...>()); } + } - template - requires __std::copy_constructible<__sexpr> - STDEXEC_ATTRIBUTE(nodiscard, always_inline) - constexpr auto connect(_Receiver __rcvr) const & noexcept( - __noexcept_of<__sexpr_impl<__tag_t>::__connect, __sexpr const &, _Receiver>) - -> __result_of<__sexpr_impl<__tag_t>::__connect, __sexpr const &, _Receiver> - { - return __sexpr_impl<__tag_t>::__connect(*this, static_cast<_Receiver&&>(__rcvr)); - } + // Non-standard extension: + template + STDEXEC_ATTRIBUTE(nodiscard, always_inline) + static constexpr auto __static_connect(_Self&& __self, _Receiver __rcvr) noexcept( + __noexcept_of<__sexpr_impl<__tag_t>::__connect, __copy_cvref_t<_Self, __sexpr>, _Receiver>) + -> __result_of<__sexpr_impl<__tag_t>::__connect, __copy_cvref_t<_Self, __sexpr>, _Receiver> + { + static_assert(STDEXEC_IS_BASE_OF(__sexpr, __decay_t<_Self>)); + return __sexpr_impl<__tag_t>::__connect(STDEXEC::__c_upcast<__sexpr>( + static_cast<_Self&&>(__self)), + static_cast<_Receiver&&>(__rcvr)); + } - // Non-standard extension: - template - STDEXEC_ATTRIBUTE(nodiscard, always_inline) - static constexpr auto submit(_Self&& __self, _Receiver&& __rcvr) noexcept( - __noexcept_of<__sexpr_impl<__tag_t>::__submit, __copy_cvref_t<_Self, __sexpr>, _Receiver>) - -> __result_of<__sexpr_impl<__tag_t>::__submit, __copy_cvref_t<_Self, __sexpr>, _Receiver> - { - return __sexpr_impl<__tag_t>::__submit(STDEXEC::__c_upcast<__sexpr>( - static_cast<_Self&&>(__self)), - static_cast<_Receiver&&>(__rcvr)); - } - }; + template + STDEXEC_ATTRIBUTE(nodiscard, always_inline) + constexpr auto connect(_Receiver __rcvr) && noexcept( + __noexcept_of<__sexpr_impl<__tag_t>::__connect, __sexpr, _Receiver>) + -> __result_of<__sexpr_impl<__tag_t>::__connect, __sexpr, _Receiver> + { + return __sexpr_impl<__tag_t>::__connect(static_cast<__sexpr&&>(*this), + static_cast<_Receiver&&>(__rcvr)); + } - template - STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE - __sexpr(_Tag, _Data, _Child...) -> __sexpr; -# if !STDEXEC_USE_MODULES() - } // anonymous namespace -# endif + template + requires __std::copy_constructible<__sexpr> + STDEXEC_ATTRIBUTE(nodiscard, always_inline) + constexpr auto connect(_Receiver __rcvr) const & noexcept( + __noexcept_of<__sexpr_impl<__tag_t>::__connect, __sexpr const &, _Receiver>) + -> __result_of<__sexpr_impl<__tag_t>::__connect, __sexpr const &, _Receiver> + { + return __sexpr_impl<__tag_t>::__connect(*this, static_cast<_Receiver&&>(__rcvr)); + } - // The __demangle_t utility defined below is used to pretty-print the type - // names of senders in compiler diagnostics. - namespace __detail - { - template - using __basic_sender_t = __basic_sender<_Tag, _Data, __demangle_t<_Child>...>::type; + // Non-standard extension: + template + STDEXEC_ATTRIBUTE(nodiscard, always_inline) + static constexpr auto submit(_Self&& __self, _Receiver&& __rcvr) noexcept( + __noexcept_of<__sexpr_impl<__tag_t>::__submit, __copy_cvref_t<_Self, __sexpr>, _Receiver>) + -> __result_of<__sexpr_impl<__tag_t>::__submit, __copy_cvref_t<_Self, __sexpr>, _Receiver> + { + return __sexpr_impl<__tag_t>::__submit(STDEXEC::__c_upcast<__sexpr>( + static_cast<_Self&&>(__self)), + static_cast<_Receiver&&>(__rcvr)); + } + }; - template - extern __mtype<__mcall1>> - __demangle_v<__sexpr<_Descriptor>>; - } // namespace __detail + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE + __sexpr(_Tag, _Data, _Child...) -> __sexpr<_Tag, _Data, _Child...>; } // namespace STDEXEC # include "__epilogue.hpp" diff --git a/include/stdexec/__detail/__basic_sender_macros.hpp b/include/stdexec/__detail/__basic_sender_macros.hpp deleted file mode 100644 index 31990cd49..000000000 --- a/include/stdexec/__detail/__basic_sender_macros.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2021-2024 NVIDIA Corporation - * - * Licensed under the Apache License Version 2.0 with LLVM Exceptions - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * https://llvm.org/LICENSE.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include "__config.hpp" - -#if STDEXEC_EDG() -# define STDEXEC_SEXPR_DESCRIPTOR_FN(_Descriptor) \ - ([](_Desc __desc = {}) { return __desc; }) -# define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \ - STDEXEC::__descriptor_fn<_Tag, _Data, _Child>() -#else // ^^^ EDG ^^^ / vvv !EDG vvv -# define STDEXEC_SEXPR_DESCRIPTOR_FN(_Descriptor) ([] { return _Descriptor(); }) -# define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \ - STDEXEC::__descriptor_fn_v> -#endif diff --git a/include/stdexec/__detail/__config.hpp b/include/stdexec/__detail/__config.hpp index 0a7c067ac..e7b22ab59 100644 --- a/include/stdexec/__detail/__config.hpp +++ b/include/stdexec/__detail/__config.hpp @@ -968,11 +968,6 @@ namespace STDEXEC # define STDEXEC_CONSTEXPR_LOCAL constexpr #endif -//////////////////////////////////////////////////////////////////////////////// -#if !defined(STDEXEC_DEMANGLE_SENDER_NAMES) && (STDEXEC_MSVC() || STDEXEC_USE_MODULES()) -# define STDEXEC_DEMANGLE_SENDER_NAMES -#endif - //////////////////////////////////////////////////////////////////////////////// // clang-tidy struggles with the CUDA function annotations #if STDEXEC_CLANG() && STDEXEC_CUDA_COMPILATION() && defined(STDEXEC_CLANG_TIDY_INVOKED) diff --git a/include/stdexec/__detail/__counting_scopes.hpp b/include/stdexec/__detail/__counting_scopes.hpp index 035e9054d..848b9f4b2 100644 --- a/include/stdexec/__detail/__counting_scopes.hpp +++ b/include/stdexec/__detail/__counting_scopes.hpp @@ -118,7 +118,7 @@ namespace STDEXEC _WHAT_(_JOINING_A_COUNTING_SCOPE_NEEDS_A_SCHEDULER_IN_THE_ENVIRONMENT_), _WHY_(_THE_CURRENT_EXECUTION_ENVIRONMENT_DOESNT_HAVE_A_SCHEDULER_), _WHERE_(STDEXEC::_IN_ALGORITHM_, __scope_join_t), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_(_Env)>(); } }; diff --git a/include/stdexec/__detail/__debug.hpp b/include/stdexec/__detail/__debug.hpp index 29606b531..dfada1ba7 100644 --- a/include/stdexec/__detail/__debug.hpp +++ b/include/stdexec/__detail/__debug.hpp @@ -95,7 +95,7 @@ namespace STDEXEC using __what_t = _WARNING_<_COMPLETION_SIGNATURES_MISMATCH_, _COMPLETION_SIGNATURE_<_Which>, _IS_NOT_ONE_OF_<_Sigs...>, - _SIGNAL_SENT_BY_SENDER_<__demangle_t<_CvSender>>>; + _SIGNAL_SENT_BY_SENDER_<_CvSender>>; __debug::_ATTENTION_<__what_t>(); } STDEXEC_TERMINATE(); diff --git a/include/stdexec/__detail/__diagnostics.hpp b/include/stdexec/__detail/__diagnostics.hpp index 75b082ec9..1d3bb6f12 100644 --- a/include/stdexec/__detail/__diagnostics.hpp +++ b/include/stdexec/__detail/__diagnostics.hpp @@ -58,21 +58,16 @@ namespace STDEXEC struct _UNRECOGNIZED_SENDER_TYPE_; + STDEXEC_MODULE_EXPORT_AUTHORING template struct _WITH_SENDER_ {}; + STDEXEC_MODULE_EXPORT_AUTHORING template struct _WITH_SENDERS_ {}; - STDEXEC_MODULE_EXPORT_AUTHORING - template - using _WITH_PRETTY_SENDER_ = _WITH_SENDER_<__demangle_t<_Sender>>; - - template - using _WITH_PRETTY_SENDERS_ = _WITH_SENDERS_<__demangle_t<_Senders>...>; - STDEXEC_MODULE_EXPORT_AUTHORING struct _WITH_ENVIRONMENT_ {}; @@ -157,7 +152,7 @@ namespace STDEXEC template using __bad_pipe_sink_t = __mexception<_WHAT_(_INVALID_EXPRESSION_), _WHY_(_CANNOT_PIPE_ONE_SENDER_INTO_ANOTHER_), - _WITH_PRETTY_SENDER_<_Sender>>; + _WITH_SENDER_<_Sender>>; template using __callable_error_t = @@ -174,7 +169,7 @@ namespace STDEXEC using __unrecognized_sender_error_t = __mexception<_WHAT_(_UNRECOGNIZED_SENDER_TYPE_), _WHY_(_UNABLE_TO_COMPUTE_THE_SENDER_COMPLETION_SIGNATURES_), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_(_Env)...>; # if __cpp_lib_constexpr_exceptions >= 202502L @@ -299,7 +294,7 @@ namespace STDEXEC // By making __dependent_sender_error_t an alias for _ERROR_<...>, we ensure // that it will get propagated correctly through various metafunctions. template - using __dependent_sender_error_t = _ERROR_>; + using __dependent_sender_error_t = _ERROR_>; STDEXEC_MODULE_EXPORT_AUTHORING template diff --git a/include/stdexec/__detail/__finally.hpp b/include/stdexec/__detail/__finally.hpp index 22ccae963..663dea413 100644 --- a/include/stdexec/__detail/__finally.hpp +++ b/include/stdexec/__detail/__finally.hpp @@ -330,7 +330,7 @@ namespace STDEXEC _WHAT_(_INVALID_ARGUMENT_TO_THE_FINALLY_ALGORITHM_), _WHERE_(_IN_ALGORITHM_, __finally_t), _WHY_(_THE_FINAL_SENDER_MUST_BE_A_SENDER_OF_VOID_), - _WITH_PRETTY_SENDER_<_CvFinalSender>>(); + _WITH_SENDER_<_CvFinalSender>>(); } else { diff --git a/include/stdexec/__detail/__get_completion_signatures.hpp b/include/stdexec/__detail/__get_completion_signatures.hpp index 32b5f424a..3b50c55aa 100644 --- a/include/stdexec/__detail/__get_completion_signatures.hpp +++ b/include/stdexec/__detail/__get_completion_signatures.hpp @@ -97,7 +97,7 @@ namespace STDEXEC return __throw_compile_time_error< _A_GET_COMPLETION_SIGNATURES_CUSTOMIZATION_RETURNED_A_TYPE_THAT_IS_NOT_A_COMPLETION_SIGNATURES_SPECIALIZATION, _WITH_COMPLETION_SIGNATURES_(_Completions), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, __fn_t<_WITH_ENVIRONMENT_, _Env>...>(); } } diff --git a/include/stdexec/__detail/__let.hpp b/include/stdexec/__detail/__let.hpp index 97a555bdb..39e1ebb5e 100644 --- a/include/stdexec/__detail/__let.hpp +++ b/include/stdexec/__detail/__let.hpp @@ -113,7 +113,7 @@ namespace STDEXEC using __bad_result_sender_t = __mexception< _WHAT_(_FUNCTION_MUST_RETURN_A_VALID_SENDER_IN_THE_CURRENT_ENVIRONMENT_), _WHERE_(_IN_ALGORITHM_, _LetTag), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, __fn_t<_WITH_ENVIRONMENT_, _JoinEnv2>..., __mapply_q<_NESTED_ERROR_, __try_completion_signatures_of_t<_Sender, _JoinEnv2...>>>; @@ -634,7 +634,7 @@ namespace STDEXEC if constexpr (!__decay_copyable<_CvSender>) { return STDEXEC::__throw_compile_time_error<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, - _WITH_PRETTY_SENDER_<_CvSender>>(); + _WITH_SENDER_<_CvSender>>(); } else if constexpr (__t<_LetTag>() == STDEXEC::set_value) { diff --git a/include/stdexec/__detail/__on.hpp b/include/stdexec/__detail/__on.hpp index 6071a30b8..258fc24e3 100644 --- a/include/stdexec/__detail/__on.hpp +++ b/include/stdexec/__detail/__on.hpp @@ -62,7 +62,7 @@ namespace STDEXEC __not_a_scheduler<_WHAT_(_CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_), _WHY_(_THE_CURRENT_EXECUTION_ENVIRONMENT_DOESNT_HAVE_A_SCHEDULER_), _WHERE_(_IN_ALGORITHM_, on_t), - _WITH_PRETTY_SENDER_<_Child>, + _WITH_SENDER_<_Child>, _WITH_ENVIRONMENT_(_Env)>>; // This transform_sender overload handles the case where `on` was called @@ -364,8 +364,7 @@ namespace STDEXEC template static auto transform_sender(set_value_t, _Sender&&, _Env&&) { - return __not_a_sender<_WHAT_(_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_), - _WITH_PRETTY_SENDER_<_Sender>>{}; + return __not_a_sender<_WHAT_(_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_), _WITH_SENDER_<_Sender>>{}; } }; diff --git a/include/stdexec/__detail/__parallel_scheduler.hpp b/include/stdexec/__detail/__parallel_scheduler.hpp index 1c1ad3add..54c4f8cab 100644 --- a/include/stdexec/__detail/__parallel_scheduler.hpp +++ b/include/stdexec/__detail/__parallel_scheduler.hpp @@ -853,7 +853,7 @@ namespace STDEXEC _WHERE_(_IN_ALGORITHM_, tag_of_t<_Sender>), _TO_FIX_THIS_ERROR_( ADD_A_CONTINUES_ON_TRANSITION_TO_THE_PARALLEL_SCHEDULER_BEFORE_THE_BULK_ALGORITHM), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_(_Env)>(); } } diff --git a/include/stdexec/__detail/__prologue.hpp b/include/stdexec/__detail/__prologue.hpp index 8ac10ea63..de969c103 100644 --- a/include/stdexec/__detail/__prologue.hpp +++ b/include/stdexec/__detail/__prologue.hpp @@ -32,6 +32,9 @@ STDEXEC_PRAGMA_PUSH() // warn the user spuriously STDEXEC_PRAGMA_IGNORE_GNU("-Wunused-template") +// Don't warn about C++26 extensions +STDEXEC_PRAGMA_IGNORE_GNU("-Wc++26-extensions") + // Windows.h macros: #if defined(interface) diff --git a/include/stdexec/__detail/__sender_concepts.hpp b/include/stdexec/__detail/__sender_concepts.hpp index a687259ff..6b75bc994 100644 --- a/include/stdexec/__detail/__sender_concepts.hpp +++ b/include/stdexec/__detail/__sender_concepts.hpp @@ -343,9 +343,7 @@ namespace STDEXEC template constexpr auto __diagnose_sender_concept_failure() noexcept { - return __detail::__diagnose_sender_concept_failure<_WITH_PRETTY_SENDER_<_Sender>, - _Sender, - _Env...>(); + return __detail::__diagnose_sender_concept_failure<_WITH_SENDER_<_Sender>, _Sender, _Env...>(); } } // namespace STDEXEC diff --git a/include/stdexec/__detail/__sender_introspection.hpp b/include/stdexec/__detail/__sender_introspection.hpp index 0fbfe11de..395ec4fe0 100644 --- a/include/stdexec/__detail/__sender_introspection.hpp +++ b/include/stdexec/__detail/__sender_introspection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2024 NVIDIA Corporation + * Copyright (c) 2021-2026 NVIDIA Corporation * * Licensed under the Apache License Version 2.0 with LLVM Exceptions * (the "License"); you may not use this file except in compliance with @@ -24,8 +24,12 @@ import stdexec; #else # include "__execution_fwd.hpp" + +# include "../functional.hpp" # include "__meta.hpp" # include "__sender_concepts.hpp" +# include "__structured_apply.hpp" +# include "__structured_binding_size.hpp" # include "__tuple.hpp" // IWYU pragma: keep for __is_tuple and __tuple_size_v # include "__type_traits.hpp" @@ -36,274 +40,87 @@ import stdexec; # include "__prologue.hpp" -STDEXEC_PRAGMA_IGNORE_GNU("-Wc++26-extensions") - namespace STDEXEC { -# if STDEXEC_USE_MODULES() - STDEXEC_MODULE_EXPORT_AUTHORING - template - struct __sexpr; -# else - namespace - { - template - struct __sexpr; - } // namespace -# endif - - // A type that describes a sender's metadata STDEXEC_MODULE_EXPORT_AUTHORING template - struct __desc - { - using __tag = _Tag; - using __data = _Data; - using __indices = __make_indices; - using __children = __mlist<_Child...>; - - constexpr auto operator()() const noexcept -> __desc - { - return __desc{}; - } - - template - using __f = __minvoke<_Fn, _Args..., _Tag, _Data, _Child...>; - }; - - namespace __detail - { - template - auto __std_tuple_sizer(std::tuple<_Ts...> const &) -> __msize_t; - } // namespace __detail - - template - concept __is_std_tuple = requires(_Tuple &&__arg) { __detail::__std_tuple_sizer(__arg); }; - - template - inline constexpr int __structured_binding_size_v = -1; - -# if STDEXEC_HAS_BUILTIN(__builtin_structured_binding_size) - template - requires(__builtin_structured_binding_size(_Ty) >= 0U) - inline constexpr int __structured_binding_size_v<_Ty> = __builtin_structured_binding_size(_Ty); -# else - template <__is_tuple _Ty> - inline constexpr int __structured_binding_size_v<_Ty> = __tuple_size_v<_Ty>; - - template <__is_std_tuple _Ty> - inline constexpr int __structured_binding_size_v<_Ty> = decltype(__detail::__std_tuple_sizer( - __declval<_Ty>()))::value; - - // For types that are *not* tuples, __structured_binding_size_v must be - // specialized explicitly. -# endif + struct __sexpr; namespace __detail { - template - struct __static_const - { - using type = decltype(_Apply); - static constexpr type value = _Apply; - }; - -# if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 202411L - - // Structured bindings can introduce a pack, so the implementation of - // __structured_apply is simple. - template - inline constexpr auto __structured_apply_impl = - [](_Fn &&__fn, _Type &&__obj, _Us &&...__us) // - noexcept(_Nothrow) -> decltype(auto) - { - using __cpcv = __copy_cvref_fn<_Type>; - auto &[... __as] = __obj; - return static_cast<_Fn &&>(__fn)(static_cast<_Us &&>(__us)..., - static_cast<__mcall1<__cpcv, decltype(__as)> &&>(__as)...); - }; - - template - inline constexpr auto const &__structured_apply_v = __structured_apply_impl<_Nothrow>; + template + STDEXEC_ATTRIBUTE(host, device) + auto __get_tag_of(__tuple<_Tag, _Data, _Child...> const &) -> _Tag; +# if !STDEXEC_MSVC() && (!STDEXEC_CLANG() || STDEXEC_CLANG_VERSION >= 2100) + template + requires(!__is_tuple<_Sender>) && (__structured_binding_size_v<_Sender> >= 2) + STDEXEC_ATTRIBUTE(host, device) + auto __get_tag_of(_Sender const &) -> __call_result_t<__structured_apply_t, __front, _Sender>; # else - - // Structured bindings *cannot* introduce a pack, so we explicitly handle - // structures with up to 10 members. - template - extern __undefined<__msize_t<_Ny>> __structured_apply_v; - - template - inline constexpr auto const &__structured_apply_v<0, _Nothrow> = __static_const<( // - [](_Fn &&__fn, __ignore, _Us &&...__us) noexcept(_Nothrow) // - -> decltype(auto) // - { // - return static_cast<_Fn &&>(__fn)(static_cast<_Us &&>(__us)...); // - })>::value; // - -# define STDEXEC_STRUCTURED_APPLY_ELEM_ID(_NY) STDEXEC_PP_IF(_NY, STDEXEC_PP_COMMA, STDEXEC_PP_EAT)() __a##_NY -# define STDEXEC_STRUCTURED_APPLY_ELEM(_NY) , static_cast<__mcall1<__cpcv, decltype(__a##_NY)> &&>(__a##_NY) -# define STDEXEC_STRUCTURED_APPLY_ITERATE(_IDX) \ - template \ - inline constexpr auto const& __structured_apply_v<_IDX, _Nothrow> = __static_const<( \ - [](_Fn &&__fn, _Type &&__obj, _Us &&...__us) \ - noexcept(_Nothrow) -> decltype(auto) \ - { \ - using __cpcv = __copy_cvref_fn<_Type>; \ - auto &[STDEXEC_PP_REPEAT(_IDX, STDEXEC_STRUCTURED_APPLY_ELEM_ID)] = __obj; \ - return static_cast<_Fn &&>(__fn)( \ - static_cast<_Us &&>(__us)... STDEXEC_PP_REPEAT(_IDX, STDEXEC_STRUCTURED_APPLY_ELEM)); \ - })>::value - - STDEXEC_STRUCTURED_APPLY_ITERATE(1); - STDEXEC_STRUCTURED_APPLY_ITERATE(2); - STDEXEC_STRUCTURED_APPLY_ITERATE(3); - STDEXEC_STRUCTURED_APPLY_ITERATE(4); - STDEXEC_STRUCTURED_APPLY_ITERATE(5); - STDEXEC_STRUCTURED_APPLY_ITERATE(6); - STDEXEC_STRUCTURED_APPLY_ITERATE(7); - STDEXEC_STRUCTURED_APPLY_ITERATE(8); - STDEXEC_STRUCTURED_APPLY_ITERATE(9); - STDEXEC_STRUCTURED_APPLY_ITERATE(10); -# undef STDEXEC_STRUCTURED_APPLY_ELEM -# undef STDEXEC_STRUCTURED_APPLY_ELEM_ID -# undef STDEXEC_STRUCTURED_APPLY_ITERATE - -# endif - - struct __structured_apply + // MSVC and clang < 21 have a bug where the return type of the function is + // computed even if the constraints are not satisfied. Use return type + // deduction instead to defer the evaluation until the function is actually + // instantiated. + template + requires(!__is_tuple<_Sender>) && (__structured_binding_size_v<_Sender> >= 2) + STDEXEC_ATTRIBUTE(host, device) + auto __get_tag_of(_Sender const &) { - private: - template - struct __get_declfn - { - template - constexpr auto operator()(_As &&...) const noexcept - { - if constexpr (__callable<_Fn, _As...>) - { - return __declfn<__call_result_t<_Fn, _As...>, __nothrow_callable<_Fn, _As...>>(); - } - } - }; - -# if STDEXEC_EDG() - template - static auto __declfn_fn() // - -> decltype((__detail::__structured_apply_v<__structured_binding_size_v<_Type>>) ( // - __get_declfn<_Fn>{}, - __declval<_Type>(), - __declval<_Us>()...)); - - template - requires(__structured_binding_size_v<_Type> >= 0) - using __declfn_t = decltype(__declfn_fn<_Fn, _Type, _Us...>()); -# else - template - requires(__structured_binding_size_v<_Type> >= 0) - using __declfn_t = __result_of<__structured_apply_v<__structured_binding_size_v<_Type>>, - __get_declfn<_Fn>, - _Type, - _Us...>; + return __call_result_t<__structured_apply_t, __front, _Sender>(); + } # endif - public: - template > - requires __callable<_DeclFn> - constexpr auto operator()(_Fn &&__fn, _Type &&__obj, _Us &&...__us) const - noexcept(__nothrow_callable<_DeclFn>) -> __call_result_t<_DeclFn> - { - return (__structured_apply_v<__structured_binding_size_v<_Type>, - __nothrow_callable<_DeclFn>>) (static_cast<_Fn &&>(__fn), - static_cast<_Type &&>(__obj), - static_cast<_Us &&>(__us)...); - } - }; - - struct __get_desc - { - template - constexpr auto operator()(_Tag, _Data const &, _Child const &...) const noexcept - -> __desc<_Tag, _Data, _Child...> - { - return __desc<_Tag, _Data, _Child...>{}; - } - }; - template - using __desc_of_t = __call_result_t<__structured_apply, __get_desc, _Sender>; + using __tag_of_t = decltype(__detail::__get_tag_of(__declval<_Sender const &>())); - STDEXEC_MODULE_EXPORT_AUTHORING - template - extern __undefined<_Sender> &__desc_of_v; - - STDEXEC_MODULE_EXPORT_AUTHORING - template - requires(__structured_binding_size_v<_Sender> >= 2) - extern __desc_of_t<_Sender> __desc_of_v<_Sender>; - - STDEXEC_MODULE_EXPORT_AUTHORING - template - extern decltype(_Descriptor()) __desc_of_v<__sexpr<_Descriptor>>; + template + requires __mcallable1_q<__tag_of_t, _CvSender> + inline constexpr auto __tag_of_v = __declfn<__tag_of_t<_CvSender>>(); } // namespace __detail - using __structured_apply_t = __detail::__structured_apply; - inline constexpr __structured_apply_t __structured_apply{}; - - template - using __desc_of_t = decltype(__detail::__desc_of_v<__decay_t<_Sender>>()); - // NOT TO SPEC: in the specification, the tparam of tag_of_t is constrained with the // sender concept STDEXEC_MODULE_EXPORT - template - requires enable_sender<__decay_t<_Sender>> - using tag_of_t = __desc_of_t<_Sender>::__tag; + template + requires enable_sender<__decay_t<_CvSender>> + using tag_of_t = decltype(__detail::__tag_of_v<_CvSender>()); STDEXEC_MODULE_EXPORT_AUTHORING - template - using __data_of = __copy_cvref_t<_Sender, typename __desc_of_t<_Sender>::__data>; + template + using __data_of = __copy_cvref_t<_CvSender, typename __decay_t<_CvSender>::__data_t>; - template > - using __children_of = __mapply<__mtransform<__copy_cvref_fn<_Sender>, _Continuation>, - typename __desc_of_t<_Sender>::__children>; + template > + using __children_of = __mapply<__mtransform<__copy_cvref_fn<_CvSender>, _Continuation>, + typename __decay_t<_CvSender>::__children_t>; - template - using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>; + template + using __nth_child_of = __children_of<_CvSender, __mbind_front_q<__m_at, _Ny>>; - template - using __nth_child_of_c = __nth_child_of<__msize_t<_Ny>, _Sender>; + template + using __nth_child_of_c = __nth_child_of<__msize_t<_Ny>, _CvSender>; STDEXEC_MODULE_EXPORT_AUTHORING - template - using __child_of = __children_of<_Sender, __qq<__mfront>>; - - template - inline constexpr std::size_t __nbr_children_of = __children_of<_Sender, __msize>::value; - - template - struct __mfor<__sexpr<_Descriptor>> : decltype(_Descriptor()){}; - - template - struct __mfor<__sexpr<_Descriptor> &> : decltype(_Descriptor()){}; + template + using __child_of = __children_of<_CvSender, __qq<__mfront>>; - template - struct __mfor<__sexpr<_Descriptor> const &> : decltype(_Descriptor()){}; + template + inline constexpr std::size_t __nbr_children_of = __children_of<_CvSender, __msize>::value; STDEXEC_MODULE_EXPORT_AUTHORING - template - concept __sender_for = sender<_Sender> && __minvocable_q - && (__std::same_as, _Tag> && ...); + template + concept __sender_for = sender<_CvSender> && __minvocable_q + && (__std::same_as, _Tag> && ...); - template + template concept sender_expr STDEXEC_DEPRECATE_CONCEPT("Please use exec::sender_for from " - " instead") = __sender_for<_Sender>; + " instead") = __sender_for<_CvSender>; - template + template concept sender_expr_for STDEXEC_DEPRECATE_CONCEPT("Please use exec::sender_for from " - " instead") = __sender_for<_Sender, _Tag>; + " instead") = __sender_for<_CvSender, _Tag>; } // namespace STDEXEC # include "__epilogue.hpp" diff --git a/include/stdexec/__detail/__sequence.hpp b/include/stdexec/__detail/__sequence.hpp index 28a703b18..45bd74698 100644 --- a/include/stdexec/__detail/__sequence.hpp +++ b/include/stdexec/__detail/__sequence.hpp @@ -340,7 +340,7 @@ namespace STDEXEC using __error_t = __mexception<_WHAT_(_INVALID_ARGUMENT_), _WHERE_(_IN_ALGORITHM_, __sequence_t), _WHY_(_ALL_SENDERS_BUT_THE_LAST_MUST_BE_SENDERS_OF_VOID_), - _WITH_PRETTY_SENDER_<_Self>>; + _WITH_SENDER_<_Self>>; template constexpr auto operator()() const noexcept @@ -382,7 +382,7 @@ namespace STDEXEC if constexpr (!__decay_copyable<_Self>) { return STDEXEC::__throw_compile_time_error<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, - _WITH_PRETTY_SENDER_<_Self>>(); + _WITH_SENDER_<_Self>>(); } else if constexpr (!__sends...>) { @@ -505,13 +505,6 @@ namespace STDEXEC // transformed further. template inline constexpr auto __structured_binding_size_v<__seq::__sndr<_Senders...>> = -1; - - namespace __detail - { - template - extern __mtype<__seq::__sndr<__demangle_t<_Senders>...>> - __demangle_v<__seq::__sndr<_Senders...>>; - } // namespace __detail } // namespace STDEXEC # include "__epilogue.hpp" diff --git a/include/stdexec/__detail/__starts_on.hpp b/include/stdexec/__detail/__starts_on.hpp index ad8209523..d055dc719 100644 --- a/include/stdexec/__detail/__starts_on.hpp +++ b/include/stdexec/__detail/__starts_on.hpp @@ -217,7 +217,7 @@ namespace STDEXEC template static constexpr auto transform_sender(set_value_t, _Sender&&, __ignore) { - return __not_a_sender<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, _WITH_PRETTY_SENDER_<_Sender>>{}; + return __not_a_sender<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, _WITH_SENDER_<_Sender>>{}; } }; diff --git a/include/stdexec/__detail/__stopped_as_error.hpp b/include/stdexec/__detail/__stopped_as_error.hpp index 1371bdc12..493df369b 100644 --- a/include/stdexec/__detail/__stopped_as_error.hpp +++ b/include/stdexec/__detail/__stopped_as_error.hpp @@ -177,7 +177,7 @@ namespace STDEXEC { return __not_a_sender<_WHAT_(_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_), _WHERE_(_IN_ALGORITHM_, stopped_as_error_t), - _WITH_PRETTY_SENDER_<_Sender>>{}; + _WITH_SENDER_<_Sender>>{}; } }; diff --git a/include/stdexec/__detail/__stopped_as_optional.hpp b/include/stdexec/__detail/__stopped_as_optional.hpp index a8c2f05bd..cc66fdbae 100644 --- a/include/stdexec/__detail/__stopped_as_optional.hpp +++ b/include/stdexec/__detail/__stopped_as_optional.hpp @@ -86,7 +86,7 @@ namespace STDEXEC return STDEXEC::__throw_compile_time_error< _WHAT_(_SENDER_MUST_HAVE_EXACTLY_ONE_VALUE_COMPLETION_WITH_AT_LEAST_ONE_ARGUMENT_), _WHERE_(_IN_ALGORITHM_, stopped_as_optional_t), - _WITH_PRETTY_SENDER_<__cv_sndr_t>>(); + _WITH_SENDER_<__cv_sndr_t>>(); } else { diff --git a/include/stdexec/__detail/__structured_apply.hpp b/include/stdexec/__detail/__structured_apply.hpp new file mode 100644 index 000000000..d74502804 --- /dev/null +++ b/include/stdexec/__detail/__structured_apply.hpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021-2026 NVIDIA Corporation + * + * Licensed under the Apache License Version 2.0 with LLVM Exceptions + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://llvm.org/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "__config.hpp" + +#if STDEXEC_USE_MODULES() && !defined(STDEXEC_IN_MODULE_PURVIEW) + +import stdexec; + +#else + +# include "__execution_fwd.hpp" + +# include "__meta.hpp" +# include "__structured_binding_size.hpp" +# include "__tuple.hpp" // IWYU pragma: keep for __is_tuple and __tuple_size_v +# include "__type_traits.hpp" + +# if !STDEXEC_USE_MODULES() +# include // IWYU pragma: keep for std::terminate +# endif + +# include "__prologue.hpp" + +namespace STDEXEC +{ + namespace __detail + { + template + struct __static_const + { + using type = decltype(_Apply); + static constexpr type value = _Apply; + }; + +# if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 202411L + + // Structured bindings can introduce a pack, so the implementation of + // __structured_apply is simple. + template + inline constexpr auto __structured_apply_impl = + [](_Fn &&__fn, _Type &&__obj, _Us &&...__us) // + noexcept(_Nothrow) -> decltype(auto) + { + using __cpcv = __copy_cvref_fn<_Type>; + auto &[... __as] = __obj; + return static_cast<_Fn &&>(__fn)(static_cast<_Us &&>(__us)..., + static_cast<__mcall1<__cpcv, decltype(__as)> &&>(__as)...); + }; + + template + inline constexpr auto const &__structured_apply_v = __structured_apply_impl<_Nothrow>; + +# else + + // Structured bindings *cannot* introduce a pack, so we explicitly handle + // structures with up to 10 members. + template + extern __undefined<__msize_t<_Ny>> __structured_apply_v; + + template + inline constexpr auto const &__structured_apply_v<0, _Nothrow> = __static_const<( // + [](_Fn &&__fn, __ignore, _Us &&...__us) noexcept(_Nothrow) // + -> decltype(auto) // + { // + return static_cast<_Fn &&>(__fn)(static_cast<_Us &&>(__us)...); // + })>::value; // + +# define STDEXEC_STRUCTURED_APPLY_ELEM_ID(_NY) STDEXEC_PP_IF(_NY, STDEXEC_PP_COMMA, STDEXEC_PP_EAT)() __a##_NY +# define STDEXEC_STRUCTURED_APPLY_ELEM(_NY) , static_cast<__mcall1<__cpcv, decltype(__a##_NY)> &&>(__a##_NY) +# define STDEXEC_STRUCTURED_APPLY_ITERATE(_IDX) \ + template \ + inline constexpr auto const& __structured_apply_v<_IDX, _Nothrow> = __static_const<( \ + [](_Fn &&__fn, _Type &&__obj, _Us &&...__us) \ + noexcept(_Nothrow) -> decltype(auto) \ + { \ + using __cpcv = __copy_cvref_fn<_Type>; \ + auto &[STDEXEC_PP_REPEAT(_IDX, STDEXEC_STRUCTURED_APPLY_ELEM_ID)] = __obj; \ + return static_cast<_Fn &&>(__fn)( \ + static_cast<_Us &&>(__us)... STDEXEC_PP_REPEAT(_IDX, STDEXEC_STRUCTURED_APPLY_ELEM)); \ + })>::value + + STDEXEC_STRUCTURED_APPLY_ITERATE(1); + STDEXEC_STRUCTURED_APPLY_ITERATE(2); + STDEXEC_STRUCTURED_APPLY_ITERATE(3); + STDEXEC_STRUCTURED_APPLY_ITERATE(4); + STDEXEC_STRUCTURED_APPLY_ITERATE(5); + STDEXEC_STRUCTURED_APPLY_ITERATE(6); + STDEXEC_STRUCTURED_APPLY_ITERATE(7); + STDEXEC_STRUCTURED_APPLY_ITERATE(8); + STDEXEC_STRUCTURED_APPLY_ITERATE(9); + STDEXEC_STRUCTURED_APPLY_ITERATE(10); +# undef STDEXEC_STRUCTURED_APPLY_ELEM +# undef STDEXEC_STRUCTURED_APPLY_ELEM_ID +# undef STDEXEC_STRUCTURED_APPLY_ITERATE + +# endif + + struct __structured_apply + { + private: + template + struct __get_declfn + { + template + constexpr auto operator()(_As &&...) const noexcept + { + if constexpr (__callable<_Fn, _As...>) + { + return __declfn<__call_result_t<_Fn, _As...>, __nothrow_callable<_Fn, _As...>>(); + } + } + }; + +# if STDEXEC_EDG() + template + static auto __declfn_fn() // + -> decltype((__detail::__structured_apply_v<__structured_binding_size_v<_Type>>) ( // + __get_declfn<_Fn>{}, + __declval<_Type>(), + __declval<_Us>()...)); + + template + requires(__structured_binding_size_v<_Type> >= 0) + using __declfn_t = decltype(__declfn_fn<_Fn, _Type, _Us...>()); +# else + template + requires(__structured_binding_size_v<_Type> >= 0) + using __declfn_t = __result_of<__structured_apply_v<__structured_binding_size_v<_Type>>, + __get_declfn<_Fn>, + _Type, + _Us...>; +# endif + + public: + template > + requires __callable<_DeclFn> + constexpr auto operator()(_Fn &&__fn, _Type &&__obj, _Us &&...__us) const + noexcept(__nothrow_callable<_DeclFn>) -> __call_result_t<_DeclFn> + { + return __structured_apply_v<__structured_binding_size_v<_Type>, + __nothrow_callable<_DeclFn>>(static_cast<_Fn &&>(__fn), + static_cast<_Type &&>(__obj), + static_cast<_Us &&>(__us)...); + } + }; + } // namespace __detail + + using __structured_apply_t = __detail::__structured_apply; + inline constexpr __structured_apply_t __structured_apply{}; +} // namespace STDEXEC + +# include "__epilogue.hpp" +#endif // !STDEXEC_USE_MODULES() || defined(STDEXEC_IN_MODULE_PURVIEW) diff --git a/include/stdexec/__detail/__structured_binding_size.hpp b/include/stdexec/__detail/__structured_binding_size.hpp new file mode 100644 index 000000000..33a57eb52 --- /dev/null +++ b/include/stdexec/__detail/__structured_binding_size.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021-2026 NVIDIA Corporation + * + * Licensed under the Apache License Version 2.0 with LLVM Exceptions + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://llvm.org/LICENSE.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "__config.hpp" + +#if STDEXEC_USE_MODULES() && !defined(STDEXEC_IN_MODULE_PURVIEW) + +import stdexec; + +#else + +# include "__execution_fwd.hpp" + +# include "__meta.hpp" +# include "__tuple.hpp" // IWYU pragma: keep for __is_tuple and __tuple_size_v + +# if !STDEXEC_USE_MODULES() +# include // IWYU pragma: keep for std::terminate +# endif + +# include "__prologue.hpp" + +namespace STDEXEC +{ + namespace __detail + { + template + auto __std_tuple_sizer(std::tuple<_Ts...> const &) -> __msize_t; + } // namespace __detail + + template + concept __is_std_tuple = requires(_Tuple &&__arg) { __detail::__std_tuple_sizer(__arg); }; + + template + inline constexpr int __structured_binding_size_v = -1; + +# if STDEXEC_HAS_BUILTIN(__builtin_structured_binding_size) + template + requires(__builtin_structured_binding_size(_Ty) >= 0U) + inline constexpr int __structured_binding_size_v<_Ty> = __builtin_structured_binding_size(_Ty); +# else + template <__is_tuple _Ty> + inline constexpr int __structured_binding_size_v<_Ty> = __tuple_size_v<_Ty>; + + template <__is_std_tuple _Ty> + inline constexpr int __structured_binding_size_v<_Ty> = decltype(__detail::__std_tuple_sizer( + __declval<_Ty>()))::value; + + // For types that are *not* tuples, __structured_binding_size_v must be + // specialized explicitly. +# endif +} // namespace STDEXEC + +# include "__epilogue.hpp" +#endif // !STDEXEC_USE_MODULES() || defined(STDEXEC_IN_MODULE_PURVIEW) diff --git a/include/stdexec/__detail/__sync_wait.hpp b/include/stdexec/__detail/__sync_wait.hpp index 07456e3d3..6b500e2e8 100644 --- a/include/stdexec/__detail/__sync_wait.hpp +++ b/include/stdexec/__detail/__sync_wait.hpp @@ -197,7 +197,7 @@ namespace STDEXEC::__sync_wait __mexception<_WHAT_(_INVALID_ARGUMENT_), _WHERE_(_IN_ALGORITHM_, sync_wait_t), _WHY_(_Reason), - _WITH_PRETTY_SENDER_<_CvSender>, + _WITH_SENDER_<_CvSender>, _WITH_ENVIRONMENT_(_Env), _TO_FIX_THIS_ERROR_(_USE_SYNC_WAIT_WITH_VARIANT_INSTEAD_)>; diff --git a/include/stdexec/__detail/__task_scheduler.hpp b/include/stdexec/__detail/__task_scheduler.hpp index 74385070b..1175756a5 100644 --- a/include/stdexec/__detail/__task_scheduler.hpp +++ b/include/stdexec/__detail/__task_scheduler.hpp @@ -213,7 +213,7 @@ namespace STDEXEC _CANNOT_DISPATCH_BULK_ALGORITHM_TO_TASK_SCHEDULER_BECAUSE_THERE_IS_NO_TASK_SCHEDULER_IN_THE_ENVIRONMENT), _TO_FIX_THIS_ERROR_( _ADD_A_CONTINUES_ON_TRANSITION_TO_THE_TASK_SCHEDULER_BEFORE_THE_BULK_ALGORITHM), - _WITH_PRETTY_SENDER_<_Sndr>, + _WITH_SENDER_<_Sndr>, _WITH_ENVIRONMENT_(_Env)>{}; } else diff --git a/include/stdexec/__detail/__transfer_just.hpp b/include/stdexec/__detail/__transfer_just.hpp index 72ef2daf1..5d2d103c8 100644 --- a/include/stdexec/__detail/__transfer_just.hpp +++ b/include/stdexec/__detail/__transfer_just.hpp @@ -66,7 +66,7 @@ namespace STDEXEC } else { - return __not_a_sender<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, _WITH_PRETTY_SENDER_<_Sender>>(); + return __not_a_sender<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, _WITH_SENDER_<_Sender>>(); } } diff --git a/include/stdexec/__detail/__typeinfo.hpp b/include/stdexec/__detail/__typeinfo.hpp index 3e9baf807..d9ad046e3 100644 --- a/include/stdexec/__detail/__typeinfo.hpp +++ b/include/stdexec/__detail/__typeinfo.hpp @@ -47,30 +47,6 @@ namespace STDEXEC using __t = _Ty; }; - namespace __detail - { - STDEXEC_MODULE_EXPORT_AUTHORING - template - extern __mtype<_Ty> __demangle_v; - } // namespace __detail - - // A utility for pretty-printing type names in diagnostics - STDEXEC_MODULE_EXPORT_AUTHORING - template - using __demangle_t = decltype(__detail::__demangle_v<_Ty>)::__t; - - namespace __detail - { - template - extern __mtype<__demangle_t<_Ty> &> __demangle_v<_Ty &>; - - template - extern __mtype<__demangle_t<_Ty> &&> __demangle_v<_Ty &&>; - - template - extern __mtype<__demangle_t<_Ty> const &> __demangle_v<_Ty const &>; - } // namespace __detail - namespace __detail { //////////////////////////////////////////////////////////////////////////// @@ -120,7 +96,7 @@ namespace STDEXEC // __mnameof: get the pretty name of a type _Ty as a string_view at compile // time template - inline constexpr std::string_view __mnameof = __detail::__get_pretty_name<__demangle_t<_Ty>>(); + inline constexpr std::string_view __mnameof = __detail::__get_pretty_name<_Ty>(); static_assert(__mnameof == "void"); diff --git a/include/stdexec/__detail/__when_all.hpp b/include/stdexec/__detail/__when_all.hpp index 878170504..0a3f34ba6 100644 --- a/include/stdexec/__detail/__when_all.hpp +++ b/include/stdexec/__detail/__when_all.hpp @@ -446,7 +446,7 @@ namespace STDEXEC _WHERE_(_IN_ALGORITHM_, when_all_t), _WHY_(_THE_GIVEN_SENDER_CAN_COMPLETE_SUCCESSFULLY_IN_MORE_THAN_ONE_WAY_), _TO_FIX_THIS_ERROR_(_USE_WHEN_ALL_WITH_VARIANT_INSTEAD_), - _WITH_PRETTY_SENDER_<_Sender>, + _WITH_SENDER_<_Sender>, __fn_t<_WITH_ENVIRONMENT_, _Env>...>; template @@ -766,10 +766,9 @@ namespace STDEXEC } else { - return STDEXEC::__throw_compile_time_error< - _INVALID_ARGUMENTS_TO_WHEN_ALL_, - __children_of<_Self, __qq<_WITH_PRETTY_SENDERS_>>, - __fn_t<_WITH_ENVIRONMENT_, _Env>...>(); + return STDEXEC::__throw_compile_time_error<_INVALID_ARGUMENTS_TO_WHEN_ALL_, + __children_of<_Self, __qq<_WITH_SENDERS_>>, + __fn_t<_WITH_ENVIRONMENT_, _Env>...>(); } } diff --git a/include/stdexec/functional.hpp b/include/stdexec/functional.hpp index e6ab30f55..e2946c37a 100644 --- a/include/stdexec/functional.hpp +++ b/include/stdexec/functional.hpp @@ -391,6 +391,25 @@ namespace STDEXEC return __binder_t{static_cast<_Fn &&>(__fn), static_cast<_BoundArgs &&>(__bound_args)...}; }; + //! @brief Returns the first argument of a parameter pack. + //! + //! @tparam _Head The type of the first argument. + //! @tparam _Tail The types of the remaining arguments. + //! + //! @param __head The first argument. + //! + //! @returns The first argument. + struct __front + { + template + STDEXEC_ATTRIBUTE(always_inline, host, device) + constexpr auto operator()(_Head &&__head, _Tail &&...) // + noexcept(__nothrow_move_constructible<_Head>) -> _Head + { + return static_cast<_Head &&>(__head); + } + }; + //! @brief A binary callable that wraps another binary callable and calls it //! with its two arguments in reverse order. //! diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e3cb13040..94b6f1ee5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -67,7 +67,6 @@ set(stdexec_test_sources stdexec/detail/test_any.cpp stdexec/detail/test_common_domain.cpp stdexec/detail/test_completion_signatures.cpp - stdexec/detail/test_demangle.cpp stdexec/detail/test_intrusive_mpsc_queue.cpp stdexec/detail/test_utility.cpp stdexec/queries/test_env.cpp diff --git a/test/stdexec/concepts/test_concept_scheduler.cpp b/test/stdexec/concepts/test_concept_scheduler.cpp index e208c36bc..51d74fae1 100644 --- a/test/stdexec/concepts/test_concept_scheduler.cpp +++ b/test/stdexec/concepts/test_concept_scheduler.cpp @@ -25,7 +25,6 @@ STDEXEC_PRAGMA_IGNORE_GNU("-Wunneeded-internal-declaration") namespace { - template struct default_env { @@ -196,9 +195,7 @@ namespace struct my_void_schedule_scheduler { - [[nodiscard]] - auto schedule() const noexcept -> void - {} + auto schedule() const noexcept -> void {} friend auto operator==(my_void_schedule_scheduler, my_void_schedule_scheduler) noexcept -> bool { diff --git a/test/stdexec/detail/test_demangle.cpp b/test/stdexec/detail/test_demangle.cpp deleted file mode 100644 index 6b1fa0a38..000000000 --- a/test/stdexec/detail/test_demangle.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2025 NVIDIA Corporation - * - * Licensed under the Apache License Version 2.0 with LLVM Exceptions - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * https://llvm.org/LICENSE.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include - -#include - -namespace -{ - TEST_CASE("demangling a type", "[detail][demangle]") - { - struct Dummy - { - void operator()(int const) const {} - }; - auto sndr = STDEXEC::just(42) | STDEXEC::then(Dummy{}); - - static_assert( - std::same_as, - STDEXEC::__basic_sender< - STDEXEC::then_t, - Dummy, - STDEXEC::__basic_sender>::type>::type>); - } -} // namespace From 67fbeb4336b5fc70bba940c0b601f5514ccefd93 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 8 Oct 2026 23:41:01 +0000 Subject: [PATCH 3/4] simplify the names of the `just*` sender types --- include/stdexec/__detail/__just.hpp | 118 ++++++++++++++++++---------- 1 file changed, 77 insertions(+), 41 deletions(-) diff --git a/include/stdexec/__detail/__just.hpp b/include/stdexec/__detail/__just.hpp index 25ebbc9e3..f0c3ab8e7 100644 --- a/include/stdexec/__detail/__just.hpp +++ b/include/stdexec/__detail/__just.hpp @@ -159,24 +159,43 @@ namespace STDEXEC { using __tag_t = set_value_t; - //! @brief Construct a sender that synchronously value-completes with the - //! decay-copies of @c __ts.... - //! - //! @tparam _Ts Zero or more types each satisfying the internal - //! `__movable_value` concept. - //! @param __ts The values to deliver. Each is decay-copied into the - //! resulting sender. - //! - //! @returns A sender with the single completion signature - //! `set_value_t(std::decay_t<_Ts>...)`. + template + struct __sender; + + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __sender(just_t, __tuple<_Ts...>) -> __sender<_Ts...>; + template <__movable_value... _Ts> STDEXEC_ATTRIBUTE(host, device) - constexpr auto operator()(_Ts&&... __ts) const noexcept(__nothrow_decay_copyable<_Ts...>) - { - return __sexpr{just_t(), __tuple{static_cast<_Ts&&>(__ts)...}}; - } + constexpr auto operator()(_Ts&&... __ts) const noexcept(__nothrow_decay_copyable<_Ts...>); }; + template <> + struct __sexpr_impl : __just::__impl + {}; + + template + struct just_t::__sender : __sexpr> + {}; + + //! @brief Construct a sender that synchronously value-completes with the + //! decay-copies of @c __ts.... + //! + //! @tparam _Ts Zero or more types each satisfying the internal + //! `__movable_value` concept. + //! @param __ts The values to deliver. Each is decay-copied into the + //! resulting sender. + //! + //! @returns A sender with the single completion signature + //! `set_value_t(std::decay_t<_Ts>...)`. + template <__movable_value... _Ts> + STDEXEC_ATTRIBUTE(host, device) + inline constexpr auto just_t::operator()(_Ts&&... __ts) const + noexcept(__nothrow_decay_copyable<_Ts...>) + { + return just_t::__sender{just_t(), __tuple{static_cast<_Ts&&>(__ts)...}}; + } + //! @brief A sender factory that produces a sender which completes //! synchronously with the given error on the error channel. //! @@ -222,22 +241,41 @@ namespace STDEXEC { using __tag_t = set_error_t; - //! @brief Construct a sender that synchronously error-completes with the - //! decay-copy of @c __err. - //! - //! @tparam _Error A type satisfying the internal `__movable_value` concept. - //! @param __err The error datum to deliver. Decay-copied into the sender. - //! - //! @returns A sender with the single completion signature - //! `set_error_t(std::decay_t<_Error>)`. + template + struct __sender; + + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __sender(just_error_t, __tuple<_Error>) -> __sender<_Error>; + template <__movable_value _Error> STDEXEC_ATTRIBUTE(host, device) - constexpr auto operator()(_Error&& __err) const noexcept(__nothrow_decay_copyable<_Error>) - { - return __sexpr{just_error_t(), __tuple{static_cast<_Error&&>(__err)}}; - } + constexpr auto operator()(_Error&& __err) const noexcept(__nothrow_decay_copyable<_Error>); }; + template <> + struct __sexpr_impl : __just::__impl + {}; + + template + struct just_error_t::__sender : __sexpr> + {}; + + //! @brief Construct a sender that synchronously error-completes with the + //! decay-copy of @c __err. + //! + //! @tparam _Error A type satisfying the internal `__movable_value` concept. + //! @param __err The error datum to deliver. Decay-copied into the sender. + //! + //! @returns A sender with the single completion signature + //! `set_error_t(std::decay_t<_Error>)`. + template <__movable_value _Error> + STDEXEC_ATTRIBUTE(host, device) + inline constexpr auto just_error_t::operator()(_Error && __err) const + noexcept(__nothrow_decay_copyable<_Error>) + { + return just_error_t::__sender{just_error_t(), __tuple{static_cast<_Error&&>(__err)}}; + } + //! @brief A sender factory that produces a sender which completes //! synchronously on the stopped channel. //! @@ -279,30 +317,28 @@ namespace STDEXEC struct just_stopped_t { using __tag_t = set_stopped_t; + struct __sender; - //! @brief Construct a sender that synchronously stops-completes. - //! - //! @returns A sender with the single completion signature - //! `set_stopped_t()`. - template STDEXEC_ATTRIBUTE(host, device) - constexpr auto operator()() const noexcept - { - return __sexpr{_Tag(), __tuple{}}; - } + constexpr auto operator()() const noexcept; }; template <> - struct __sexpr_impl : __just::__impl + struct __sexpr_impl : __just::__impl {}; - template <> - struct __sexpr_impl : __just::__impl + struct just_stopped_t::__sender : __sexpr> {}; - template <> - struct __sexpr_impl : __just::__impl - {}; + //! @brief Construct a sender that synchronously stops-completes. + //! + //! @returns A sender with the single completion signature + //! `set_stopped_t()`. + STDEXEC_ATTRIBUTE(host, device) + inline constexpr auto just_stopped_t::operator()() const noexcept + { + return just_stopped_t::__sender{just_stopped_t(), __tuple{}}; + } //! @brief The customization point object for the @c just sender factory. //! From e80205fe9b95e819693580371ade40ddefdd008b Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Fri, 9 Oct 2026 03:01:55 +0000 Subject: [PATCH 4/4] simplify the names of the `then` and `upon_[error|stopped]` senders --- include/stdexec/__detail/__then.hpp | 35 ++++++++++++----- include/stdexec/__detail/__upon_error.hpp | 38 ++++++++++++++----- include/stdexec/__detail/__upon_stopped.hpp | 42 +++++++++++++++------ 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/include/stdexec/__detail/__then.hpp b/include/stdexec/__detail/__then.hpp index 975eaefbb..1a86eece8 100644 --- a/include/stdexec/__detail/__then.hpp +++ b/include/stdexec/__detail/__then.hpp @@ -189,6 +189,12 @@ namespace STDEXEC //! sender-returning function struct then_t { + template + struct __sender; + + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __sender(then_t, _Fun, _Sender) -> __sender<_Fun, _Sender>; + //! @brief Construct a sender that adapts @c __sndr by invoking @c __fun //! with each value-completion argument pack it produces. //! @@ -213,10 +219,9 @@ namespace STDEXEC //! the program is ill-formed at the point where the resulting sender //! is connected to a receiver. template - constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender auto - { - return __sexpr{then_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; - } + STDEXEC_ATTRIBUTE(host, device) + constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const + noexcept(__nothrow_decay_copyable<_Sender, _Fun>) -> __well_formed_sender auto; //! @brief Construct a sender-adaptor closure that, when applied to a //! sender, produces `then(sndr, __fun)`. @@ -233,13 +238,29 @@ namespace STDEXEC //! value. When piped against a sender @c sndr, it yields the //! sender `then(sndr, std::move(__fun))`. template <__movable_value _Fun> - STDEXEC_ATTRIBUTE(always_inline) + STDEXEC_ATTRIBUTE(always_inline, host, device) constexpr auto operator()(_Fun __fun) const { return __closure(*this, static_cast<_Fun&&>(__fun)); } }; + template <> + struct __sexpr_impl : __then::__then_impl + {}; + + template + struct then_t::__sender : __sexpr + {}; + + template + STDEXEC_ATTRIBUTE(host, device) + inline constexpr auto then_t::operator()(_Sender && __sndr, _Fun __fun) const + noexcept(__nothrow_decay_copyable<_Sender, _Fun>) -> __well_formed_sender auto + { + return then_t::__sender{then_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; + } + //! @brief The customization point object for the @c then sender adaptor. //! //! @c then is an instance of @c then_t. See @ref then_t for the full @@ -248,10 +269,6 @@ namespace STDEXEC //! //! @hideinitializer inline constexpr then_t then{}; - - template <> - struct __sexpr_impl : __then::__then_impl - {}; } // namespace STDEXEC # include "__epilogue.hpp" diff --git a/include/stdexec/__detail/__upon_error.hpp b/include/stdexec/__detail/__upon_error.hpp index 2d7bd50b5..2a50a022c 100644 --- a/include/stdexec/__detail/__upon_error.hpp +++ b/include/stdexec/__detail/__upon_error.hpp @@ -189,6 +189,13 @@ namespace STDEXEC //! sender-returning function struct upon_error_t { + template + struct __sender; + + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE + __sender(upon_error_t, _Fun, _Sender) -> __sender<_Fun, _Sender>; + //! @brief Construct a sender that handles each error completion of //! @c __sndr by invoking @c __fun on the error datum. //! @@ -213,10 +220,9 @@ namespace STDEXEC //! ill-formed at the point where the resulting sender is connected //! to a receiver. template - constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender auto - { - return __sexpr{upon_error_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; - } + STDEXEC_ATTRIBUTE(host, device) + constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const + noexcept(__nothrow_decay_copyable<_Sender, _Fun>) -> __well_formed_sender auto; //! @brief Construct a sender-adaptor closure that, when applied to a //! sender, produces `upon_error(sndr, __fun)`. @@ -232,13 +238,31 @@ namespace STDEXEC //! value. When piped against a sender @c sndr, it yields the //! sender `upon_error(sndr, std::move(__fun))`. template <__movable_value _Fun> - STDEXEC_ATTRIBUTE(always_inline) + STDEXEC_ATTRIBUTE(always_inline, host, device) constexpr auto operator()(_Fun __fun) const noexcept(__nothrow_move_constructible<_Fun>) { return __closure(*this, static_cast<_Fun&&>(__fun)); } }; + template <> + struct __sexpr_impl : __upon_error::__upon_error_impl + {}; + + template + struct upon_error_t::__sender : __sexpr + {}; + + template + STDEXEC_ATTRIBUTE(host, device) + inline constexpr auto upon_error_t::operator()(_Sender && __sndr, _Fun __fun) const + noexcept(__nothrow_decay_copyable<_Sender, _Fun>) -> __well_formed_sender auto + { + return upon_error_t::__sender{upon_error_t(), + static_cast<_Fun&&>(__fun), + static_cast<_Sender&&>(__sndr)}; + } + //! @brief The customization point object for the @c upon_error sender //! adaptor. //! @@ -248,10 +272,6 @@ namespace STDEXEC //! //! @hideinitializer inline constexpr upon_error_t upon_error{}; - - template <> - struct __sexpr_impl : __upon_error::__upon_error_impl - {}; } // namespace STDEXEC # include "__epilogue.hpp" diff --git a/include/stdexec/__detail/__upon_stopped.hpp b/include/stdexec/__detail/__upon_stopped.hpp index 7f32013ba..82f9cab4f 100644 --- a/include/stdexec/__detail/__upon_stopped.hpp +++ b/include/stdexec/__detail/__upon_stopped.hpp @@ -158,6 +158,13 @@ namespace STDEXEC //! sender-returning function struct upon_stopped_t { + template + struct __sender; + + template + STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE + __sender(upon_stopped_t, _Fun, _Sender) -> __sender<_Fun, _Sender>; + //! @brief Construct a sender that handles a stopped completion of @c __sndr //! by invoking @c __fun and delivering its return value. //! @@ -180,10 +187,9 @@ namespace STDEXEC //! clause enforces this). Otherwise the call is not viable. template requires __callable<_Fun> - auto operator()(_Sender&& __sndr, _Fun __fun) const -> __well_formed_sender auto - { - return __sexpr{upon_stopped_t(), static_cast<_Fun&&>(__fun), static_cast<_Sender&&>(__sndr)}; - } + STDEXEC_ATTRIBUTE(host, device) + constexpr auto operator()(_Sender&& __sndr, _Fun __fun) const + noexcept(__nothrow_decay_copyable<_Sender, _Fun>) -> __well_formed_sender auto; //! @brief Construct a sender-adaptor closure that, when applied to a //! sender, produces `upon_stopped(sndr, __fun)`. @@ -200,13 +206,32 @@ namespace STDEXEC //! sender `upon_stopped(sndr, std::move(__fun))`. template <__movable_value _Fun> requires __callable<_Fun> - STDEXEC_ATTRIBUTE(always_inline) - auto operator()(_Fun __fun) const noexcept(__nothrow_move_constructible<_Fun>) + STDEXEC_ATTRIBUTE(always_inline, host, device) + constexpr auto operator()(_Fun __fun) const noexcept(__nothrow_move_constructible<_Fun>) { return __closure(*this, static_cast<_Fun&&>(__fun)); } }; + template <> + struct __sexpr_impl : __upon_stopped::__upon_stopped_impl + {}; + + template + struct upon_stopped_t::__sender : __sexpr + {}; + + template + requires __callable<_Fun> + STDEXEC_ATTRIBUTE(host, device) + inline constexpr auto upon_stopped_t::operator()(_Sender && __sndr, _Fun __fun) const + noexcept(__nothrow_decay_copyable<_Sender, _Fun>) -> __well_formed_sender auto + { + return upon_stopped_t::__sender{upon_stopped_t(), + static_cast<_Fun&&>(__fun), + static_cast<_Sender&&>(__sndr)}; + } + //! @brief The customization point object for the @c upon_stopped sender //! adaptor. //! @@ -217,11 +242,6 @@ namespace STDEXEC //! //! @hideinitializer inline constexpr upon_stopped_t upon_stopped{}; - - template <> - struct __sexpr_impl : __upon_stopped::__upon_stopped_impl - {}; - } // namespace STDEXEC # include "__epilogue.hpp"