Skip to content

Commit

Permalink
(breaking change) simplification of receiver_adaptor; migrate more …
Browse files Browse the repository at this point in the history
…`get_env` to member functions (#1328)

* (breaking change) simplification of `receiver_adaptor`; migrate more `get_env` to member functions

* avoid recursive template instatiation in `then` example
  • Loading branch information
ericniebler committed May 16, 2024
1 parent 4e573c3 commit c2e37c4
Show file tree
Hide file tree
Showing 24 changed files with 124 additions and 214 deletions.
5 changes: 2 additions & 3 deletions examples/algorithms/retry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,8 @@ struct _retry_sender {
return {static_cast<S&&>(self.s_), static_cast<R&&>(r)};
}

friend auto tag_invoke(stdexec::get_env_t, const _retry_sender& self) //
noexcept(noexcept(stdexec::get_env(self.s_))) -> std::invoke_result_t<stdexec::get_env_t, S> {
return stdexec::get_env(self.s_);
auto get_env() const noexcept -> stdexec::env_of_t<S> {
return stdexec::get_env(s_);
}
};

Expand Down
32 changes: 17 additions & 15 deletions examples/algorithms/then.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ using namespace stdexec::tags;
///////////////////////////////////////////////////////////////////////////////
// then algorithm:
template <class R, class F>
class _then_receiver : stdexec::receiver_adaptor<_then_receiver<R, F>, R> {
friend stdexec::receiver_adaptor<_then_receiver, R>;
F f_;

class _then_receiver : public stdexec::receiver_adaptor<_then_receiver<R, F>, R> {
template <class... As>
using _completions = //
stdexec::completion_signatures<
stdexec::set_value_t(std::invoke_result_t<F, As...>),
stdexec::set_error_t(std::exception_ptr)>;

public:
_then_receiver(R r, F f)
: stdexec::receiver_adaptor<_then_receiver, R>{std::move(r)}
, f_(std::move(f)) {
}

// Customize set_value by invoking the callable and passing the result to the inner receiver
template <class... As>
requires stdexec::receiver_of<R, _completions<As...>>
Expand All @@ -46,11 +49,8 @@ class _then_receiver : stdexec::receiver_adaptor<_then_receiver<R, F>, R> {
}
}

public:
_then_receiver(R r, F f)
: stdexec::receiver_adaptor<_then_receiver, R>{std::move(r)}
, f_(std::move(f)) {
}
private:
F f_;
};

template <stdexec::sender S, class F>
Expand All @@ -67,26 +67,28 @@ struct _then_sender {

template <class Env>
using _completions_t = //
stdexec::make_completion_signatures<
stdexec::transform_completion_signatures_of<
S,
Env,
stdexec::completion_signatures<stdexec::set_error_t(std::exception_ptr)>,
_set_value_t>;

template <class Env>
STDEXEC_MEMFN_DECL(auto get_completion_signatures)(this _then_sender&&, Env) -> _completions_t<Env> {
return {};
STDEXEC_MEMFN_DECL(auto get_completion_signatures)(this _then_sender&&, Env&&) {
return _completions_t<Env>();
}

// Connect:
template <class R>
STDEXEC_MEMFN_DECL(auto connect)(this _then_sender&& self, R r) -> stdexec::connect_result_t<S, _then_receiver<R, F>> {
template <stdexec::same_as<_then_sender> Self, stdexec::receiver R>
requires stdexec::sender_to<S, _then_receiver<R, F>>
STDEXEC_MEMFN_DECL(
auto connect)(this Self&& self, R r) {
return stdexec::connect(
static_cast<S&&>(self.s_),
_then_receiver<R, F>{static_cast<R&&>(r), static_cast<F&&>(self.f_)});
}

auto get_env() const noexcept -> stdexec::env_of_t<S> {
auto get_env() const noexcept -> decltype(auto) {
return stdexec::get_env(s_);
}
};
Expand Down
14 changes: 7 additions & 7 deletions examples/benchmark/static_thread_pool_old.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,18 @@ namespace exec_old {
}
};

friend env tag_invoke(stdexec::get_env_t, const sender& self) noexcept {
return env{self.pool_};
}

friend struct static_thread_pool::scheduler;

explicit sender(static_thread_pool& pool) noexcept
: pool_(pool) {
}

static_thread_pool& pool_;

public:
env get_env() const noexcept {
return env{pool_};
}
};

friend class static_thread_pool;
Expand Down Expand Up @@ -493,9 +494,8 @@ namespace exec_old {
return {};
}

friend auto tag_invoke(stdexec::get_env_t, const bulk_sender& self) noexcept
-> stdexec::env_of_t<const Sender&> {
return stdexec::get_env(self.sndr_);
auto get_env() const noexcept -> stdexec::env_of_t<const Sender&> {
return stdexec::get_env(sndr_);
}
};

Expand Down
6 changes: 2 additions & 4 deletions examples/nvexec/maxwell/snr.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,8 @@ namespace repeat_n_detail {
}
#endif

friend auto tag_invoke(stdexec::get_env_t, const repeat_n_sender_t& s) //
noexcept(stdexec::__nothrow_callable<stdexec::get_env_t, const Sender&>)
-> stdexec::env_of_t<const Sender&> {
return stdexec::get_env(s.sender_);
auto get_env() const noexcept -> stdexec::env_of_t<const Sender&> {
return stdexec::get_env(sender_);
}
};
} // namespace repeat_n_detail
Expand Down
6 changes: 3 additions & 3 deletions examples/scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
using namespace stdexec;
using stdexec::sync_wait;

class noop_receiver : receiver_adaptor<noop_receiver> {
friend receiver_adaptor<noop_receiver>;
struct noop_receiver {
using receiver_concept = receiver_t;

template <class... _As>
void set_value(_As&&...) noexcept {
Expand All @@ -42,7 +42,7 @@ class noop_receiver : receiver_adaptor<noop_receiver> {
}

auto get_env() const & noexcept {
return exec::make_env(exec::with(get_stop_token, stdexec::never_stop_token{}));
return exec::with(get_stop_token, stdexec::never_stop_token{});
}
};

Expand Down
5 changes: 2 additions & 3 deletions include/exec/sequence/any_sequence_of.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,8 @@ namespace exec {
static_cast<__sender_base&&>(__self.__sender_), static_cast<_Rcvr&&>(__rcvr));
}

template <stdexec::same_as<stdexec::get_env_t> _GetEnv, stdexec::__decays_to<__t> _Self>
friend auto tag_invoke(_GetEnv, _Self&& __self) noexcept -> stdexec::env_of_t<__sender_base> {
return stdexec::get_env(__self.__sender_);
auto get_env() const noexcept -> stdexec::env_of_t<__sender_base> {
return stdexec::get_env(__sender_);
}
};

Expand Down
3 changes: 1 addition & 2 deletions include/exec/sequence_senders.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,7 @@ namespace exec {
static constexpr auto __select_impl() noexcept {
using _Domain = __late_domain_of_t<_Sender, env_of_t<_Receiver&>>;
constexpr bool _NothrowTfxSender =
__nothrow_callable<get_env_t, _Receiver&>
&& __nothrow_callable<transform_sender_t, _Domain, _Sender, env_of_t<_Receiver&>>;
__nothrow_callable<transform_sender_t, _Domain, _Sender, env_of_t<_Receiver&>>;
using _TfxSender = __tfx_sndr<_Sender, _Receiver>;
if constexpr (__next_connectable_with_tag_invoke<_TfxSender, _Receiver>) {
using _Result = tag_invoke_result_t<
Expand Down
17 changes: 4 additions & 13 deletions include/nvexec/stream/when_all.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,12 @@ namespace nvexec::STDEXEC_STREAM_DETAIL_NS {
make_terminal_stream_env_t<
exec::make_env_t<env_of_t<Receiver>, exec::with_t<get_stop_token_t, inplace_stop_token>>>;

struct __t
: receiver_adaptor<__t>
, stream_receiver_base {
struct __t : stream_receiver_base {
using receiver_concept = stdexec::receiver_t;
using __id = receiver_t;
using SenderId = nvexec::detail::nth_type<Index, SenderIds...>;
using Completions = completion_sigs<env_of_t<Receiver>, CvrefReceiverId>;

Receiver&& base() && noexcept {
return static_cast<Receiver&&>(op_state_->recvr_);
}

const Receiver& base() const & noexcept {
return op_state_->recvr_;
}

template <class Error>
void _set_error_impl(Error&& err, _when_all::state_t expected) noexcept {
// TODO: _What memory orderings are actually needed here?
Expand Down Expand Up @@ -199,7 +190,7 @@ namespace nvexec::STDEXEC_STREAM_DETAIL_NS {
Env get_env() const noexcept {
auto env = make_terminal_stream_env(
exec::make_env(
stdexec::get_env(base()),
stdexec::get_env(op_state_->recvr_),
__env::__with(op_state_->stop_source_.get_token(), get_stop_token)),
&const_cast<stream_provider_t&>(op_state_->stream_providers_[Index]));

Expand Down Expand Up @@ -321,7 +312,7 @@ namespace nvexec::STDEXEC_STREAM_DETAIL_NS {
decltype(std::get<Is>((static_cast<WhenAll&&>(when_all)).sndrs_)),
stdexec::__t<receiver_t<CvrefReceiverId, Is>>>(
std::get<Is>((static_cast<WhenAll&&>(when_all)).sndrs_),
stdexec::__t<receiver_t<CvrefReceiverId, Is>>{{}, {}, parent_op},
stdexec::__t<receiver_t<CvrefReceiverId, Is>>{{}, parent_op},
context_state);
}}...} {
status_ = STDEXEC_DBG_ERR(cudaMallocManaged(&values_, sizeof(child_values_tuple_t)));
Expand Down
143 changes: 42 additions & 101 deletions include/stdexec/__detail/__receiver_adaptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ namespace stdexec {

struct __receiver : __nope {
using receiver_concept = receiver_t;
};

template <same_as<set_error_t> _Tag>
void tag_invoke(_Tag, __receiver, std::exception_ptr) noexcept;
template <same_as<set_stopped_t> _Tag>
void tag_invoke(_Tag, __receiver) noexcept;
auto tag_invoke(get_env_t, __receiver) noexcept -> empty_env;
void set_error(std::exception_ptr) noexcept;
void set_stopped() noexcept;
auto get_env() const noexcept -> empty_env;
};
} // namespace __no

using __not_a_receiver = __no::__receiver;
Expand Down Expand Up @@ -110,124 +108,67 @@ namespace stdexec {
struct receiver_adaptor
: __adaptor_base<_Base>
, receiver_t {
friend _Derived;
STDEXEC_DEFINE_MEMBER(set_value);
STDEXEC_DEFINE_MEMBER(set_error);
STDEXEC_DEFINE_MEMBER(set_stopped);
STDEXEC_DEFINE_MEMBER(get_env);

static constexpr bool __has_base = !derived_from<_Base, __no::__nope>;

template <class _Dp>
using __base_from_derived_t = decltype(__declval<_Dp>().base());
template <class _Self>
using __base_from_derived_t = decltype(__declval<_Self>().base());

using __get_base_t =
using __get_base_fn =
__if_c<__has_base, __mbind_back_q<__copy_cvref_t, _Base>, __q<__base_from_derived_t>>;

template <class _Dp>
using __base_t = __minvoke<__get_base_t, _Dp&&>;
template <class _Self>
using __base_t = __minvoke<__get_base_fn, _Self&&>;

template <class _Dp>
template <class _Self>
STDEXEC_ATTRIBUTE((host, device))
static auto
__get_base(_Dp&& __self) noexcept -> __base_t<_Dp> {
__get_base(_Self&& __self) noexcept -> __base_t<_Self> {
if constexpr (__has_base) {
return __c_upcast<receiver_adaptor>(static_cast<_Dp&&>(__self)).base();
return __c_upcast<receiver_adaptor>(static_cast<_Self&&>(__self)).base();
} else {
return static_cast<_Dp&&>(__self).base();
return static_cast<_Self&&>(__self).base();
}
}

template <__same_as<set_value_t> _SetValue, class... _As>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend auto
tag_invoke(_SetValue, _Derived&& __self, _As&&... __as) noexcept //
-> __msecond< //
__if_c<__same_as<set_value_t, _SetValue>>,
decltype(STDEXEC_CALL_MEMBER(
set_value,
static_cast<_Derived&&>(__self),
static_cast<_As&&>(__as)...))> {
static_assert(noexcept(STDEXEC_CALL_MEMBER(
set_value, static_cast<_Derived&&>(__self), static_cast<_As&&>(__as)...)));
STDEXEC_CALL_MEMBER(set_value, static_cast<_Derived&&>(__self), static_cast<_As&&>(__as)...);
}

template <__same_as<set_value_t> _SetValue, class _Dp = _Derived, class... _As>
requires STDEXEC_MISSING_MEMBER(_Dp, set_value) && tag_invocable<_SetValue, __base_t<_Dp>, _As...>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend void
tag_invoke(_SetValue, _Derived&& __self, _As&&... __as) noexcept {
stdexec::set_value(__get_base(static_cast<_Dp&&>(__self)), static_cast<_As&&>(__as)...);
}

template <__same_as<set_error_t> _SetError, class _Error>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend auto
tag_invoke(_SetError, _Derived&& __self, _Error&& __err) noexcept //
-> __msecond< //
__if_c<__same_as<set_error_t, _SetError>>,
decltype(STDEXEC_CALL_MEMBER(
set_error,
static_cast<_Derived&&>(__self),
static_cast<_Error&&>(__err)))> {
static_assert(noexcept(STDEXEC_CALL_MEMBER(
set_error, static_cast<_Derived&&>(__self), static_cast<_Error&&>(__err))));
STDEXEC_CALL_MEMBER(
set_error, static_cast<_Derived&&>(__self), static_cast<_Error&&>(__err));
}
public:
using receiver_concept = receiver_t;

template <__same_as<set_error_t> _SetError, class _Error, class _Dp = _Derived>
requires STDEXEC_MISSING_MEMBER(_Dp, set_error) && tag_invocable<_SetError, __base_t<_Dp>, _Error>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend void
tag_invoke(_SetError, _Derived&& __self, _Error&& __err) noexcept {
stdexec::set_error(
__get_base(static_cast<_Derived&&>(__self)), static_cast<_Error&&>(__err));
}
receiver_adaptor() = default;
using __adaptor_base<_Base>::__adaptor_base;

template <__same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend auto
tag_invoke(_SetStopped, _Derived&& __self) noexcept //
-> __msecond< //
__if_c<__same_as<set_stopped_t, _SetStopped>>,
decltype(STDEXEC_CALL_MEMBER(set_stopped, static_cast<_Dp&&>(__self)))> {
static_assert(noexcept(STDEXEC_CALL_MEMBER(set_stopped, static_cast<_Derived&&>(__self))));
STDEXEC_CALL_MEMBER(set_stopped, static_cast<_Derived&&>(__self));
template <class... _As, class _Self = _Derived>
requires __callable<set_value_t, __base_t<_Self>, _As...>
STDEXEC_ATTRIBUTE((host, device))
void
set_value(_As&&... __as) && noexcept {
return stdexec::set_value(
__get_base(static_cast<_Self&&>(*this)), static_cast<_As&&>(__as)...);
}

template <__same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
requires STDEXEC_MISSING_MEMBER(_Dp, set_stopped) && tag_invocable<_SetStopped, __base_t<_Dp>>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend void
tag_invoke(_SetStopped, _Derived&& __self) noexcept {
stdexec::set_stopped(__get_base(static_cast<_Derived&&>(__self)));
template <class _Error, class _Self = _Derived>
requires __callable<set_error_t, __base_t<_Self>, _Error>
STDEXEC_ATTRIBUTE((host, device))
void
set_error(_Error&& __err) && noexcept {
return stdexec::set_error(
__get_base(static_cast<_Self&&>(*this)), static_cast<_Error&&>(__err));
}

// Pass through the get_env receiver query
template <__same_as<get_env_t> _GetEnv, class _Dp = _Derived>
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend auto
tag_invoke(_GetEnv, const _Derived& __self) noexcept
-> decltype(STDEXEC_CALL_MEMBER(get_env, static_cast<const _Dp&>(__self))) {
static_assert(noexcept(STDEXEC_CALL_MEMBER(get_env, __self)));
return STDEXEC_CALL_MEMBER(get_env, __self);
template <class _Self = _Derived>
requires __callable<set_stopped_t, __base_t<_Self>>
STDEXEC_ATTRIBUTE((host, device))
void
set_stopped() && noexcept {
return stdexec::set_stopped(__get_base(static_cast<_Self&&>(*this)));
}

template <__same_as<get_env_t> _GetEnv, class _Dp = _Derived>
requires STDEXEC_MISSING_MEMBER(_Dp, get_env)
STDEXEC_ATTRIBUTE((host, device, always_inline))
friend auto
tag_invoke(_GetEnv, const _Derived& __self) noexcept -> env_of_t<__base_t<const _Dp&>> {
return stdexec::get_env(__get_base(__self));
template <class _Self = _Derived>
STDEXEC_ATTRIBUTE((host, device))
auto
get_env() const noexcept -> env_of_t<__base_t<const _Self&>> {
return stdexec::get_env(__get_base(static_cast<const _Self&>(*this)));
}

public:
receiver_adaptor() = default;
using __adaptor_base<_Base>::__adaptor_base;

using receiver_concept = receiver_t;
};
} // namespace __adaptors

Expand Down
Loading

0 comments on commit c2e37c4

Please sign in to comment.