Skip to content

Commit

Permalink
support structured bindings for __sexpr (#1136)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericniebler committed Nov 8, 2023
1 parent e9633ca commit 2e3ba0d
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 37 deletions.
9 changes: 4 additions & 5 deletions examples/nvexec/maxwell/snr.cuh
Expand Up @@ -187,13 +187,13 @@ namespace nvexec::STDEXEC_STREAM_DETAIL_NS { //
namespace repeat_n_detail {

template <class OpT>
class receiver_2_t : public stdexec::__receiver_base {
class receiver_2_t : public stdexec::__receiver_base {
using Sender = typename OpT::PredSender;
using Receiver = typename OpT::Receiver;

OpT& op_state_;

public:
public:
template <stdexec::__one_of<ex::set_error_t, ex::set_stopped_t> _Tag, class... _Args>
friend void tag_invoke(_Tag __tag, receiver_2_t&& __self, _Args&&... __args) noexcept {
OpT& op_state = __self.op_state_;
Expand Down Expand Up @@ -236,7 +236,7 @@ namespace repeat_n_detail {

OpT& op_state_;

public:
public:
template <stdexec::__one_of<ex::set_error_t, ex::set_stopped_t> _Tag, class... _Args>
friend void tag_invoke(_Tag __tag, receiver_1_t&& __self, _Args&&... __args) noexcept {
OpT& op_state = __self.op_state_;
Expand All @@ -252,8 +252,7 @@ namespace repeat_n_detail {
auto sch = stdexec::get_scheduler(stdexec::get_env(op_state.rcvr_));
inner_op_state_t& inner_op_state = op_state.inner_op_state_.emplace(
stdexec::__conv{[&]() noexcept {
return ex::connect(
ex::schedule(sch) | op_state.closure_, receiver_2_t<OpT>{op_state});
return ex::connect(ex::schedule(sch) | op_state.closure_, receiver_2_t<OpT>{op_state});
}});

ex::start(inner_op_state);
Expand Down
79 changes: 74 additions & 5 deletions include/stdexec/__detail/__basic_sender.hpp
Expand Up @@ -22,6 +22,8 @@

#include "../concepts.hpp"

#include <utility> // for tuple_size/tuple_element

namespace stdexec {
/////////////////////////////////////////////////////////////////////////////
// Generic __sender type
Expand Down Expand Up @@ -51,6 +53,32 @@ namespace stdexec {
return nullptr;
}
};

STDEXEC_PRAGMA_PUSH()
STDEXEC_PRAGMA_IGNORE_GNU("-Wunused-local-typedef")

struct __get_meta {
template <class _Tag, class _Data, class... _Children>
constexpr auto operator()(_Tag, _Data&&, _Children&&...) const noexcept {
struct __meta {
using __tag = _Tag;
using __data = _Data;
using __children = __types<_Children...>;
};

return __meta{};
}
};

STDEXEC_PRAGMA_POP()

struct __tie {
template <class _Tag, class _Data, class... _Children>
constexpr auto operator()(_Tag, _Data&& __data, _Children&&... __children) const noexcept {
return std::tuple<_Tag, _Data&&, _Children&&...>{
{}, (_Data&&) __data, (_Children&&) __children...};
}
};
} // namespace __detail

//////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -66,7 +94,11 @@ namespace stdexec {
using is_sender = void;
using __t = __sexpr;
using __id = __sexpr;
using __tag_t = __call_result_t<_ImplFn, __cp, __detail::__get_tag>;
using __meta_t = __call_result_t<_ImplFn, __cp, __detail::__get_meta>;
using __tag_t = typename __meta_t::__tag;
using __data_t = typename __meta_t::__data;
using __children_t = typename __meta_t::__children;
using __arity_t = __mapply<__msize, __children_t>;

STDEXEC_ATTRIBUTE((always_inline)) //
static __tag_t __tag() noexcept {
Expand Down Expand Up @@ -121,6 +153,19 @@ namespace stdexec {
-> __call_result_t<__detail::__impl_of<_Sender>, __copy_cvref_fn<_Sender>, _ApplyFn> { //
return ((_Sender&&) __sndr).__impl_(__copy_cvref_fn<_Sender>(), (_ApplyFn&&) __fun); //
}

template <std::size_t _Idx, __decays_to_derived_from<__sexpr> _Self>
STDEXEC_ATTRIBUTE((always_inline))
friend decltype(auto) get(_Self&& __self) noexcept
requires(_Idx < (__v<__arity_t> + 2))
{
if constexpr (_Idx == 0) {
return __tag_t();
} else {
return __self.__impl_(__copy_cvref_fn<_Self>(), __nth_pack_element<_Idx>);
}
STDEXEC_UNREACHABLE();
}
};

template <class _ImplFn>
Expand Down Expand Up @@ -245,15 +290,20 @@ 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 = __call_result_t<__sexpr_apply_t, _Sender, __detail::__get_tag>;
using __tag_of = typename __detail::__meta_of<_Sender>::__tag;

template <class _Sender>
using __data_of = __call_result_t<__sexpr_apply_t, _Sender, __detail::__get_data>;
using __data_of = typename __detail::__meta_of<_Sender>::__data;

template <class _Sender, class _Continuation = __q<__types>>
using __children_of = __t<__call_result_t<
__call_result_t<__sexpr_apply_t, _Sender, __detail::__get_children<_Continuation>>>>;
using __children_of = //
__mapply< _Continuation, typename __detail::__meta_of<_Sender>::__children>;

template <class _Ny, class _Sender>
using __nth_child_of = __children_of<_Sender, __mbind_front_q<__m_at, _Ny>>;
Expand Down Expand Up @@ -317,8 +367,27 @@ namespace stdexec {
template <__has_id _Sender>
requires(!same_as<__id<_Sender>, _Sender>)
extern __id_name __name_of_v<_Sender>;

template <class _Ty>
_Ty __remove_rvalue_reference_fn(_Ty&&);

template <class _Ty>
using __remove_rvalue_reference_t =
decltype(__detail::__remove_rvalue_reference_fn(__declval<_Ty>()));
} // namespace __detail

template <class _Sender>
using __name_of = __detail::__name_of<_Sender>;
} // namespace stdexec

namespace std {
template <class _Impl>
struct tuple_size<stdexec::__sexpr<_Impl>>
: integral_constant< size_t, stdexec::__v<typename stdexec::__sexpr<_Impl>::__arity_t> + 2> { };

template <size_t _Idx, class _Impl>
struct tuple_element<_Idx, stdexec::__sexpr<_Impl>> {
using type = stdexec::__detail::__remove_rvalue_reference_t<
stdexec::__call_result_t<_Impl, stdexec::__cp, stdexec::__nth_pack_element_t<_Idx>>>;
};
}
56 changes: 34 additions & 22 deletions include/stdexec/__detail/__meta.hpp
Expand Up @@ -943,42 +943,53 @@ namespace stdexec {
template <template <class...> class _Cp, class _Noexcept = __mbool<true>>
using __mconstructor_for = __mcompose<__q<__mconstruct>, __q<_Cp>>;

template <std::size_t>
using __ignore_t = __ignore;

#if STDEXEC_MSVC()
// MSVCBUG https://developercommunity.visualstudio.com/t/Incorrect-function-template-argument-sub/10437827

template <std::size_t>
struct __msvc_ignore_t {
__msvc_ignore_t() = default;
struct __ignore_t {
__ignore_t() = default;

constexpr __msvc_ignore_t(auto&&...) noexcept {
constexpr __ignore_t(auto&&...) noexcept {
}
};

template <std::size_t... _Is, class _Ty, class... _Us>
_Ty&& __nth_pack_element_(__msvc_ignore_t<_Is>..., _Ty&& __t, _Us&&...) noexcept {
return (_Ty&&) __t;
}
#else
template <std::size_t... _Is, class _Ty, class... _Us>
_Ty&& __nth_pack_element_(__ignore_t<_Is>..., _Ty&& __t, _Us&&...) noexcept {
return (_Ty&&) __t;
}
template <std::size_t>
using __ignore_t = __ignore;
#endif

template <std::size_t _Np, class... _Ts>
constexpr decltype(auto) __nth_pack_element(_Ts&&... __ts) noexcept {
static_assert(_Np < sizeof...(_Ts));
return [&]<std::size_t... _Is>(__indices<_Is...>) noexcept -> decltype(auto) {
return stdexec::__nth_pack_element_<_Is...>((_Ts&&) __ts...);
}(__make_indices<_Np>());
}
template <class... _Ignore>
struct __nth_pack_element_impl {
template <class _Ty, class... _Us>
STDEXEC_ATTRIBUTE((always_inline)) //
constexpr _Ty&& operator()(_Ignore..., _Ty&& __t, _Us&&...) const noexcept {
return (decltype(__t)&&) __t;
}
};

template <std::size_t _Np>
struct __nth_pack_element_t {
template <std::size_t... _Is>
STDEXEC_ATTRIBUTE((always_inline)) //
static constexpr auto __impl(__indices<_Is...>) noexcept {
return __nth_pack_element_impl<__ignore_t<_Is>...>();
}

template <class... _Ts>
STDEXEC_ATTRIBUTE((always_inline)) //
constexpr decltype(auto) operator()(_Ts&&... __ts) const noexcept {
static_assert(_Np < sizeof...(_Ts));
return __impl(__make_indices<_Np>())((_Ts&&) __ts...);
}
};

template <std::size_t _Np>
inline constexpr __nth_pack_element_t<_Np> __nth_pack_element{};

template <auto... _Vs>
struct __mliterals {
template <std::size_t _Np>
STDEXEC_ATTRIBUTE((always_inline)) //
static constexpr auto __nth() noexcept {
return stdexec::__nth_pack_element<_Np>(_Vs...);
}
Expand All @@ -987,6 +998,7 @@ namespace stdexec {
template <std::size_t _Np>
struct __nth_member {
template <class _Ty>
STDEXEC_ATTRIBUTE((always_inline)) //
constexpr decltype(auto) operator()(_Ty&& __ty) const noexcept {
return ((_Ty&&) __ty).*(__ty.__mbrs_.template __nth<_Np>());
}
Expand Down
13 changes: 8 additions & 5 deletions include/stdexec/execution.hpp
Expand Up @@ -63,6 +63,9 @@ namespace stdexec {
struct default_domain;
struct dependent_domain;

template <class _Sender>
using tag_of_t = __tag_of<_Sender>;

namespace __domain {
template <class _Tag>
using __legacy_c11n_for = typename _Tag::__legacy_customizations_t;
Expand Down Expand Up @@ -93,7 +96,7 @@ namespace stdexec {
template <class _Sender, class... _Env>
concept __has_default_transform_sender = //
sender_expr<_Sender> //
&& __has_transform_sender<__tag_of<_Sender>, _Sender, _Env...>;
&& __has_transform_sender<tag_of_t<_Sender>, _Sender, _Env...>;

template <class _Type, class _Sender, class _Env>
concept __has_transform_env = requires(_Type __obj, _Sender&& __sender, _Env&& __env) {
Expand All @@ -103,7 +106,7 @@ namespace stdexec {
template <class _Sender, class _Env>
concept __has_default_transform_env = //
sender_expr<_Sender> //
&& __has_transform_env<__tag_of<_Sender>, _Sender, _Env>;
&& __has_transform_env<tag_of_t<_Sender>, _Sender, _Env>;

template <class _DomainOrTag, class... _Args>
concept __has_apply_sender = requires(_DomainOrTag __tag, _Args&&... __args) {
Expand All @@ -126,7 +129,7 @@ namespace stdexec {
if constexpr (__callable<__sexpr_apply_t, _Sender, __domain::__legacy_customization>) {
return stdexec::__sexpr_apply((_Sender&&) __sndr, __domain::__legacy_customization());
} else if constexpr (__domain::__has_default_transform_sender<_Sender>) {
return __tag_of<_Sender>().transform_sender((_Sender&&) __sndr);
return tag_of_t<_Sender>().transform_sender((_Sender&&) __sndr);
} else {
return static_cast<_Sender>((_Sender&&) __sndr);
}
Expand All @@ -138,7 +141,7 @@ namespace stdexec {
STDEXEC_ATTRIBUTE((always_inline))
decltype(auto) transform_sender(_Sender&& __sndr, const _Env& __env) const {
if constexpr (__domain::__has_default_transform_sender<_Sender, _Env>) {
return __tag_of<_Sender>().transform_sender((_Sender&&) __sndr, __env);
return tag_of_t<_Sender>().transform_sender((_Sender&&) __sndr, __env);
} else {
return static_cast<_Sender>((_Sender&&) __sndr);
}
Expand All @@ -163,7 +166,7 @@ namespace stdexec {
template <class _Sender, class _Env>
decltype(auto) transform_env(_Sender&& __sndr, _Env&& __env) const noexcept {
if constexpr (__domain::__has_default_transform_env<_Sender, _Env>) {
return __tag_of<_Sender>().transform_env((_Sender&&) __sndr, (_Env&&) __env);
return tag_of_t<_Sender>().transform_env((_Sender&&) __sndr, (_Env&&) __env);
} else {
return static_cast<_Env>((_Env&&) __env);
}
Expand Down

0 comments on commit 2e3ba0d

Please sign in to comment.