Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions include/stdexec/__detail/__affine_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@

namespace STDEXEC
{
struct _CANNOT_MAKE_SENDER_AFFINE_TO_THE_CURRENT_SCHEDULER_
{};
struct _THE_SCHEDULER_IN_THE_CURRENT_EXECUTION_ENVIRONMENT_IS_NOT_INFALLIBLE_
{};
struct _CANNOT_MAKE_SENDER_AFFINE_TO_THE_STARTING_SCHEDULER_;
struct _THE_SCHEDULER_IN_THE_CURRENT_EXECUTION_ENVIRONMENT_IS_NOT_INFALLIBLE_;

namespace __affine_on
{
Expand Down Expand Up @@ -87,18 +85,22 @@ namespace STDEXEC
{
// The environment doesn't have a scheduler, so we can't adapt the sender to be
// affine. Instead, return a type describing the problem.
return __not_a_sender<_WHAT_(_CANNOT_MAKE_SENDER_AFFINE_TO_THE_CURRENT_SCHEDULER_),
_WHY_(_THE_CURRENT_EXECUTION_ENVIRONMENT_DOESNT_HAVE_A_SCHEDULER_),
_WHERE_(_IN_ALGORITHM_, affine_on_t)>{};
return __not_a_sender< //
_WHAT_(_CANNOT_MAKE_SENDER_AFFINE_TO_THE_STARTING_SCHEDULER_),
_WHY_(_THE_CURRENT_EXECUTION_ENVIRONMENT_DOESNT_HAVE_A_SCHEDULER_),
_WHERE_(_IN_ALGORITHM_, affine_on_t),
_WITH_PRETTY_SENDER_<__cv_child_t>,
_WITH_ENVIRONMENT_(_Env)>{};
}
else if constexpr (!__infallible_scheduler<__sched_t, __unstoppable_env_t<_Env>>)
{
// The scheduler in the environment isn't infallible, so we can't adapt the sender to be
// affine. Instead, return a type describing the problem.
return __not_a_sender<
_WHAT_(_CANNOT_MAKE_SENDER_AFFINE_TO_THE_CURRENT_SCHEDULER_),
_WHAT_(_CANNOT_MAKE_SENDER_AFFINE_TO_THE_STARTING_SCHEDULER_),
_WHY_(_THE_SCHEDULER_IN_THE_CURRENT_EXECUTION_ENVIRONMENT_IS_NOT_INFALLIBLE_),
_WHERE_(_IN_ALGORITHM_, affine_on_t),
_WITH_PRETTY_SENDER_<__cv_child_t>,
_WITH_SCHEDULER_(__sched_t)>{};
}
else
Expand Down
88 changes: 30 additions & 58 deletions include/stdexec/__detail/__on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,7 @@ namespace STDEXEC
{
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.on]
namespace __on
{
struct on_t;
struct _CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_
{};

template <class _Sender, class _Env>
struct __no_scheduler_in_environment
{
using sender_concept = sender_t;

template <class>
static consteval auto get_completion_signatures()
{
return STDEXEC::__throw_compile_time_error<
_WHAT_(_CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_),
_WHY_(_THE_CURRENT_EXECUTION_ENVIRONMENT_DOESNT_HAVE_A_SCHEDULER_),
_WHERE_(_IN_ALGORITHM_, on_t),
_WITH_PRETTY_SENDER_<_Sender>,
_WITH_ENVIRONMENT_(_Env)>();
}
};
} // namespace __on
struct _CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_;

////////////////////////////////////////////////////////////////////////////////////////////////
struct on_t
Expand Down Expand Up @@ -84,70 +62,64 @@ namespace STDEXEC
return __closure(*this, static_cast<_Scheduler&&>(__sched), static_cast<_Closure&&>(__clsur));
}

// This transform_sender overload handles the case where `on` was called like
// `on(sch, sndr)`. In this case, we find the old scheduler by looking in the
// receiver's environment.
// This transform_sender overload handles the case where `on` was called like `on(sch,
// sndr)`. In this case, we find the old scheduler by looking in the receiver's
// environment.
template <__decay_copyable _Sender, class _Env>
requires scheduler<__data_of<_Sender>>
STDEXEC_ATTRIBUTE(always_inline)
static auto transform_sender(set_value_t, _Sender&& __sndr, _Env const & __env)
{
auto& [__tag, __sched, __child] = __sndr;
auto __old = __with_default(get_scheduler, __end_sched_t<_Sender, _Env>())(__env);
static_assert(__sender_for<_Sender, on_t>);
auto& [__tag, __new_sched, __child] = __sndr;
auto __old_sched = __with_default(get_scheduler, __end_sched_t<_Sender, _Env>())(__env);

return continues_on(starts_on(STDEXEC::__forward_like<_Sender>(__sched),
return continues_on(starts_on(STDEXEC::__forward_like<_Sender>(__new_sched),
STDEXEC::__forward_like<_Sender>(__child)),
std::move(__old));
std::move(__old_sched));
}

// This transform_sender overload handles the case where `on` was called like
// `sndr | on(sch, clsur)` or `on(sndr, sch, clsur)`. In this case, __child is a
// predecessor sender, so the scheduler we want to restore is the completion
// scheduler of __child.
// This transform_sender overload handles the case where `on` was called like `sndr |
// on(sch, clsur)` or `on(sndr, sch, clsur)`. In this case, __child is a predecessor
// sender, so the scheduler we want to restore is the completion scheduler of __child.
template <__decay_copyable _Sender, class _Env>
requires(!scheduler<__data_of<_Sender>>)
STDEXEC_ATTRIBUTE(always_inline)
static auto transform_sender(set_value_t, _Sender&& __sndr, _Env const & __env)
{
static_assert(__sender_for<_Sender, on_t>);
auto& [__tag, __data, __child] = __sndr;
auto& [__sched, __clsur] = __data;
auto& [__new_sched, __clsur] = __data;

auto __old = __with_default(get_completion_scheduler<set_value_t>,
__end_sched_t<_Sender, _Env>())(get_env(__child), __env);
auto __old_sched = __with_default(get_completion_scheduler<set_value_t>,
__end_sched_t<_Sender, _Env>())(get_env(__child), __env);

auto __pred = __reschedule(STDEXEC::__forward_like<_Sender>(__child), __old, __sched);
return __reschedule(STDEXEC::__forward_like<_Sender>(__clsur)(std::move(__pred)),
std::move(__sched),
std::move(__old));
return continues_on(STDEXEC::__forward_like<_Sender>(__clsur)(
continues_on(STDEXEC::__forward_like<_Sender>(__child),
STDEXEC::__forward_like<_Sender>(__new_sched))),
std::move(__old_sched));
}

template <class _Sender, class _Env>
static auto transform_sender(set_value_t, _Sender&&, _Env const &)
{
return __not_a_sender<_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_, _WITH_PRETTY_SENDER_<_Sender>>{};
return __not_a_sender<_WHAT_(_SENDER_TYPE_IS_NOT_DECAY_COPYABLE_),
_WITH_PRETTY_SENDER_<_Sender>>{};
}

private:
// If __is_root_env<_Env> is true, then this sender has no parent, so there is
// no need to restore the execution context. We can use the inline scheduler
// as the scheduler if __env does not have one.
// If __is_root_env<_Env> is true, then this sender has no parent, so there is no need
// to restore the execution context. We can use the inline scheduler as the scheduler
// if __env does not have one.
template <class _Sender, class _Env>
using __end_sched_t =
__if_c<__is_root_env<_Env>,
inline_scheduler,
__not_a_scheduler<__on::__no_scheduler_in_environment<_Sender, _Env>>>;

template <class _Sender, class _OldSched, class _NewSched>
static constexpr auto __reschedule(_Sender&& __sndr,
[[maybe_unused]] _OldSched&& __old_sched,
_NewSched&& __new_sched)
{
// BUGBUG TODO(ericniebler): FIXME
// return continues_on(
// write_env(static_cast<_Sender&&>(__sndr), __sched_env{__old_sched}),
// static_cast<_NewSched&&>(__new_sched));
return continues_on(static_cast<_Sender&&>(__sndr), static_cast<_NewSched&&>(__new_sched));
}
__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_of<_Sender>>,
_WITH_ENVIRONMENT_(_Env)>>;
};

inline constexpr on_t on{};
Expand Down
Loading