2121#include " ../stdexec/__detail/__optional.hpp"
2222#include " ../stdexec/execution.hpp"
2323
24+ #include " completion_signatures.hpp"
2425#include " sequence.hpp"
2526#include " trampoline_scheduler.hpp"
2627
2728#include < exception>
2829#include < type_traits>
2930
31+ STDEXEC_PRAGMA_PUSH ()
32+ STDEXEC_PRAGMA_IGNORE_EDG (not_used_in_template_function_params)
33+
3034namespace experimental ::execution
3135{
36+ struct _EXPECTING_A_SENDER_OF_ONE_VALUE_THAT_IS_CONVERTIBLE_TO_BOOL_ ;
37+ struct _EXPECTING_A_SENDER_OF_VOID_ ;
38+
3239 namespace __repeat
3340 {
3441 using namespace STDEXEC ;
@@ -81,8 +88,7 @@ namespace experimental::execution
8188 else
8289 {
8390 // Mixed results:
84- constexpr bool __is_nothrow = noexcept (
85- (static_cast <bool >(static_cast <_Booleans &&>(__bools)) && ...));
91+ constexpr bool __is_nothrow = (std::is_nothrow_convertible_v<_Booleans, bool > && ...);
8692 STDEXEC_TRY
8793 {
8894 // If the child sender completed with true, we're done
@@ -110,11 +116,11 @@ namespace experimental::execution
110116
111117 template <class _Error >
112118 constexpr void set_error (_Error &&__err) noexcept
113- { // intentionally pass-by-value
119+ {
114120 STDEXEC_TRY
115121 {
116122 auto __err_copy = static_cast <_Error &&>(__err); // make a local copy of the error...
117- __state_->__cleanup (); // because this could potentially invalidate it.
123+ __state_->__cleanup (); // ... because this could potentially invalidate it.
118124 STDEXEC::set_error (std::move (__state_->__rcvr_ ), static_cast <_Error &&>(__err_copy));
119125 }
120126 STDEXEC_CATCH_ALL
@@ -134,9 +140,9 @@ namespace experimental::execution
134140 }
135141
136142 [[nodiscard]]
137- constexpr auto get_env () const noexcept -> env_of_t<_Receiver>
143+ constexpr auto get_env () const noexcept -> __fwd_env_t< env_of_t<_Receiver> >
138144 {
139- return STDEXEC::get_env (__state_->__rcvr_ );
145+ return __fwd_env ( STDEXEC::get_env (__state_->__rcvr_ ) );
140146 }
141147
142148 __opstate_base<_Receiver> *__state_;
@@ -207,69 +213,97 @@ namespace experimental::execution
207213
208214 STDEXEC_PRAGMA_POP ()
209215
210- struct _EXPECTING_A_SENDER_OF_ONE_VALUE_THAT_IS_CONVERTIBLE_TO_BOOL_
211- {};
212- struct _EXPECTING_A_SENDER_OF_VOID_
213- {};
214-
215- template <class _Child , class ... _Args>
216- using __values_t =
217- // There's something funny going on with __if_c here. Use std::conditional_t instead. :-(
218- std::conditional_t <
219- ((sizeof ...(_Args) == 1 ) && (__std::convertible_to<_Args, bool > && ...)),
220- std::conditional_t <(__bool_constant<_Args, false > && ...),
221- completion_signatures<>,
222- completion_signatures<set_value_t ()>>,
223- __mexception<_WHAT_(_INVALID_ARGUMENT_),
224- _WHERE_ (_IN_ALGORITHM_, repeat_until_t ),
225- _WHY_ (_EXPECTING_A_SENDER_OF_ONE_VALUE_THAT_IS_CONVERTIBLE_TO_BOOL_),
226- _WITH_PRETTY_SENDER_<_Child>>>;
227-
228- template <class ... _Booleans>
229- using __values_overload_nothrow_bool_convertible_t =
230- __mand<std::is_nothrow_convertible<_Booleans, bool >...>;
231-
232- template <class _Sender , class ... _Env>
233- using __values_nothrow_bool_convertible_t =
234- __value_types_t <__completion_signatures_of_t <_Sender, _Env...>, // sigs
235- __qq<__values_overload_nothrow_bool_convertible_t >, // tuple
236- __qq<__mand> // variant
237- >;
238-
239- template <typename _Sender, typename ... _Env>
240- using __with_eptr_completion_t = __eptr_completion_unless<
241- __values_nothrow_bool_convertible_t <_Sender, _Env...>::value
242- && __cmplsigs::__partitions_of_t <
243- __completion_signatures_of_t <_Sender, _Env...>>::__nothrow_decay_copyable::__errors::value
244- && (__nothrow_connectable<_Sender, __receiver_archetype<_Env>> && ...)>;
245-
246- template <class ...>
247- using __delete_set_value_t = completion_signatures<>;
248-
249- template <class _Child , class ... _Env>
250- using __completions_t = STDEXEC ::transform_completion_signatures<
251- __completion_signatures_of_t <__decay_t <_Child> &, _Env...>,
252- STDEXEC ::transform_completion_signatures<
253- __completion_signatures_of_t <STDEXEC ::schedule_result_t <trampoline_scheduler>, _Env...>,
254- __with_eptr_completion_t <_Child, _Env...>,
255- __delete_set_value_t >,
256- __mbind_front_q<__values_t , _Child>::template __f>;
257-
258216 struct __repeat_until_impl : __sexpr_defaults
259217 {
218+ template <class _Child >
219+ static constexpr auto __transform_values = []<class ... _Args>()
220+ {
221+ if constexpr (sizeof ...(_Args) != 1 || (!__std::convertible_to<_Args, bool > || ...))
222+ {
223+ return exec::throw_compile_time_error<
224+ _WHAT_ (_INVALID_ARGUMENT_),
225+ _WHERE_ (_IN_ALGORITHM_, repeat_until_t ),
226+ _WHY_ (_EXPECTING_A_SENDER_OF_ONE_VALUE_THAT_IS_CONVERTIBLE_TO_BOOL_),
227+ _WITH_PRETTY_SENDER_<_Child>>();
228+ }
229+ else if constexpr ((__bool_constant<_Args, false > && ...))
230+ {
231+ return STDEXEC ::completion_signatures{};
232+ }
233+ else if constexpr ((std::is_nothrow_convertible_v<_Args, bool > && ...))
234+ {
235+ return STDEXEC ::completion_signatures<set_value_t ()>();
236+ }
237+ else
238+ {
239+ return STDEXEC ::completion_signatures<set_value_t (), set_error_t (std::exception_ptr)>();
240+ }
241+ };
242+
243+ static constexpr auto __transform_errors = []<class _Error >() noexcept
244+ {
245+ if constexpr (__nothrow_decay_copyable<_Error> || __decays_to<_Error, std::exception_ptr>)
246+ {
247+ return STDEXEC ::completion_signatures<set_error_t (_Error)>();
248+ }
249+ else
250+ {
251+ return STDEXEC ::completion_signatures<set_error_t (_Error),
252+ set_error_t (std::exception_ptr)>();
253+ }
254+ };
255+
260256 template <class _Sender , class ... _Env>
261257 static consteval auto __get_completion_signatures ()
262258 {
263- // TODO: port this to use constant evaluation
264- return __completions_t <__child_of<_Sender>, _Env...>{};
259+ using __child_t = __child_of<_Sender>;
260+ using __bouncer_t = schedule_result_t <trampoline_scheduler>;
261+ using __eptr_completion_t = set_error_t (std::exception_ptr);
262+ constexpr auto __eptr_completion = (__eptr_completion_t *) nullptr ;
263+
264+ STDEXEC_COMPLSIGS_LET (
265+ __sigs,
266+ exec::transform_completion_signatures (get_completion_signatures<__child_t , _Env...>(),
267+ __transform_values<__child_t >,
268+ __transform_errors))
269+ {
270+ // The repeat_until sender is a dependent sender if one of the following is
271+ // true:
272+ // - the child sender is a dependent sender, or
273+ // - the trampoline scheduler's sender is a dependent sender, or
274+ // - sizeof...(_Env) == 0 and the child sender does not have a
275+ // set_error(exception_ptr) completion.
276+ constexpr bool __is_dependent = (sizeof ...(_Env) == 0 )
277+ && (dependent_sender<__bouncer_t >
278+ || !__sigs.__contains (__eptr_completion));
279+ if constexpr (__is_dependent)
280+ {
281+ return exec::throw_compile_time_error<dependent_sender_error,
282+ _WITH_PRETTY_SENDER_<__child_t >>();
283+ }
284+ else
285+ {
286+ constexpr bool __has_nothrow_connect =
287+ (__nothrow_connectable<__child_t , __receiver_archetype<_Env>> || ...);
288+ constexpr auto __eptr_sigs = __eptr_completion_unless<__has_nothrow_connect>();
289+ constexpr auto __bouncer_sigs = exec::transform_completion_signatures (
290+ get_completion_signatures<__bouncer_t , _Env...>(),
291+ exec::ignore_completion ()); // drop the set_value_t() completion from the
292+ // trampoline scheduler.
293+
294+ return exec::concat_completion_signatures (__sigs, __eptr_sigs, __bouncer_sigs);
295+ }
296+ }
265297 };
266298
267299 static constexpr auto __connect =
268300 []<class _Sender , class _Receiver >(_Sender &&__sndr, _Receiver __rcvr) noexcept (
269- noexcept (__opstate(STDEXEC ::__get<2 >(__declval<_Sender>()), __declval<_Receiver>())))
301+ __nothrow_constructible_from<__opstate<__child_of<_Sender>, _Receiver>,
302+ __child_of<_Sender>,
303+ _Receiver>)
270304 {
271- return __opstate ( STDEXEC ::__get< 2 >( static_cast <_Sender &&>(__sndr)),
272- static_cast <_Receiver &&> (__rcvr));
305+ auto &[__tag, __ign, __child] = __sndr;
306+ return __opstate ( STDEXEC ::__forward_like<_Sender>(__child), std::move (__rcvr));
273307 };
274308 };
275309
@@ -362,3 +396,5 @@ namespace STDEXEC
362396 struct __sexpr_impl <exec::repeat_until_t > : exec::__repeat::__repeat_until_impl
363397 {};
364398} // namespace STDEXEC
399+
400+ STDEXEC_PRAGMA_POP ()
0 commit comments