Skip to content

Commit

Permalink
Merge pull request #1148 from NVIDIA/stopped-as-optional
Browse files Browse the repository at this point in the history
port `stopped_as_optional` to generic sender
  • Loading branch information
ericniebler authored Nov 22, 2023
2 parents 6b9f350 + aef05b4 commit 393a276
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 154 deletions.
103 changes: 53 additions & 50 deletions include/stdexec/__detail/__basic_sender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,33 @@ namespace stdexec {

STDEXEC_PRAGMA_POP()

struct __tie {
template <class _Tag, class _Data, class... _Child>
STDEXEC_ATTRIBUTE((always_inline))
constexpr auto operator()(_Tag, _Data&& __data, _Child&&... __child) const noexcept {
return std::tuple<_Tag, _Data&&, _Child&&...>{{}, (_Data&&) __data, (_Child&&) __child...};
}
};
template <class _Sender>
using __meta_of = __call_result_t<__impl_of<_Sender>, __copy_cvref_fn<_Sender>, __get_meta>;
} // namespace __detail

template <class _Sender>
using __tag_of = typename __detail::__meta_of<_Sender>::__tag;

template <class _Sender>
using __data_of = typename __detail::__meta_of<_Sender>::__data;

template <class _Sender, class _Continuation = __q<__types>>
using __children_of = //
__mapply< _Continuation, typename __detail::__meta_of<_Sender>::__child>;

template <class _Ny, class _Sender>
using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>;

template <std::size_t _Ny, class _Sender>
using __nth_child_of_c = __children_of<_Sender, __mbind_front_q<__m_at, __msize_t<_Ny>>>;

template <class _Sender>
using __child_of = __children_of<_Sender, __q<__mfront>>;

template <class _Sender>
inline constexpr std::size_t __nbr_children_of = __v<__children_of<_Sender, __msize>>;

namespace __detail {
// Note: This is UB. UBSAN allows it for now.
template <class _Parent, class _Child>
_Parent* __parent_from_child(_Child* __child, _Child _Parent::*__mbr_ptr) noexcept {
Expand Down Expand Up @@ -132,6 +151,32 @@ namespace stdexec {
{ &__probe_named_mbrs<_Tag>::complete } -> same_as<__none_such __with_named_mbrs::*>;
};

template <class _Sexpr, class _Receiver>
struct __connect_fn;

struct __default_basis_ops;

template <class _Tag>
using __start_impl = __if_c<__has_start_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag>
using __complete_impl = __if_c<__has_complete_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag>
using __get_state_impl = __if_c<__has_get_state_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag>
using __connect_impl = __if_c<__has_connect_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag, class _Sexpr, class _Receiver>
using __state_type_t =
__decay_t<decltype(__get_state_impl<_Tag>::get_state(__declval<_Sexpr>(), __declval<_Receiver&>()))>;

template <class _Sexpr, class _Receiver>
concept __connectable =
__callable<__impl_of<_Sexpr>, __copy_cvref_fn<_Sexpr>, __connect_fn<_Sexpr, _Receiver>>
&& __mvalid<__state_type_t, __tag_of<_Sexpr>, _Sexpr, _Receiver>;

////////////////////////////////////////////////////////////////////////////
// default behaviors for the sender/receiver/op state basis operations,
// used by __sexpr
Expand Down Expand Up @@ -164,27 +209,12 @@ namespace stdexec {

// By default, return a generic operation state
template <class _Sender, class _Receiver>
requires __detail::__connectable<_Sender, _Receiver>
static auto connect(_Sender&& __sndr, _Receiver __rcvr) -> __op_state<_Sender, _Receiver> {
return __op_state<_Sender, _Receiver>{(_Sender&&) __sndr, (_Receiver&&) __rcvr};
}
};

template <class _Tag>
using __start_impl = __if_c<__has_start_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag>
using __complete_impl = __if_c<__has_complete_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag>
using __get_state_impl = __if_c<__has_get_state_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag>
using __connect_impl = __if_c<__has_connect_member<_Tag>, _Tag, __default_basis_ops>;

template <class _Tag, class _Sexpr, class _Receiver>
using __state_type_t =
__decay_t<decltype(__get_state_impl<_Tag>::get_state(__declval<_Sexpr>(), __declval<_Receiver&>()))>;

template <class _ReceiverId, class _Sexpr, class _Idx>
struct __receiver {
struct __t {
Expand Down Expand Up @@ -558,33 +588,6 @@ namespace stdexec {
template <class _Sender, class _ApplyFn>
using __sexpr_apply_result_t = __call_result_t<__sexpr_apply_t, _Sender, _ApplyFn>;

namespace __detail {
template <class _Sender>
using __meta_of = __call_result_t<__sexpr_apply_t, _Sender, __detail::__get_meta>;
}

template <class _Sender>
using __tag_of = typename __detail::__meta_of<_Sender>::__tag;

template <class _Sender>
using __data_of = typename __detail::__meta_of<_Sender>::__data;

template <class _Sender, class _Continuation = __q<__types>>
using __children_of = //
__mapply< _Continuation, typename __detail::__meta_of<_Sender>::__child>;

template <class _Ny, class _Sender>
using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>;

template <std::size_t _Ny, class _Sender>
using __nth_child_of_c = __children_of<_Sender, __mbind_front_q<__m_at, __msize_t<_Ny>>>;

template <class _Sender>
using __child_of = __children_of<_Sender, __q<__mfront>>;

template <class _Sender>
inline constexpr std::size_t __nbr_children_of = __v<__children_of<_Sender, __msize>>;

template <class _Sender>
concept sender_expr = //
__mvalid<__tag_of, _Sender>;
Expand Down
129 changes: 25 additions & 104 deletions include/stdexec/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,6 @@ namespace stdexec {
};
} // namespace __domain

namespace __write_ {
struct __write_t;
}

struct default_domain {
default_domain() = default;

Expand Down Expand Up @@ -4527,76 +4523,6 @@ namespace stdexec {
// [execution.senders.adaptors.stopped_as_optional]
// [execution.senders.adaptors.stopped_as_error]
namespace __stopped_as_xxx {
template <class _CvrefSenderId, class _ReceiverId>
struct __operation;

template <class _CvrefSenderId, class _ReceiverId>
struct __receiver {
using _Sender = stdexec::__t<_CvrefSenderId>;
using _Receiver = stdexec::__t<_ReceiverId>;

struct __t {
using is_receiver = void;
using __id = __receiver;

template <same_as<set_value_t> _Tag, class _Ty>
friend void tag_invoke(_Tag, __t&& __self, _Ty&& __a) noexcept {
try {
using _Value = __decay_t<__single_sender_value_t<_Sender, env_of_t<_Receiver>>>;
static_assert(constructible_from<_Value, _Ty>);
stdexec::set_value(
(_Receiver&&) __self.__op_->__rcvr_, std::optional<_Value>{(_Ty&&) __a});
} catch (...) {
stdexec::set_error((_Receiver&&) __self.__op_->__rcvr_, std::current_exception());
}
}

template <same_as<set_error_t> _Tag, class _Error>
friend void tag_invoke(_Tag, __t&& __self, _Error&& __error) noexcept {
stdexec::set_error((_Receiver&&) __self.__op_->__rcvr_, (_Error&&) __error);
}

template <same_as<set_stopped_t> _Tag>
friend void tag_invoke(_Tag, __t&& __self) noexcept {
using _Value = __decay_t<__single_sender_value_t<_Sender, env_of_t<_Receiver>>>;
stdexec::set_value(
(_Receiver&&) __self.__op_->__rcvr_, std::optional<_Value>{std::nullopt});
}

template <same_as<get_env_t> _Tag>
friend env_of_t<_Receiver> tag_invoke(_Tag, const __t& __self) noexcept {
return stdexec::get_env(__self.__op_->__rcvr_);
}

stdexec::__t<__operation<_CvrefSenderId, _ReceiverId>>* __op_;
};
};

template <class _CvrefSenderId, class _ReceiverId>
struct __operation {
using _Sender = stdexec::__t<_CvrefSenderId>;
using _Receiver = stdexec::__t<_ReceiverId>;
using __receiver_t = stdexec::__t<__receiver<_CvrefSenderId, _ReceiverId>>;

struct __t {
using __id = __operation;

__t(_Sender&& __sndr, _Receiver&& __rcvr)
: __rcvr_((_Receiver&&) __rcvr)
, __op_state_(connect((_Sender&&) __sndr, __receiver_t{this})) {
}

STDEXEC_IMMOVABLE(__t);

friend void tag_invoke(start_t, __t& __self) noexcept {
start(__self.__op_state_);
}

_Receiver __rcvr_;
connect_result_t<_Sender, __receiver_t> __op_state_;
};
};

struct stopped_as_optional_t : __with_default_get_env<stopped_as_optional_t> {
template <sender _Sender>
auto operator()(_Sender&& __sndr) const {
Expand All @@ -4608,36 +4534,6 @@ namespace stdexec {
return {};
}

#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
private:
template <class...>
friend struct stdexec::__sexpr;
#endif

template <class _CvrefSender, class _Receiver>
using __operation_t =
stdexec::__t<__operation<stdexec::__cvref_id<_CvrefSender>, stdexec::__id<_Receiver>>>;
template <class _CvrefSender, class _Receiver>
using __receiver_t =
stdexec::__t<__receiver<stdexec::__cvref_id<_CvrefSender>, stdexec::__id<_Receiver>>>;

template <class _Receiver>
struct __connect_fn {
_Receiver __rcvr_;

template <class _Child>
__operation_t<_Child, _Receiver> operator()(stopped_as_optional_t, __, _Child&& __child) {
return {(_Child&&) __child, std::move(__rcvr_)};
}
};

template <sender_expr_for<stopped_as_optional_t> _Self, receiver _Receiver>
requires __single_typed_sender<__child_of<_Self>, env_of_t<_Receiver>>
&& sender_to<__child_of<_Self>, __receiver_t<__child_of<_Self>, _Receiver>>
static __operation_t<__child_of<_Self>, _Receiver> connect(_Self&& __self, _Receiver __rcvr) {
return __sexpr_apply((_Self&&) __self, __connect_fn<_Receiver>{(_Receiver&&) __rcvr});
}

template <class... _Tys>
requires(sizeof...(_Tys) == 1)
using __set_value_t = completion_signatures<set_value_t(std::optional<__decay_t<_Tys>>...)>;
Expand All @@ -4655,6 +4551,31 @@ namespace stdexec {
completion_signatures<>> {
return {};
}

template <sender_expr_for<stopped_as_optional_t> _Self, class _Receiver>
requires __single_typed_sender<__child_of<_Self>, env_of_t<_Receiver>>
static auto get_state(_Self&&, _Receiver&) noexcept {
using _Value = __decay_t<__single_sender_value_t<__child_of<_Self>, env_of_t<_Receiver>>>;
return __mtype<_Value>();
}

template <class _State, class _Receiver, __completion_tag _Tag, class... _Args>
static void complete(_State, _Receiver&& __rcvr, _Tag, _Args&&... __args) noexcept {
if constexpr (same_as<_Tag, set_value_t>) {
try {
static_assert(constructible_from<__t<_State>, _Args...>);
stdexec::set_value(
(_Receiver&&) __rcvr, std::optional<__t<_State>>{(_Args&&) __args...});
} catch (...) {
stdexec::set_error((_Receiver&&) __rcvr, std::current_exception());
}
} else if constexpr (same_as<_Tag, set_error_t>) {
stdexec::set_error((_Receiver&&) __rcvr, (_Args&&) __args...);
} else {
stdexec::set_value(
(_Receiver&&) __rcvr, std::optional<__t<_State>>{std::nullopt});
}
}
};

struct stopped_as_error_t {
Expand Down

0 comments on commit 393a276

Please sign in to comment.