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
32 changes: 31 additions & 1 deletion include/exec/sequence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,38 @@ namespace experimental::execution {
}
STDEXEC_EXPLICIT_THIS_END(connect)

template <std::size_t Index, class Self>
STDEXEC_ATTRIBUTE(always_inline, host, device)
static constexpr auto&& static_get(Self&& self) noexcept {
if constexpr (Index == 0) {
return static_cast<Self&&>(self)._tag;
} else if constexpr (Index == 1) {
return static_cast<Self&&>(self)._ign;
} else {
return STDEXEC::__get<Index - 2>(static_cast<Self&&>(self)._sndrs);
}
}

template <std::size_t Index>
STDEXEC_ATTRIBUTE(always_inline, host, device)
constexpr auto&& get() && noexcept {
return static_get<Index>(static_cast<_sndr&&>(*this));
}

template <std::size_t Index>
STDEXEC_ATTRIBUTE(always_inline, host, device)
constexpr auto&& get() & noexcept {
return static_get<Index>(*this);
}

template <std::size_t Index>
STDEXEC_ATTRIBUTE(always_inline, host, device)
constexpr auto&& get() const & noexcept {
return static_get<Index>(*this);
}

STDEXEC_ATTRIBUTE(no_unique_address, maybe_unused) sequence_t _tag;
STDEXEC_ATTRIBUTE(no_unique_address, maybe_unused) STDEXEC::__ignore _ignore;
STDEXEC_ATTRIBUTE(no_unique_address, maybe_unused) STDEXEC::__ _ign;
STDEXEC::__tuple<Sender0, Senders...> _sndrs;
};

Expand Down
2 changes: 1 addition & 1 deletion include/stdexec/__detail/__basic_sender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ namespace STDEXEC {
using __env_type_t = __result_of<__sexpr_impl<_Tag>::__get_env, _Index, const _State&>;

template <class _Sexpr>
using __child_indices_t = __desc_of<_Sexpr>::__indices;
using __child_indices_t = STDEXEC::__desc_of_t<_Sexpr>::__indices;

template <class _Receiver, class _Data>
struct __state {
Expand Down
102 changes: 89 additions & 13 deletions include/stdexec/__detail/__sender_introspection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "__execution_fwd.hpp"
#include "__meta.hpp"
#include "__sender_concepts.hpp"
#include "__tuple.hpp"
#include "__type_traits.hpp"

Expand Down Expand Up @@ -50,41 +51,116 @@ namespace STDEXEC {
using __f = __minvoke<_Fn, _Args..., _Tag, _Data, _Child...>;
};

template <class _Ty>
inline constexpr int __structured_binding_size_v = -1;

#if STDEXEC_HAS_BUILTIN(__builtin_structured_binding_size)
template <class _Ty>
requires(__builtin_structured_binding_size(_Ty) >= 0U)
inline constexpr int __structured_binding_size_v<_Ty> = __builtin_structured_binding_size(_Ty);
#else
template <__is_tuple _Ty>
inline constexpr int __structured_binding_size_v<_Ty> = __tuple_size_v<_Ty>;
// For types that are *not* tuples, __structured_binding_size_v must be specialized
// explicitly.
#endif

namespace __detail {
template <class _Tag, class _Data, class... _Child>
auto __get_desc_impl(__tuple<_Tag, _Data, _Child...> &&) -> __desc<_Tag, _Data, _Child...>;

// Can structured bindings introduce a pack?
#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 2024'11L
STDEXEC_PRAGMA_PUSH()
STDEXEC_PRAGMA_IGNORE_GNU("-Wc++26-extensions")

template <class _Sender>
requires (!__is_tuple<_Sender>)
auto __get_desc_impl(_Sender &&__sndr) {
auto &&[__tag, __data, ... __child] = __sndr;
return __desc<decltype(__tag), decltype(__data), decltype(__child)...>{};
}

STDEXEC_PRAGMA_POP()
#else
template <std::size_t _Arity>
extern __undefined<__msize_t<_Arity>>& __get_desc_impl_v;

# define STDEXEC_GET_DESC_IMPL_CHILD(_NY) , __child##_NY
# define STDEXEC_GET_DESC_IMPL_CHILD_TYPE(_NY) , decltype(__child##_NY)
# define STDEXEC_GET_DESC_IMPL_ITERATE(_IDX) \
template <> \
inline constexpr auto __get_desc_impl_v<_IDX> = []<class _Sender>(_Sender &&__sndr) { \
auto &&[__tag, __data STDEXEC_PP_REPEAT(_IDX, STDEXEC_GET_DESC_IMPL_CHILD)] = __sndr; \
return __desc< \
decltype(__tag), \
decltype(__data) STDEXEC_PP_REPEAT(_IDX, STDEXEC_GET_DESC_IMPL_CHILD_TYPE) \
>{}; \
}
STDEXEC_GET_DESC_IMPL_ITERATE(0);
STDEXEC_GET_DESC_IMPL_ITERATE(1);
STDEXEC_GET_DESC_IMPL_ITERATE(2);
STDEXEC_GET_DESC_IMPL_ITERATE(3);
STDEXEC_GET_DESC_IMPL_ITERATE(4);
STDEXEC_GET_DESC_IMPL_ITERATE(5);
STDEXEC_GET_DESC_IMPL_ITERATE(6);
STDEXEC_GET_DESC_IMPL_ITERATE(7);
STDEXEC_GET_DESC_IMPL_ITERATE(8);
STDEXEC_GET_DESC_IMPL_ITERATE(9);
STDEXEC_GET_DESC_IMPL_ITERATE(10);
# undef STDEXEC_GET_DESC_IMPL_CHILD
# undef STDEXEC_GET_DESC_IMPL_CHILD_TYPE
# undef STDEXEC_GET_DESC_IMPL_ITERATE

template <class _Sender>
using __desc_of = STDEXEC_REMOVE_REFERENCE(_Sender)::__desc_t;
requires (!__is_tuple<_Sender>)
auto __get_desc_impl(_Sender &&__sndr) {
using __desc_t = decltype(__get_desc_impl_v<__structured_binding_size_v<_Sender> - 2>(__sndr));
return __desc_t{};
}
#endif

template <class _Sender>
using __desc_of_t = decltype(__detail::__get_desc_impl(__declval<_Sender>()));

template <class _Sender>
using __tag_of = __desc_of<_Sender>::__tag;
extern __undefined<_Sender>& __desc_of_v;

template <class _Sender>
requires __minvocable_q<__tag_of, _Sender>
extern __tag_of<_Sender> __tag_of_v;
requires(__structured_binding_size_v<_Sender> >= 2)
extern __desc_of_t<_Sender> __desc_of_v<_Sender>;

template <auto _Descriptor>
extern decltype(_Descriptor()) __desc_of_v<__sexpr<_Descriptor>>;
} // namespace __detail

template <class _Sender>
using tag_of_t = decltype(__detail::__tag_of_v<_Sender>);
using __desc_of_t = decltype(__detail::__desc_of_v<__decay_t<_Sender>>());

template <class _Sender>
using __data_of = __tuple_element_t<1, _Sender>;
requires enable_sender<__decay_t<_Sender>>
using tag_of_t = __desc_of_t<_Sender>::__tag;

template <class _Sender>
using __data_of = __copy_cvref_t<_Sender, typename __desc_of_t<_Sender>::__data>;

template <class _Sender, class _Continuation = __q<__mlist>>
using __children_of = __mapply<
__mtransform<__copy_cvref_fn<_Sender>, _Continuation>,
typename __detail::__desc_of<_Sender>::__children
typename __desc_of_t<_Sender>::__children
>;

template <std::size_t _Ny, class _Sender>
using __nth_child_of_c = __tuple_element_t<_Ny + 2, _Sender>;

template <class _Ny, class _Sender>
using __nth_child_of = __nth_child_of_c<_Ny::value, _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 = __nth_child_of<__msize_t<_Ny>, _Sender>;

template <class _Sender>
using __child_of = __tuple_element_t<2, _Sender>;
using __child_of = __children_of<_Sender, __qq<__mfront>>;

template <class _Sender>
inline constexpr std::size_t __nbr_children_of = __tuple_size_v<_Sender> - 2;
inline constexpr std::size_t __nbr_children_of = __children_of<_Sender, __msize>::value;

template <auto _Descriptor>
struct __mfor<__sexpr<_Descriptor>> : decltype(_Descriptor()){};
Expand Down
9 changes: 9 additions & 0 deletions include/stdexec/__detail/__tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,15 @@ namespace STDEXEC {
inline constexpr size_t __tuple_size_v = decltype(__detail::__tuple_sizer(
__declval<_Tuple>()))::value;

template <class... _Ts>
inline constexpr size_t __tuple_size_v<__tuple<_Ts...>> = sizeof...(_Ts);

//
// __is_tuple
//
template <class _Ty>
concept __is_tuple = requires(_Ty&& __arg) { __detail::__tuple_sizer(__arg); };

//
// __tuple_element_t
//
Expand Down
Loading