diff --git a/include/exec/completion_signatures.hpp b/include/exec/completion_signatures.hpp index 45cb840f2..7ab18ac4c 100644 --- a/include/exec/completion_signatures.hpp +++ b/include/exec/completion_signatures.hpp @@ -43,16 +43,6 @@ namespace experimental::execution detail::normalize(static_cast(nullptr))...)); } // namespace detail - /////////////////////////////////////////////////////////////////////////////////////////////////// - // get_child_completion_signatures - template - [[nodiscard]] - consteval auto get_child_completion_signatures() - { - return STDEXEC::get_completion_signatures, - STDEXEC::__fwd_env_t<_Env>...>(); - } - //! Creates a compile-time completion signatures type from explicit and deduced signature types. //! //! This function is a compile-time helper that constructs a completion signatures type @@ -86,6 +76,16 @@ namespace experimental::execution return {}; } + /////////////////////////////////////////////////////////////////////////////////////////////////// + // get_child_completion_signatures + template + [[nodiscard]] + consteval auto get_child_completion_signatures() + { + return STDEXEC::get_completion_signatures, + STDEXEC::__fwd_env_t<_Env>...>(); + } + /////////////////////////////////////////////////////////////////////////////////////////////////// // concat_completion_signatures inline constexpr STDEXEC::__detail::__concat_completion_signatures_fn diff --git a/include/exec/repeat_n.hpp b/include/exec/repeat_n.hpp index 58344d868..e6af4c626 100644 --- a/include/exec/repeat_n.hpp +++ b/include/exec/repeat_n.hpp @@ -21,6 +21,7 @@ #include "../stdexec/__detail/__optional.hpp" #include "../stdexec/execution.hpp" +#include "completion_signatures.hpp" #include "sequence.hpp" #include "trampoline_scheduler.hpp" @@ -105,21 +106,24 @@ namespace experimental::execution __opstate_base<_Receiver> *__state_; }; + template + using __bouncy_sndr_t = + __result_of, _Child &>; + + template + constexpr bool __nothrow_connect = + __nothrow_invocable + && __nothrow_invocable, _Child &> + && __nothrow_connectable<__bouncy_sndr_t<_Child>, _Receiver>; + template struct __opstate final : __opstate_base<_Receiver> { using __receiver_t = __receiver<_Receiver>; - using __bouncy_sndr_t = - __result_of, _Child &>; - using __child_op_t = STDEXEC::connect_result_t<__bouncy_sndr_t, __receiver_t>; - - static constexpr bool __nothrow_connect = - __nothrow_invocable - && __nothrow_invocable, _Child &> - && __nothrow_connectable<__bouncy_sndr_t, __receiver_t>; + using __child_op_t = STDEXEC::connect_result_t<__bouncy_sndr_t<_Child>, __receiver_t>; constexpr explicit __opstate(std::size_t __count, _Child __child, _Receiver __rcvr) - noexcept(__nothrow_move_constructible<_Child> && __nothrow_connect) + noexcept(__nothrow_move_constructible<_Child> && __nothrow_connect<_Child, _Receiver>) : __opstate_base<_Receiver>{static_cast<_Receiver &&>(__rcvr), __count} , __child_(std::move(__child)) { @@ -141,7 +145,7 @@ namespace experimental::execution } } - constexpr auto __connect() noexcept(__nothrow_connect) -> __child_op_t & + constexpr auto __connect() noexcept(__nothrow_connect<_Child, _Receiver>) -> __child_op_t & { return __child_op_.__emplace_from(STDEXEC::connect, exec::sequence(STDEXEC::schedule(trampoline_scheduler{}), @@ -171,7 +175,7 @@ namespace experimental::execution } STDEXEC_CATCH_ALL { - if constexpr (!__nothrow_connect) + if constexpr (!__nothrow_connect<_Child, _Receiver>) { STDEXEC::set_error(std::move(this->__rcvr_), std::current_exception()); } @@ -186,36 +190,6 @@ namespace experimental::execution STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __opstate(std::size_t, _Child, _Receiver) -> __opstate<_Child, _Receiver>; - template - using __values_t = - // There's something funny going on with __if_c here. Use std::conditional_t instead. :-( - std::conditional_t<(sizeof...(_Args) == 0), - completion_signatures<>, - __mexception<_WHAT_(_INVALID_ARGUMENT_), - _WHERE_(_IN_ALGORITHM_, repeat_n_t), - _WHY_(_THE_INPUT_SENDER_MUST_HAVE_VOID_VALUE_COMPLETION_), - _WITH_PRETTY_SENDER_<_Child>>>; - - template - using __error_t = completion_signatures)>; - - template - using __with_eptr_completion_t = __eptr_completion_unless_t<__mbool< - __cmplsigs::__partitions_of_t< - __completion_signatures_of_t<_Sender, _Env...>>::__nothrow_decay_copyable::__errors::value - && (__nothrow_connectable<_Sender, __receiver_archetype<_Env>> && ...)>>; - - template - using __completions_t = STDEXEC::__transform_completion_signatures_t< - __completion_signatures_of_t<_Child &, _Env...>, - STDEXEC::__transform_completion_signatures_t< - __completion_signatures_of_t, _Env...>, - __with_eptr_completion_t<_Child, _Env...>, - __cmplsigs::__default_set_value, - __error_t>, - __mbind_front_q<__values_t, _Child>::template __f, - __error_t>; - struct __impls : __sexpr_defaults { static constexpr auto __get_attrs = @@ -225,19 +199,40 @@ namespace experimental::execution return {STDEXEC::schedule(trampoline_scheduler{}), const_cast<_Child &>(__child)}; }; - template - requires(!STDEXEC::dependent_sender<__child_of<_Sender>>) + template static consteval auto __get_completion_signatures() { - // TODO: port this to use constant evaluation - return __completions_t<__child_of<_Sender>>{}; - } + using __child_t = __child_of<_Sender>; - template - static consteval auto __get_completion_signatures() - { - // TODO: port this to use constant evaluation - return __completions_t<__child_of<_Sender>, _Env>{}; + auto __completions = transform_completion_signatures( + STDEXEC::get_completion_signatures<__bouncy_sndr_t<__child_t>, _Env...>(), + // transform for set_value completions: + []() + { + if constexpr (sizeof...(_Args) == 0) + return completion_signatures(); + else + return STDEXEC::__throw_compile_time_error< + _WHAT_(_INVALID_ARGUMENT_), + _WHERE_(_IN_ALGORITHM_, repeat_n_t), + _WHY_(_THE_INPUT_SENDER_MUST_HAVE_VOID_VALUE_COMPLETION_), + _WITH_PRETTY_SENDER_<__child_t &>>(); + }, + // transform for set_error completions: + decay_arguments()); + + STDEXEC_IF_OK(__completions) + { + // Conditionally add set_error(std::exception_ptr) when appropriate + if constexpr (__completions.template __contains()) + return __completions; // NOLINT(bugprone-branch-clone) + else if constexpr (sizeof...(_Env) == 0) + return STDEXEC::__throw_dependent_sender_error<__child_t>(); + else if constexpr ((__nothrow_connect<__child_t, __receiver_archetype<_Env>> || ...)) + return __completions; + else + return concat_completion_signatures(__completions, __eptr_completion_t()); + } } static constexpr auto __connect = // diff --git a/include/stdexec/__detail/__completion_signatures.hpp b/include/stdexec/__detail/__completion_signatures.hpp index 282457711..055b58344 100644 --- a/include/stdexec/__detail/__completion_signatures.hpp +++ b/include/stdexec/__detail/__completion_signatures.hpp @@ -24,6 +24,7 @@ #include "__tuple.hpp" // IWYU pragma: keep for __tuple #include "__utility.hpp" +#include #include #include "__prologue.hpp" @@ -432,6 +433,11 @@ namespace STDEXEC } }; + using __eptr_completion_t = completion_signatures; + + template + using __eptr_completion_unless_t = __if<_NoExcept, completion_signatures<>, __eptr_completion_t>; + #if STDEXEC_NO_STDCPP_CONSTEXPR_EXCEPTIONS() template diff --git a/include/stdexec/__detail/__finally.hpp b/include/stdexec/__detail/__finally.hpp index 43f7d151e..528d039be 100644 --- a/include/stdexec/__detail/__finally.hpp +++ b/include/stdexec/__detail/__finally.hpp @@ -324,7 +324,6 @@ namespace STDEXEC } else { - using __is_nothrow_t = __nothrow_decay_copyable_results_t<__initial_completions_t>; // The finally sender's completion signatures are ... return STDEXEC::__concat_completion_signatures( // ... the initial sender's completions with value types decayed ... @@ -333,9 +332,7 @@ namespace STDEXEC __decay_arguments()), // ... and the final sender's error and stopped completions ... STDEXEC::__transform_completion_signatures(__final_completions, - __ignore_completion()), - // ... and possibly a set_error(exception_ptr) completion. - __eptr_completion_unless_t<__is_nothrow_t>()); + __ignore_completion())); } } } diff --git a/include/stdexec/__detail/__transform_completion_signatures.hpp b/include/stdexec/__detail/__transform_completion_signatures.hpp index 01fe17548..d36edd8df 100644 --- a/include/stdexec/__detail/__transform_completion_signatures.hpp +++ b/include/stdexec/__detail/__transform_completion_signatures.hpp @@ -26,8 +26,6 @@ #include "__get_completion_signatures.hpp" #include "__meta.hpp" -#include - #include "__prologue.hpp" namespace STDEXEC @@ -444,7 +442,9 @@ namespace STDEXEC { if constexpr (__decay_copyable<_Args...>) { - return completion_signatures<_SetTag(__decay_t<_Args>...)>(); + return __concat_completion_signatures( + completion_signatures<_SetTag(__decay_t<_Args>...)>(), + __eptr_completion_unless_t<__nothrow_decay_copyable_t<_Args...>>()); } else { @@ -591,11 +591,6 @@ namespace STDEXEC } } - using __eptr_completion_t = completion_signatures; - - template - using __eptr_completion_unless_t = __if<_NoExcept, completion_signatures<>, __eptr_completion_t>; - // The following utilities are needed fairly often: template requires __invocable<_Fun, _Args...>