stdexec: update to latest commit
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I14eba410c2d60e3bf90e25c28e9dfad547241927
diff --git a/include/sdbusplus/async/stdexec/__detail/__basic_sender.hpp b/include/sdbusplus/async/stdexec/__detail/__basic_sender.hpp
index e582f3d..70a02ec 100644
--- a/include/sdbusplus/async/stdexec/__detail/__basic_sender.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__basic_sender.hpp
@@ -16,8 +16,10 @@
#pragma once
#include "../concepts.hpp"
+#include "__env.hpp"
#include "__execution_fwd.hpp"
#include "__meta.hpp"
+#include "__tuple.hpp"
#include "__type_traits.hpp"
#include <utility> // for tuple_size/tuple_element
@@ -34,6 +36,7 @@
struct __get_tag
{
template <class _Tag, class... _Rest>
+ STDEXEC_ATTRIBUTE((always_inline))
_Tag operator()(_Tag, _Rest&&...) const noexcept
{
return {};
@@ -43,6 +46,7 @@
struct __get_data
{
template <class _Data, class... _Rest>
+ STDEXEC_ATTRIBUTE((always_inline))
_Data&& operator()(__ignore, _Data&& __data, _Rest&&...) const noexcept
{
return (_Data&&)__data;
@@ -52,47 +56,443 @@
template <class _Continuation>
struct __get_children
{
- template <class... _Children>
- auto operator()(__ignore, __ignore, _Children&&...) const noexcept
- -> __mtype<__minvoke<_Continuation, _Children...>> (*)()
+ template <class... _Child>
+ STDEXEC_ATTRIBUTE((always_inline))
+ auto operator()(__ignore, __ignore, _Child&&...) const noexcept
+ -> __mtype<__minvoke<_Continuation, _Child...>> (*)()
{
return nullptr;
}
};
-STDEXEC_PRAGMA_PUSH()
-STDEXEC_PRAGMA_IGNORE_GNU("-Wunused-local-typedefs")
-
-struct __get_meta
+template <class _Tag, class _Data, class... _Child>
+struct __desc
{
- 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...>;
- };
+ using __tag = _Tag;
+ using __data = _Data;
+ using __children = __types<_Child...>;
+};
- return __meta{};
+template <class _Fn>
+struct __sexpr_uncurry_fn
+{
+ template <class _Tag, class _Data, class... _Child>
+ requires __minvocable<_Fn, _Tag, _Data, _Child...>
+ constexpr auto operator()(_Tag, _Data&&, _Child&&...) const noexcept
+ -> __minvoke<_Fn, _Tag, _Data, _Child...>;
+};
+
+template <class _Sender, class _Fn>
+using __sexpr_uncurry =
+ __call_result_t<__impl_of<_Sender>, __copy_cvref_fn<_Sender>,
+ __sexpr_uncurry_fn<_Fn>>;
+
+template <class _Sender>
+using __desc_of = __sexpr_uncurry<_Sender, __q<__desc>>;
+
+using __get_desc = __sexpr_uncurry_fn<__q<__desc>>;
+
+template <class _Sender>
+extern __q<__midentity> __name_of_v;
+
+template <class _Sender>
+using __name_of_fn = decltype(__name_of_v<_Sender>);
+
+template <class _Sender>
+using __name_of = __minvoke<__name_of_fn<_Sender>, _Sender>;
+} // namespace __detail
+
+template <class _Sender>
+using tag_of_t = typename __detail::__desc_of<_Sender>::__tag;
+
+template <class _Sender>
+using __data_of = typename __detail::__desc_of<_Sender>::__data;
+
+template <class _Sender, class _Continuation = __q<__types>>
+using __children_of = //
+ __mapply<_Continuation, typename __detail::__desc_of<_Sender>::__children>;
+
+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 _Fn, class _Tp>
+ requires __mvalid<tag_of_t, _Tp> &&
+ __mvalid<__detail::__sexpr_uncurry, _Tp, _Fn>
+struct __uncurry_<_Fn, _Tp>
+{
+ using __t = __detail::__sexpr_uncurry<_Tp, _Fn>;
+};
+
+template <class _Tag>
+struct __sexpr_impl;
+
+template <class _Sender>
+using __name_of = __detail::__name_of<_Sender>;
+
+namespace __detail
+{
+template <class _Sexpr, class _Receiver>
+struct __op_state;
+
+template <class _Sexpr, class _Receiver>
+struct __connect_fn;
+
+template <class _Tag, class _Sexpr, class _Receiver>
+using __state_type_t =
+ __decay_t<__result_of<__sexpr_impl<_Tag>::get_state, _Sexpr, _Receiver&>>;
+
+template <class _Tag, class _Index, class _Sexpr, class _Receiver>
+using __env_type_t =
+ __result_of<__sexpr_impl<_Tag>::get_env, _Index,
+ __state_type_t<_Tag, _Sexpr, _Receiver>&, _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_t<_Sexpr>, _Sexpr, _Receiver>;
+
+// 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
+{
+ alignas(_Parent) char __buf[sizeof(_Parent)];
+ _Parent* __parent = (_Parent*)&__buf;
+ const std::ptrdiff_t __offset = (char*)&(__parent->*__mbr_ptr) - __buf;
+ return (_Parent*)((char*)__child - __offset);
+}
+
+inline constexpr auto __get_attrs = //
+ [](__ignore, const auto&... __child) noexcept -> decltype(auto) {
+ if constexpr (sizeof...(__child) == 1)
+ {
+ return stdexec::get_env(
+ __child...); // BUGBUG: should be only the forwarding queries
+ }
+ else
+ {
+ return empty_env();
+ }
+ STDEXEC_UNREACHABLE();
+};
+
+inline constexpr auto __get_env = //
+ []<class _Receiver>(__ignore, __ignore, const _Receiver& __rcvr) noexcept
+ -> env_of_t<const _Receiver&> { return stdexec::get_env(__rcvr); };
+
+inline constexpr auto __get_state = //
+ []<class _Sender>(_Sender&& __sndr, __ignore) noexcept -> decltype(auto) {
+ return STDEXEC_CALL_EXPLICIT_THIS_MEMFN((_Sender&&)__sndr,
+ apply)(__get_data());
+};
+
+inline constexpr auto __connect = //
+ []<class _Sender, class _Receiver>(
+ _Sender&& __sndr, _Receiver __rcvr) -> __op_state<_Sender, _Receiver>
+ requires __connectable<_Sender, _Receiver>
+{
+ return __op_state<_Sender, _Receiver>{(_Sender&&)__sndr,
+ (_Receiver&&)__rcvr};
+};
+
+inline constexpr auto __start = //
+ []<class _StartTag = start_t, class... _ChildOps>(
+ __ignore, __ignore, _ChildOps&... __ops) noexcept
+{
+ (_StartTag()(__ops), ...);
+};
+
+inline constexpr auto __complete = //
+ []<class _Index, class _Receiver, class _SetTag, class... _Args>(
+ _Index, __ignore, _Receiver& __rcvr, _SetTag,
+ _Args&&... __args) noexcept {
+ static_assert(__v<_Index> == 0,
+ "I don't know how to complete this operation.");
+ _SetTag()(std::move(__rcvr), (_Args&&)__args...);
+};
+
+inline constexpr auto __get_completion_signagures = //
+ [](__ignore, __ignore) noexcept { return void(); };
+
+template <class _ReceiverId, class _Sexpr, class _Idx>
+struct __receiver
+{
+ struct __t
+ {
+ using receiver_concept = receiver_t;
+ using _Receiver = stdexec::__t<_ReceiverId>;
+ using __sexpr = _Sexpr;
+ using __index = _Idx;
+ using __id = __receiver;
+ using __parent_op_t = __op_state<_Sexpr, _Receiver>;
+ using __tag_t = tag_of_t<_Sexpr>;
+
+ // A pointer to the parent operation state, which contains the one
+ // created with this receiver.
+ __parent_op_t* __op_;
+
+ template <class _ChildSexpr, class _ChildReceiver>
+ static __t __from_op_state(
+ __op_state<_ChildSexpr, _ChildReceiver>* __child) noexcept
+ {
+ using __parent_op_t = __op_state<_Sexpr, _Receiver>;
+ std::ptrdiff_t __offset =
+ __parent_op_t::template __get_child_op_offset<__v<_Idx>>();
+ __parent_op_t* __parent =
+ (__parent_op_t*)((char*)__child - __offset);
+ return __t{__parent};
+ }
+
+ template <__completion_tag _Tag, class... _Args>
+ STDEXEC_ATTRIBUTE((always_inline))
+ friend void tag_invoke(_Tag, __t&& __self, _Args&&... __args) noexcept
+ {
+ __self.__op_->__complete(_Idx(), _Tag(), (_Args&&)__args...);
+ }
+
+ template <same_as<get_env_t> _Tag, class _SexprTag = __tag_t>
+ STDEXEC_ATTRIBUTE((always_inline))
+ friend auto tag_invoke(_Tag, const __t& __self) noexcept
+ -> __env_type_t<_SexprTag, _Idx, _Sexpr, _Receiver>
+ {
+ return __self.__op_->__get_env(_Idx());
+ }
+ };
+};
+
+template <class _Receiver>
+using __sexpr_connected_with =
+ __mapply<__mbind_front_q<__m_at, typename _Receiver::__index>,
+ typename __call_result_t<__impl_of<typename _Receiver::__sexpr>,
+ __cp, __get_desc>::__children>;
+
+template <class _Sexpr, class _Receiver>
+struct __op_base : __immovable
+{
+ using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
+ using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
+
+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Receiver __rcvr_;
+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
+
+ __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr) :
+ __rcvr_((_Receiver&&)__rcvr),
+ __state_(__sexpr_impl<__tag_t>::get_state((_Sexpr&&)__sndr, __rcvr_))
+ {}
+
+ _Receiver& __rcvr() noexcept
+ {
+ return __rcvr_;
+ }
+
+ const _Receiver& __rcvr() const noexcept
+ {
+ return __rcvr_;
+ }
+};
+
+// template <class _Sexpr, class _Receiver>
+// requires __is_instance_of<__id<_Receiver>, __receiver>
+// && __decays_to<_Sexpr, __sexpr_connected_with<_Receiver>>
+// struct __op_base<_Sexpr, _Receiver> : __immovable {
+// using __tag_t = typename __decay_t<_Sexpr>::__tag_t;
+// using __state_t = __state_type_t<__tag_t, _Sexpr, _Receiver>;
+
+// STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS __state_t __state_;
+
+// __op_base(_Sexpr&& __sndr, _Receiver&& __rcvr)
+// : __state_(__sexpr_impl<__tag_t>::get_state((_Sexpr&&) __sndr, __rcvr)) {
+// STDEXEC_ASSERT(this->__rcvr().__op_ == __rcvr.__op_);
+// }
+
+// _Receiver __rcvr() const noexcept {
+// return _Receiver::__from_op_state( //
+// static_cast<__op_state<_Sexpr, _Receiver>*>( //
+// const_cast<__op_base*>(this)));
+// }
+// };
+
+STDEXEC_PRAGMA_PUSH()
+STDEXEC_PRAGMA_IGNORE_GNU("-Winvalid-offsetof")
+STDEXEC_PRAGMA_IGNORE_EDG(offset_in_non_POD_nonstandard)
+
+template <class _Sexpr, class _Receiver>
+struct __enable_receiver_from_this
+{
+ using __op_base_t = __op_base<_Sexpr, _Receiver>;
+
+ decltype(auto) __receiver() noexcept
+ {
+ using __derived_t = decltype(__op_base_t::__state_);
+ __derived_t* __derived = static_cast<__derived_t*>(this);
+ constexpr std::size_t __offset = offsetof(__op_base_t, __state_);
+ __op_base_t* __base = (__op_base_t*)((char*)__derived - __offset);
+ return __base->__rcvr();
+ }
+
+ decltype(auto) __receiver() const noexcept
+ {
+ using __derived_t = decltype(__op_base_t::__state_);
+ const __derived_t* __derived = static_cast<const __derived_t*>(this);
+ constexpr std::size_t __offset = offsetof(__op_base_t, __state_);
+ const __op_base_t* __base =
+ (const __op_base_t*)((const char*)__derived - __offset);
+ return __base->__rcvr();
}
};
STDEXEC_PRAGMA_POP()
-struct __tie
+STDEXEC_PRAGMA_PUSH()
+STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
+
+template <class _Sexpr, class _Receiver>
+struct __connect_fn
{
- template <class _Tag, class _Data, class... _Children>
- constexpr auto operator()(_Tag, _Data&& __data,
- _Children&&... __children) const noexcept
+ template <std::size_t _Idx>
+ using __receiver_t =
+ __t<__receiver<__id<_Receiver>, _Sexpr, __mconstant<_Idx>>>;
+
+ __op_state<_Sexpr, _Receiver>* __op_;
+
+ struct __impl
{
- return std::tuple<_Tag, _Data&&, _Children&&...>{
- {}, (_Data&&)__data, (_Children&&)__children...};
+ __op_state<_Sexpr, _Receiver>* __op_;
+
+ template <std::size_t... _Is, class _Tag, class _Data, class... _Child>
+ auto operator()(__indices<_Is...>, _Tag, _Data&&,
+ _Child&&... __child) const
+ -> __tup::__tuple<__indices<_Is...>,
+ connect_result_t<_Child, __receiver_t<_Is>>...>
+ {
+ return __tuple{
+ connect((_Child&&)__child, __receiver_t<_Is>{__op_})...};
+ }
+ };
+
+ template <class _Tag, class _Data, class... _Child>
+ auto operator()(_Tag, _Data&& __data, _Child&&... __child) const
+ -> __call_result_t<__impl, __indices_for<_Child...>, _Tag, _Data,
+ _Child...>
+ {
+ return __impl{__op_}(__indices_for<_Child...>(), _Tag(),
+ (_Data&&)__data, (_Child&&)__child...);
}
};
+STDEXEC_PRAGMA_POP()
+
+template <class _Sexpr, class _Receiver>
+struct __op_state : __op_base<_Sexpr, _Receiver>
+{
+ using __desc_t = typename __decay_t<_Sexpr>::__desc_t;
+ using __tag_t = typename __desc_t::__tag;
+ using __data_t = typename __desc_t::__data;
+ using __children_t = typename __desc_t::__children;
+ using __state_t = typename __op_state::__state_t;
+ using __connect_t = __connect_fn<_Sexpr, _Receiver>;
+
+ static auto __connect(__op_state* __self, _Sexpr&& __sexpr)
+ -> __result_of<__sexpr_apply, _Sexpr, __connect_t>
+ {
+ return __sexpr_apply((_Sexpr&&)__sexpr, __connect_t{__self});
+ }
+
+ using __inner_ops_t =
+ decltype(__op_state::__connect(nullptr, __declval<_Sexpr>()));
+ __inner_ops_t __inner_ops_;
+
+ template <std::size_t _Idx>
+ static std::ptrdiff_t __get_child_op_offset() noexcept
+ {
+ __op_state* __self = (__op_state*)&__self;
+ return (std::ptrdiff_t)(
+ (char*)&__tup::__get<_Idx>(__self->__inner_ops_) - (char*)__self);
+ }
+
+ __op_state(_Sexpr&& __sexpr, _Receiver __rcvr) :
+ __op_state::__op_base{(_Sexpr&&)__sexpr, (_Receiver&&)__rcvr},
+ __inner_ops_(__op_state::__connect(this, (_Sexpr&&)__sexpr))
+ {}
+
+ template <same_as<start_t> _Tag2>
+ STDEXEC_ATTRIBUTE((always_inline))
+ friend void tag_invoke(_Tag2, __op_state& __self) noexcept
+ {
+ using __tag_t = typename __op_state::__tag_t;
+ auto&& __rcvr = __self.__rcvr();
+ __tup::__apply(
+ [&](auto&... __ops) noexcept {
+ __sexpr_impl<__tag_t>::start(__self.__state_, __rcvr, __ops...);
+ },
+ __self.__inner_ops_);
+ }
+
+ template <class _Index, class _Tag2, class... _Args>
+ STDEXEC_ATTRIBUTE((always_inline))
+ void __complete(_Index, _Tag2, _Args&&... __args) noexcept
+ {
+ using __tag_t = typename __op_state::__tag_t;
+ auto&& __rcvr = this->__rcvr();
+ __sexpr_impl<__tag_t>::complete(_Index(), this->__state_, __rcvr,
+ _Tag2(), (_Args&&)__args...);
+ }
+
+ template <class _Index>
+ STDEXEC_ATTRIBUTE((always_inline)) //
+ auto __get_env(_Index) noexcept
+ -> __env_type_t<__tag_t, _Index, _Sexpr, _Receiver>
+ {
+ const auto& __rcvr = this->__rcvr();
+ return __sexpr_impl<__tag_t>::get_env(_Index(), this->__state_, __rcvr);
+ }
+};
+
+inline constexpr auto __drop_front = //
+ []<class _Fn>(_Fn __fn) noexcept {
+ return
+ [__fn = std::move(__fn)]<class... _Rest>(
+ auto&&, _Rest&&... __rest) noexcept(__nothrow_callable<const _Fn&,
+ _Rest...>)
+ -> __call_result_t<const _Fn&, _Rest...> {
+ return __fn((_Rest&&)__rest...);
+ };
+};
} // namespace __detail
+struct __sexpr_defaults
+{
+ static constexpr auto get_attrs = __detail::__get_attrs;
+ static constexpr auto get_env = __detail::__get_env;
+ static constexpr auto get_state = __detail::__get_state;
+ static constexpr auto connect = __detail::__connect;
+ static constexpr auto start = __detail::__start;
+ static constexpr auto complete = __detail::__complete;
+ static constexpr auto get_completion_signagures =
+ __detail::__get_completion_signagures;
+};
+
+template <class Tag>
+struct __sexpr_impl : __sexpr_defaults
+{};
+
+using __detail::__enable_receiver_from_this;
+
+template <class _Tag>
+using __get_attrs_fn = __result_of<__detail::__drop_front,
+ __mtypeof<__sexpr_impl<_Tag>::get_attrs>>;
+
//////////////////////////////////////////////////////////////////////////////////////////////////
// __sexpr
template <class...>
@@ -105,15 +505,18 @@
template <class _ImplFn>
struct __sexpr<_ImplFn>
{
- using is_sender = void;
+ using sender_concept = sender_t;
using __t = __sexpr;
using __id = __sexpr;
- 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 __desc_t = __call_result_t<_ImplFn, __cp, __detail::__get_desc>;
+ using __tag_t = typename __desc_t::__tag;
+ using __data_t = typename __desc_t::__data;
+ using __children_t = typename __desc_t::__children;
using __arity_t = __mapply<__msize, __children_t>;
+ template <class _Tag>
+ using __impl = __sexpr_impl<__meval<__msecond, _Tag, __tag_t>>;
+
STDEXEC_ATTRIBUTE((always_inline)) //
static __tag_t __tag() noexcept
{
@@ -126,22 +529,24 @@
explicit __sexpr(_ImplFn __impl) : __impl_((_ImplFn&&)__impl) {}
template <same_as<get_env_t> _Tag, same_as<__sexpr> _Self>
- STDEXEC_ATTRIBUTE((always_inline)) //
- friend auto tag_invoke(_Tag, const _Self& __self) noexcept //
- -> __msecond<__if_c<same_as<_Tag, get_env_t>>, //
- decltype(__self.__tag().get_env(__self))>
+ STDEXEC_ATTRIBUTE((always_inline)) //
+ friend auto tag_invoke(_Tag, const _Self& __self) noexcept //
+ -> __msecond<
+ __if_c<same_as<_Tag, get_env_t> && same_as<_Self, __sexpr>>, //
+ __result_of<__sexpr_apply, const _Self&, __get_attrs_fn<__tag_t>>>
{
- static_assert(noexcept(__self.__tag().get_env(__self)));
- return __tag_t::get_env(__self);
+ return __sexpr_apply(__self,
+ __detail::__drop_front(__impl<_Tag>::get_attrs));
}
template <same_as<get_completion_signatures_t> _Tag,
__decays_to<__sexpr> _Self, class _Env>
- STDEXEC_ATTRIBUTE((always_inline)) //
- friend auto tag_invoke(_Tag, _Self&& __self, _Env&& __env) //
- -> __msecond<__if_c<same_as<_Tag, get_completion_signatures_t>>,
- decltype(__self.__tag().get_completion_signatures(
- (_Self&&)__self, (_Env&&)__env))>
+ STDEXEC_ATTRIBUTE((always_inline)) //
+ friend auto tag_invoke(_Tag, _Self&& __self, _Env&& __env) noexcept //
+ -> __msecond<
+ __if_c<same_as<_Tag, get_completion_signatures_t> &&
+ __decays_to<_Self, __sexpr>>,
+ __result_of<__impl<_Tag>::get_completion_signatures, _Self, _Env>>
{
return {};
}
@@ -149,15 +554,15 @@
// BUGBUG fix receiver constraint here:
template <same_as<connect_t> _Tag, __decays_to<__sexpr> _Self,
/*receiver*/ class _Receiver>
- STDEXEC_ATTRIBUTE((always_inline)) //
- friend auto tag_invoke(_Tag, _Self&& __self, _Receiver&& __rcvr) //
- noexcept(noexcept(__self.__tag().connect((_Self&&)__self,
- (_Receiver&&)__rcvr))) //
- -> __msecond<__if_c<same_as<_Tag, connect_t>>,
- decltype(__self.__tag().connect((_Self&&)__self,
- (_Receiver&&)__rcvr))>
+ STDEXEC_ATTRIBUTE((always_inline)) //
+ friend auto tag_invoke(_Tag, _Self&& __self, _Receiver&& __rcvr) //
+ noexcept(noexcept(__impl<_Tag>::connect((_Self&&)__self,
+ (_Receiver&&)__rcvr))) //
+ -> __msecond<
+ __if_c<same_as<_Tag, connect_t> && __decays_to<_Self, __sexpr>>,
+ __result_of<__impl<_Tag>::connect, _Self, _Receiver>>
{
- return __tag_t::connect((_Self&&)__self, (_Receiver&&)__rcvr);
+ return __impl<_Tag>::connect((_Self&&)__self, (_Receiver&&)__rcvr);
}
template <class _Sender, class _ApplyFn>
@@ -202,8 +607,8 @@
template <class _Tag>
struct __make_sexpr_t
{
- template <class _Data = __, class... _Children>
- constexpr auto operator()(_Data __data = {}, _Children... __children) const;
+ template <class _Data = __, class... _Child>
+ constexpr auto operator()(_Data __data = {}, _Child... __child) const;
};
#if STDEXEC_NVHPC() || (STDEXEC_GCC() && __GNUC__ < 13)
@@ -266,12 +671,12 @@
} // anonymous namespace
template <class _Tag>
-template <class _Data, class... _Children>
+template <class _Data, class... _Child>
constexpr auto __make_sexpr_t<_Tag>::operator()(_Data __data,
- _Children... __children) const
+ _Child... __child) const
{
return __sexpr{__make_tuple(_Tag(), __detail::__mbc(__data),
- __detail::__mbc(__children)...)};
+ __detail::__mbc(__child)...)};
}
#else
// Anonymous namespace here is to avoid symbol name collisions with the
@@ -295,12 +700,11 @@
} // anonymous namespace
template <class _Tag>
-template <class _Data, class... _Children>
+template <class _Data, class... _Child>
constexpr auto __make_sexpr_t<_Tag>::operator()(_Data __data,
- _Children... __children) const
+ _Child... __child) const
{
- return __sexpr{
- __make_tuple(_Tag(), (_Data&&)__data, (_Children&&)__children...)};
+ return __sexpr{__make_tuple(_Tag(), (_Data&&)__data, (_Child&&)__child...)};
};
#endif
@@ -310,8 +714,8 @@
using __detail::__make_sexpr;
-template <class _Tag, class _Data, class... _Children>
-using __sexpr_t = __result_of<__make_sexpr<_Tag>, _Data, _Children...>;
+template <class _Tag, class _Data, class... _Child>
+using __sexpr_t = __result_of<__make_sexpr<_Tag>, _Data, _Child...>;
namespace __detail
{
@@ -338,67 +742,27 @@
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>::__children>;
-
-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>;
+ __mvalid<tag_of_t, _Sender>;
template <class _Sender, class _Tag>
concept sender_expr_for = //
- sender_expr<_Sender> && same_as<__tag_of<_Sender>, _Tag>;
+ sender_expr<_Sender> && same_as<tag_of_t<_Sender>, _Tag>;
// The __name_of utility defined below is used to pretty-print the type names of
// senders in compiler diagnostics.
namespace __detail
{
-template <class _Sender>
-extern __q<__midentity> __name_of_v;
-
-template <class _Sender>
-using __name_of_fn = decltype(__name_of_v<_Sender>);
-
-template <class _Sender>
-using __name_of = __minvoke<__name_of_fn<_Sender>, _Sender>;
-
struct __basic_sender_name
{
template <class _Sender>
using __f = //
__call_result_t<__sexpr_apply_result_t<_Sender, __basic_sender_name>>;
- template <class _Tag, class _Data, class... _Children>
- auto operator()(_Tag, _Data&&, _Children&&...) const //
- -> __sexpr<_Tag, _Data, __name_of<_Children>...> (*)();
+ template <class _Tag, class _Data, class... _Child>
+ auto operator()(_Tag, _Data&&, _Child&&...) const //
+ -> __sexpr<_Tag, _Data, __name_of<_Child>...> (*)();
};
struct __id_name
@@ -430,9 +794,6 @@
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
diff --git a/include/sdbusplus/async/stdexec/__detail/__config.hpp b/include/sdbusplus/async/stdexec/__detail/__config.hpp
index 7cfd3dc..d63c894 100644
--- a/include/sdbusplus/async/stdexec/__detail/__config.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__config.hpp
@@ -161,11 +161,19 @@
#define STDEXEC_ATTR_WHICH_0(_ATTR) [[_ATTR]]
// custom handling for specific attribute types
-#define STDEXEC_ATTR_WHICH_1(_ATTR) STDEXEC_CUDA(__host__)
+#ifdef __CUDACC__
+#define STDEXEC_ATTR_WHICH_1(_ATTR) __host__
+#else
+#define STDEXEC_ATTR_WHICH_1(_ATTR)
+#endif
#define STDEXEC_ATTR_host STDEXEC_PROBE(~, 1)
#define STDEXEC_ATTR___host__ STDEXEC_PROBE(~, 1)
-#define STDEXEC_ATTR_WHICH_2(_ATTR) STDEXEC_CUDA(__device__)
+#ifdef __CUDACC__
+#define STDEXEC_ATTR_WHICH_2(_ATTR) __device__
+#else
+#define STDEXEC_ATTR_WHICH_2(_ATTR)
+#endif
#define STDEXEC_ATTR_device STDEXEC_PROBE(~, 2)
#define STDEXEC_ATTR___device__ STDEXEC_PROBE(~, 2)
diff --git a/include/sdbusplus/async/stdexec/__detail/__domain.hpp b/include/sdbusplus/async/stdexec/__detail/__domain.hpp
new file mode 100644
index 0000000..07a7d25
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/__detail/__domain.hpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2021-2022 NVIDIA Corporation
+ *
+ * Licensed under the Apache License Version 2.0 with LLVM Exceptions
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://llvm.org/LICENSE.txt
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "../functional.hpp"
+#include "__basic_sender.hpp"
+#include "__env.hpp"
+#include "__execution_fwd.hpp"
+#include "__meta.hpp"
+
+namespace stdexec
+{
+
+struct default_domain;
+struct dependent_domain;
+
+namespace __domain
+{
+template <class _Tag>
+using __legacy_c11n_for = typename _Tag::__legacy_customizations_t;
+
+template <class _Tag, class... _Args>
+using __legacy_c11n_fn = //
+ __make_dispatcher<__legacy_c11n_for<_Tag>, __none_such, _Args...>;
+
+template <class _Tag, class... _Args>
+concept __has_legacy_c11n = //
+ __callable<__legacy_c11n_fn<_Tag, _Args...>, _Args...>;
+
+struct __legacy_customization
+{
+ template <class _Tag, class _Data, class... _Children>
+ requires __has_legacy_c11n<_Tag, _Data, _Children...>
+ decltype(auto) operator()(_Tag, _Data && __data,
+ _Children&&... __children) const
+ {
+ return __legacy_c11n_fn<_Tag, _Data, _Children...>()(
+ static_cast<_Data&&>(__data),
+ static_cast<_Children&&>(__children)...);
+ }
+};
+
+template <class _DomainOrTag, class _Sender, class... _Env>
+concept __has_transform_sender =
+ requires(_DomainOrTag __tag, _Sender&& __sender, const _Env&... __env) {
+ __tag.transform_sender((_Sender&&)__sender, __env...);
+ };
+
+template <class _Sender, class... _Env>
+concept __has_default_transform_sender = //
+ sender_expr<_Sender> //
+ && __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) {
+ __obj.transform_env((_Sender&&)__sender, (_Env&&)__env);
+ };
+
+template <class _Sender, class _Env>
+concept __has_default_transform_env = //
+ sender_expr<_Sender> //
+ && __has_transform_env<tag_of_t<_Sender>, _Sender, _Env>;
+
+template <class _DomainOrTag, class... _Args>
+concept __has_apply_sender = requires(_DomainOrTag __tag, _Args&&... __args) {
+ __tag.apply_sender((_Args&&)__args...);
+ };
+} // namespace __domain
+
+struct default_domain
+{
+ default_domain() = default;
+
+ // Called without the environment during eager customization
+ template <class _Sender>
+ STDEXEC_ATTRIBUTE((always_inline))
+ decltype(auto) transform_sender(_Sender&& __sndr) const
+ {
+ // Look for a legacy customization for the given tag, and if found,
+ // apply it.
+ 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_t<_Sender>().transform_sender((_Sender&&)__sndr);
+ }
+ else
+ {
+ return static_cast<_Sender>((_Sender&&)__sndr);
+ }
+ STDEXEC_UNREACHABLE();
+ }
+
+ // Called with an environment during lazy customization
+ template <class _Sender, class _Env>
+ 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_t<_Sender>().transform_sender((_Sender&&)__sndr,
+ __env);
+ }
+ else
+ {
+ return static_cast<_Sender>((_Sender&&)__sndr);
+ }
+ STDEXEC_UNREACHABLE();
+ }
+
+ template <class _Tag, class _Sender, class... _Args>
+ requires __domain::__has_legacy_c11n<_Tag, _Sender, _Args...> ||
+ __domain::__has_apply_sender<_Tag, _Sender, _Args...>
+ STDEXEC_ATTRIBUTE((always_inline)) decltype(auto)
+ apply_sender(_Tag, _Sender&& __sndr, _Args&&... __args) const
+ {
+ // Look for a legacy customization for the given tag, and if found,
+ // apply it.
+ if constexpr (__domain::__has_legacy_c11n<_Tag, _Sender, _Args...>)
+ {
+ return __domain::__legacy_c11n_fn<_Tag, _Sender, _Args...>()(
+ static_cast<_Sender&&>(__sndr),
+ static_cast<_Args&&>(__args)...);
+ }
+ else
+ {
+ return _Tag().apply_sender((_Sender&&)__sndr, (_Args&&)__args...);
+ }
+ STDEXEC_UNREACHABLE();
+ }
+
+ 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_t<_Sender>().transform_env((_Sender&&)__sndr,
+ (_Env&&)__env);
+ }
+ else
+ {
+ return static_cast<_Env>((_Env&&)__env);
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////
+namespace __detail
+{
+template <class _Env, class _Tag>
+using __completion_scheduler_for =
+ __meval_or<__call_result_t, __none_such, get_completion_scheduler_t<_Tag>,
+ _Env>;
+
+template <class _Env, class _Tag>
+using __completion_domain_for =
+ __meval_or<__call_result_t, __none_such, get_domain_t,
+ __completion_scheduler_for<_Env, _Tag>>;
+
+// Check the value, error, and stopped channels for completion schedulers.
+// Of the completion schedulers that are known, they must all have compatible
+// domains. This computes that domain, or else returns __none_such if there
+// are no completion schedulers or if they don't specify a domain.
+template <class _Env>
+struct __completion_domain_or_none_ :
+ __mdefer_<__transform<
+ __mbind_front_q<__completion_domain_for, _Env>,
+ __remove<__none_such, __munique<__msingle_or<__none_such>>>>,
+ set_value_t, set_error_t, set_stopped_t>
+{};
+
+template <class _Sender>
+using __completion_domain_or_none =
+ __t<__completion_domain_or_none_<env_of_t<_Sender>>>;
+
+template <class _Sender>
+concept __consistent_completion_domains =
+ __mvalid<__completion_domain_or_none, _Sender>;
+
+template <class _Sender>
+concept __has_completion_domain =
+ (!same_as<__completion_domain_or_none<_Sender>, __none_such>);
+
+template <__has_completion_domain _Sender>
+using __completion_domain_of = __completion_domain_or_none<_Sender>;
+} // namespace __detail
+
+/////////////////////////////////////////////////////////////////////////////
+inline constexpr struct __get_early_domain_t
+{
+ template <class _Sender, class _Default = default_domain>
+ auto operator()(const _Sender&, _Default __def = {}) const noexcept
+ {
+ if constexpr (__callable<get_domain_t, env_of_t<_Sender>>)
+ {
+ return __call_result_t<get_domain_t, env_of_t<_Sender>>();
+ }
+ else if constexpr (__detail::__has_completion_domain<_Sender>)
+ {
+ return __detail::__completion_domain_of<_Sender>();
+ }
+ else
+ {
+ return __def;
+ }
+ STDEXEC_UNREACHABLE();
+ }
+} __get_early_domain{};
+
+template <class _Sender, class _Default = default_domain>
+using __early_domain_of_t =
+ __call_result_t<__get_early_domain_t, _Sender, _Default>;
+
+/////////////////////////////////////////////////////////////////////////////
+inline constexpr struct __get_late_domain_t
+{
+ // When connect is looking for a customization, it first checks the sender's
+ // domain. If the sender knows the domain in which it completes, then that
+ // is where the subsequent task will execute. Otherwise, look to the
+ // receiver for late-bound information about the current execution context.
+ template <class _Sender, class _Env>
+ auto operator()(const _Sender& __sndr, const _Env& __env) const noexcept
+ {
+ if constexpr (!same_as<dependent_domain,
+ __early_domain_of_t<_Sender, dependent_domain>>)
+ {
+ return __get_early_domain(__sndr);
+ }
+ else if constexpr (__callable<get_domain_t, const _Env&>)
+ {
+ return get_domain(__env);
+ }
+ else if constexpr (__callable<__composed<get_domain_t, get_scheduler_t>,
+ const _Env&>)
+ {
+ return get_domain(get_scheduler(__env));
+ }
+ else
+ {
+ return default_domain();
+ }
+ STDEXEC_UNREACHABLE();
+ }
+
+ // The transfer algorithm is the exception to the rule. It ignores the
+ // domain of the predecessor, and dispatches based on the domain of the
+ // scheduler to which execution is being transferred.
+ template <sender_expr_for<transfer_t> _Sender, class _Env>
+ auto operator()(const _Sender& __sndr, const _Env&) const noexcept
+ {
+ return __sexpr_apply(__sndr,
+ [](__ignore, auto& __data, __ignore) noexcept {
+ auto __sched = get_completion_scheduler<set_value_t>(__data);
+ return query_or(get_domain, __sched, default_domain());
+ });
+ }
+} __get_late_domain{};
+
+template <class _Sender, class _Env>
+using __late_domain_of_t = __call_result_t<__get_late_domain_t, _Sender, _Env>;
+
+namespace __domain
+{
+struct __common_domain_fn
+{
+ static default_domain __common_domain() noexcept
+ {
+ return {};
+ }
+
+ template <class _Domain, class... _OtherDomains>
+ requires __all_of<_Domain, _OtherDomains...>
+ static _Domain __common_domain(_Domain __domain, _OtherDomains...) noexcept
+ {
+ return (_Domain&&)__domain;
+ }
+
+ template <class... _Domains>
+ static auto __common_domain(_Domains...) noexcept //
+ -> __if_c<__one_of<dependent_domain, _Domains...>, dependent_domain,
+ __none_such>
+ {
+ return {};
+ }
+
+ auto operator()(__ignore, __ignore, const auto&... __sndrs) const noexcept
+ {
+ return __common_domain(__get_early_domain(__sndrs)...);
+ }
+};
+
+template <class... _Senders>
+using __common_domain_t = //
+ __call_result_t<__common_domain_fn, int, int, _Senders...>;
+
+template <class... _Senders>
+concept __has_common_domain = //
+ __none_of<__none_such, __common_domain_t<_Senders...>>;
+} // namespace __domain
+} // namespace stdexec
diff --git a/include/sdbusplus/async/stdexec/__detail/__env.hpp b/include/sdbusplus/async/stdexec/__detail/__env.hpp
new file mode 100644
index 0000000..8d16b3b
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/__detail/__env.hpp
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2021-2023 NVIDIA Corporation
+ *
+ * Licensed under the Apache License Version 2.0 with LLVM Exceptions
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://llvm.org/LICENSE.txt
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "../functional.hpp"
+#include "../stop_token.hpp"
+#include "__concepts.hpp"
+#include "__execution_fwd.hpp"
+
+#include <concepts>
+
+STDEXEC_PRAGMA_PUSH()
+STDEXEC_PRAGMA_IGNORE_EDG(probable_guiding_friend)
+STDEXEC_PRAGMA_IGNORE_EDG(type_qualifiers_ignored_on_reference)
+
+namespace stdexec
+{
+// [exec.queries.queryable]
+template <class T>
+concept queryable = destructible<T>;
+
+template <class Tag>
+struct __query
+{
+ template <class Sig>
+ static inline constexpr Tag (*signature)(Sig) = nullptr;
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// [exec.queries]
+namespace __queries
+{
+struct forwarding_query_t
+{
+ template <class _Query>
+ constexpr bool operator()(_Query __query) const noexcept
+ {
+ if constexpr (tag_invocable<forwarding_query_t, _Query>)
+ {
+ return tag_invoke(*this, (_Query&&)__query);
+ }
+ else if constexpr (std::derived_from<_Query, forwarding_query_t>)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+};
+
+struct query_or_t
+{
+ template <class _Query, class _Queryable, class _Default>
+ constexpr auto operator()(_Query, _Queryable&&, _Default&& __default) const
+ noexcept(__nothrow_constructible_from<_Default, _Default&&>) -> _Default
+ {
+ return (_Default&&)__default;
+ }
+
+ template <class _Query, class _Queryable, class _Default>
+ requires __callable<_Query, _Queryable>
+ constexpr auto operator()(_Query __query, _Queryable&& __queryable,
+ _Default&&) const
+ noexcept(__nothrow_callable<_Query, _Queryable>)
+ -> __call_result_t<_Query, _Queryable>
+ {
+ return ((_Query&&)__query)((_Queryable&&)__queryable);
+ }
+};
+
+struct execute_may_block_caller_t : __query<execute_may_block_caller_t>
+{
+ template <class _Tp>
+ requires tag_invocable<execute_may_block_caller_t, __cref_t<_Tp>>
+ constexpr bool operator()(_Tp&& __t) const noexcept
+ {
+ static_assert(
+ same_as<bool, tag_invoke_result_t<execute_may_block_caller_t,
+ __cref_t<_Tp>>>);
+ static_assert(
+ nothrow_tag_invocable<execute_may_block_caller_t, __cref_t<_Tp>>);
+ return tag_invoke(execute_may_block_caller_t{}, std::as_const(__t));
+ }
+
+ constexpr bool operator()(auto&&) const noexcept
+ {
+ return true;
+ }
+};
+
+struct get_forward_progress_guarantee_t :
+ __query<get_forward_progress_guarantee_t>
+{
+ template <class _Tp>
+ requires tag_invocable<get_forward_progress_guarantee_t, __cref_t<_Tp>>
+ constexpr auto operator()(_Tp&& __t) const noexcept(
+ nothrow_tag_invocable<get_forward_progress_guarantee_t, __cref_t<_Tp>>)
+ -> tag_invoke_result_t<get_forward_progress_guarantee_t, __cref_t<_Tp>>
+ {
+ return tag_invoke(get_forward_progress_guarantee_t{},
+ std::as_const(__t));
+ }
+
+ constexpr stdexec::forward_progress_guarantee
+ operator()(auto&&) const noexcept
+ {
+ return stdexec::forward_progress_guarantee::weakly_parallel;
+ }
+};
+
+struct __has_algorithm_customizations_t :
+ __query<__has_algorithm_customizations_t>
+{
+ template <class _Tp>
+ using __result_t =
+ tag_invoke_result_t<__has_algorithm_customizations_t, __cref_t<_Tp>>;
+
+ template <class _Tp>
+ requires tag_invocable<__has_algorithm_customizations_t, __cref_t<_Tp>>
+ constexpr __result_t<_Tp> operator()(_Tp&&) const
+ noexcept(noexcept(__result_t<_Tp>{}))
+ {
+ using _Boolean = tag_invoke_result_t<__has_algorithm_customizations_t,
+ __cref_t<_Tp>>;
+ static_assert(_Boolean{}
+ ? true
+ : true); // must be contextually convertible to bool
+ return _Boolean{};
+ }
+
+ constexpr std::false_type operator()(auto&&) const noexcept
+ {
+ return {};
+ }
+};
+
+// TODO: implement allocator concept
+template <class _T0>
+concept __allocator_c = true;
+
+struct get_scheduler_t : __query<get_scheduler_t>
+{
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const get_scheduler_t&) noexcept
+ {
+ return true;
+ }
+
+ template <class _Env>
+ requires tag_invocable<get_scheduler_t, const _Env&>
+ auto operator()(const _Env& __env) const noexcept
+ -> tag_invoke_result_t<get_scheduler_t, const _Env&>;
+
+ auto operator()() const noexcept;
+};
+
+struct get_delegatee_scheduler_t : __query<get_delegatee_scheduler_t>
+{
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const get_delegatee_scheduler_t&) noexcept
+ {
+ return true;
+ }
+
+ template <class _Env>
+ requires tag_invocable<get_delegatee_scheduler_t, const _Env&>
+ auto operator()(const _Env& __t) const noexcept
+ -> tag_invoke_result_t<get_delegatee_scheduler_t, const _Env&>;
+
+ auto operator()() const noexcept;
+};
+
+struct get_allocator_t : __query<get_allocator_t>
+{
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const get_allocator_t&) noexcept
+ {
+ return true;
+ }
+
+ template <class _Env>
+ requires tag_invocable<get_allocator_t, const _Env&>
+ auto operator()(const _Env& __env) const noexcept
+ -> tag_invoke_result_t<get_allocator_t, const _Env&>
+ {
+ static_assert(nothrow_tag_invocable<get_allocator_t, const _Env&>);
+ static_assert(
+ __allocator_c<tag_invoke_result_t<get_allocator_t, const _Env&>>);
+ return tag_invoke(get_allocator_t{}, __env);
+ }
+
+ auto operator()() const noexcept;
+};
+
+struct get_stop_token_t : __query<get_stop_token_t>
+{
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const get_stop_token_t&) noexcept
+ {
+ return true;
+ }
+
+ template <class _Env>
+ never_stop_token operator()(const _Env&) const noexcept
+ {
+ return {};
+ }
+
+ template <class _Env>
+ requires tag_invocable<get_stop_token_t, const _Env&>
+ auto operator()(const _Env& __env) const noexcept
+ -> tag_invoke_result_t<get_stop_token_t, const _Env&>
+ {
+ static_assert(nothrow_tag_invocable<get_stop_token_t, const _Env&>);
+ static_assert(stoppable_token<
+ tag_invoke_result_t<get_stop_token_t, const _Env&>>);
+ return tag_invoke(get_stop_token_t{}, __env);
+ }
+
+ auto operator()() const noexcept;
+};
+
+template <class _Queryable, class _CPO>
+concept __has_completion_scheduler_for =
+ queryable<_Queryable> && //
+ tag_invocable<get_completion_scheduler_t<_CPO>, const _Queryable&>;
+
+template <__completion_tag _CPO>
+struct get_completion_scheduler_t : __query<get_completion_scheduler_t<_CPO>>
+{
+ friend constexpr bool
+ tag_invoke(forwarding_query_t,
+ const get_completion_scheduler_t<_CPO>&) noexcept
+ {
+ return true;
+ }
+
+ template <__has_completion_scheduler_for<_CPO> _Queryable>
+ auto operator()(const _Queryable& __queryable) const noexcept
+ -> tag_invoke_result_t<get_completion_scheduler_t<_CPO>,
+ const _Queryable&>;
+};
+
+struct get_domain_t
+{
+ template <class _Ty>
+ requires tag_invocable<get_domain_t, const _Ty&>
+ constexpr auto operator()(const _Ty& __ty) const noexcept
+ -> tag_invoke_result_t<get_domain_t, const _Ty&>
+ {
+ static_assert(nothrow_tag_invocable<get_domain_t, const _Ty&>,
+ "Customizations of get_domain must be noexcept.");
+ static_assert(__class<tag_invoke_result_t<get_domain_t, const _Ty&>>,
+ "Customizations of get_domain must return a class type.");
+ return tag_invoke(get_domain_t{}, __ty);
+ }
+
+ friend constexpr bool tag_invoke(forwarding_query_t, get_domain_t) noexcept
+ {
+ return true;
+ }
+};
+} // namespace __queries
+
+using __queries::__has_algorithm_customizations_t;
+using __queries::execute_may_block_caller_t;
+using __queries::forwarding_query_t;
+using __queries::get_allocator_t;
+using __queries::get_completion_scheduler_t;
+using __queries::get_delegatee_scheduler_t;
+using __queries::get_domain_t;
+using __queries::get_forward_progress_guarantee_t;
+using __queries::get_scheduler_t;
+using __queries::get_stop_token_t;
+using __queries::query_or_t;
+
+inline constexpr forwarding_query_t forwarding_query{};
+inline constexpr query_or_t query_or{}; // NOT TO SPEC
+inline constexpr execute_may_block_caller_t execute_may_block_caller{};
+inline constexpr __has_algorithm_customizations_t
+ __has_algorithm_customizations{};
+inline constexpr get_forward_progress_guarantee_t
+ get_forward_progress_guarantee{};
+inline constexpr get_scheduler_t get_scheduler{};
+inline constexpr get_delegatee_scheduler_t get_delegatee_scheduler{};
+inline constexpr get_allocator_t get_allocator{};
+inline constexpr get_stop_token_t get_stop_token{};
+#if !STDEXEC_GCC() || defined(__OPTIMIZE_SIZE__)
+template <__completion_tag _CPO>
+inline constexpr get_completion_scheduler_t<_CPO> get_completion_scheduler{};
+#else
+template <>
+inline constexpr get_completion_scheduler_t<set_value_t>
+ get_completion_scheduler<set_value_t>{};
+template <>
+inline constexpr get_completion_scheduler_t<set_error_t>
+ get_completion_scheduler<set_error_t>{};
+template <>
+inline constexpr get_completion_scheduler_t<set_stopped_t>
+ get_completion_scheduler<set_stopped_t>{};
+#endif
+
+template <class _Tag>
+concept __forwarding_query = forwarding_query(_Tag{});
+
+inline constexpr get_domain_t get_domain{};
+
+template <class _Tag, class _Queryable, class _Default>
+using __query_result_or_t =
+ __call_result_t<query_or_t, _Tag, _Queryable, _Default>;
+
+/////////////////////////////////////////////////////////////////////////////
+// env_of
+namespace __env
+{
+template <class _Descriptor>
+struct __prop;
+
+template <class _Value, class... _Tags>
+struct __prop<_Value(_Tags...)>
+{
+ using __t = __prop;
+ using __id = __prop;
+ _Value __value_;
+
+ template <__one_of<_Tags...> _Key>
+ friend auto tag_invoke(_Key, const __prop& __self) //
+ noexcept(__nothrow_decay_copyable<_Value>) -> _Value
+ {
+ return __self.__value_;
+ }
+};
+
+template <class... _Tags>
+struct __prop<void(_Tags...)>
+{
+ using __t = __prop;
+ using __id = __prop;
+
+ template <__one_of<_Tags...> _Key, class _Self>
+ requires(std::is_base_of_v<__prop, __decay_t<_Self>>)
+ friend auto tag_invoke(_Key, _Self&&) noexcept = delete;
+};
+
+struct __mkprop_t
+{
+ template <class _Value, class _Tag, class... _Tags>
+ auto operator()(_Value&& __value, _Tag, _Tags...) const
+ noexcept(__nothrow_decay_copyable<_Value>)
+ -> __prop<__decay_t<_Value>(_Tag, _Tags...)>
+ {
+ return {(_Value&&)__value};
+ }
+
+ template <class _Tag>
+ auto operator()(_Tag) const -> __prop<void(_Tag)>
+ {
+ return {};
+ }
+};
+
+template <__nothrow_move_constructible _Fun>
+struct __env_fn
+{
+ using __t = __env_fn;
+ using __id = __env_fn;
+ STDEXEC_ATTRIBUTE((no_unique_address)) _Fun __fun_;
+
+ template <class _Tag>
+ requires __callable<const _Fun&, _Tag>
+ friend auto tag_invoke(_Tag, const __env_fn& __self) //
+ noexcept(__nothrow_callable<const _Fun&, _Tag>)
+ -> __call_result_t<const _Fun&, _Tag>
+ {
+ return __self.__fun_(_Tag());
+ }
+};
+
+template <class _Fun>
+__env_fn(_Fun) -> __env_fn<_Fun>;
+
+template <class _Env>
+struct __env_fwd
+{
+ static_assert(__nothrow_move_constructible<_Env>);
+ using __t = __env_fwd;
+ using __id = __env_fwd;
+ STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
+
+ template <__forwarding_query _Tag>
+ requires tag_invocable<_Tag, const _Env&>
+ friend auto tag_invoke(_Tag, const __env_fwd& __self) //
+ noexcept(nothrow_tag_invocable<_Tag, const _Env&>)
+ -> tag_invoke_result_t<_Tag, const _Env&>
+ {
+ return _Tag()(__self.__env_);
+ }
+};
+
+template <class _Env>
+__env_fwd(_Env&&) -> __env_fwd<_Env>;
+
+template <class _Env, class _Base = empty_env>
+struct __joined_env : __env_fwd<_Base>
+{
+ static_assert(__nothrow_move_constructible<_Env>);
+ using __t = __joined_env;
+ using __id = __joined_env;
+ STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
+
+ const _Base& base() const noexcept
+ {
+ return this->__env_fwd<_Base>::__env_;
+ }
+
+ template <class _Tag>
+ requires tag_invocable<_Tag, const _Env&>
+ friend auto tag_invoke(_Tag, const __joined_env& __self) //
+ noexcept(nothrow_tag_invocable<_Tag, const _Env&>)
+ -> tag_invoke_result_t<_Tag, const _Env&>
+ {
+ return _Tag()(__self.__env_);
+ }
+};
+
+template <class _Tag, class _Base>
+struct __joined_env<__prop<void(_Tag)>, _Base> : __env_fwd<_Base>
+{
+ using __t = __joined_env;
+ using __id = __joined_env;
+ STDEXEC_ATTRIBUTE((no_unique_address)) __prop<void(_Tag)> __env_;
+
+ friend void tag_invoke(_Tag, const __joined_env&) noexcept = delete;
+};
+
+struct __join_env_t
+{
+ template <class _Env>
+ _Env operator()(_Env&& __env) const noexcept
+ {
+ return (_Env&&)__env;
+ }
+
+ template <class _Env, class _Base>
+ decltype(auto) operator()(_Env && __env, _Base && __base) const noexcept
+ {
+ using __env_t = __decay_t<_Env>;
+ using __base_t = __decay_t<_Base>;
+ if constexpr (__same_as<__env_t, empty_env>)
+ {
+ return _Base((_Base&&)__base);
+ }
+ else if constexpr (__same_as<__base_t, empty_env>)
+ {
+ return _Env((_Env&&)__env);
+ }
+ else
+ {
+ return __joined_env<_Env, _Base>{{(_Base&&)__base}, (_Env&&)__env};
+ }
+ }
+
+ template <class _Env0, class _Env1, class _Env2, class... _Envs>
+ decltype(auto) operator()(_Env0 && __env0, _Env1 && __env1, _Env2 && __env2,
+ _Envs&&... __envs) const noexcept
+ {
+ const auto& __join_env = *this;
+ return __join_env(
+ (_Env0&&)__env0,
+ __join_env((_Env1&&)__env1,
+ __join_env((_Env2&&)__env2, (_Envs&&)__envs...)));
+ }
+};
+
+template <class... _Envs>
+using __env_join_t = __call_result_t<__join_env_t, _Envs...>;
+
+// To be kept in sync with the promise type used in __connect_awaitable
+template <class _Env>
+struct __env_promise
+{
+ template <class _Ty>
+ _Ty&& await_transform(_Ty&& __value) noexcept
+ {
+ return (_Ty&&)__value;
+ }
+
+ template <class _Ty>
+ requires tag_invocable<as_awaitable_t, _Ty, __env_promise&>
+ auto await_transform(_Ty&& __value) //
+ noexcept(nothrow_tag_invocable<as_awaitable_t, _Ty, __env_promise&>)
+ -> tag_invoke_result_t<as_awaitable_t, _Ty, __env_promise&>
+ {
+ return tag_invoke(as_awaitable, (_Ty&&)__value, *this);
+ }
+
+ friend auto tag_invoke(get_env_t, const __env_promise&) noexcept
+ -> const _Env&;
+};
+
+// For making an environment from key/value pairs and optionally
+// another environment.
+struct __make_env_t
+{
+ template <__nothrow_move_constructible _Base,
+ __nothrow_move_constructible _Env>
+ auto operator()(_Base&& __base, _Env&& __env) const noexcept
+ -> __env_join_t<_Env, _Base>
+ {
+ return __join_env_t()((_Env&&)__env, (_Base&&)__base);
+ }
+
+ template <__nothrow_move_constructible _Env>
+ _Env operator()(_Env&& __env) const noexcept
+ {
+ return (_Env&&)__env;
+ }
+};
+
+// For getting an evaluation environment from a receiver
+struct get_env_t
+{
+ template <class _EnvProvider>
+ requires tag_invocable<get_env_t, const _EnvProvider&>
+ STDEXEC_ATTRIBUTE((always_inline)) //
+ constexpr auto
+ operator()(const _EnvProvider& __with_env) const noexcept
+ -> tag_invoke_result_t<get_env_t, const _EnvProvider&>
+ {
+ static_assert(
+ queryable<tag_invoke_result_t<get_env_t, const _EnvProvider&>>);
+ static_assert(nothrow_tag_invocable<get_env_t, const _EnvProvider&>);
+ return tag_invoke(*this, __with_env);
+ }
+
+ template <class _EnvProvider>
+ constexpr empty_env operator()(const _EnvProvider&) const noexcept
+ {
+ return {};
+ }
+};
+} // namespace __env
+
+using __env::empty_env;
+using __empty_env
+ [[deprecated("Please use stdexec::empty_env now.")]] = empty_env;
+
+using __env::__env_promise;
+
+inline constexpr __env::__make_env_t __make_env{};
+inline constexpr __env::__join_env_t __join_env{};
+inline constexpr __env::get_env_t get_env{};
+
+// for making an environment from a single key/value pair
+inline constexpr __env::__mkprop_t __mkprop{};
+
+template <class _Tag, class _Value = void>
+using __with = __env::__prop<_Value(_Tag)>;
+
+template <class... _Ts>
+using __make_env_t = __call_result_t<__env::__make_env_t, _Ts...>;
+
+using __default_env = empty_env;
+
+template <class _EnvProvider>
+concept environment_provider = //
+ requires(_EnvProvider& __ep) {
+ {
+ get_env(std::as_const(__ep))
+ } -> queryable;
+ };
+} // namespace stdexec
+
+STDEXEC_PRAGMA_POP()
diff --git a/include/sdbusplus/async/stdexec/__detail/__execution_fwd.hpp b/include/sdbusplus/async/stdexec/__detail/__execution_fwd.hpp
index 898c636..affffe9 100644
--- a/include/sdbusplus/async/stdexec/__detail/__execution_fwd.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__execution_fwd.hpp
@@ -45,6 +45,8 @@
concept __completion_tag =
__one_of<_Tag, set_value_t, set_error_t, set_stopped_t>;
+struct receiver_t;
+
template <class _Sender>
extern const bool enable_receiver;
@@ -52,7 +54,12 @@
namespace __env
{
struct get_env_t;
-struct empty_env;
+
+struct empty_env
+{
+ using __t = empty_env;
+ using __id = empty_env;
+};
} // namespace __env
using __env::empty_env;
@@ -141,6 +148,8 @@
concept __nothrow_connectable =
__nothrow_callable<connect_t, _Sender, _Receiver>;
+struct sender_t;
+
template <class _Sender>
extern const bool enable_sender;
@@ -208,4 +217,19 @@
{
using __on_v2::on_t;
}
+
+namespace __detail
+{
+struct __sexpr_apply_t;
+}
+
+using __detail::__sexpr_apply_t;
+extern const __sexpr_apply_t __sexpr_apply;
} // namespace stdexec
+
+template <class...>
+[[deprecated]] void print()
+{}
+
+template <class>
+struct undef;
diff --git a/include/sdbusplus/async/stdexec/__detail/__meta.hpp b/include/sdbusplus/async/stdexec/__detail/__meta.hpp
index d1f5fea..b339405 100644
--- a/include/sdbusplus/async/stdexec/__detail/__meta.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__meta.hpp
@@ -87,6 +87,12 @@
template <std::size_t _Np>
using __msize_t = char[_Np + 1];
+template <auto _Np>
+struct __mconstant_;
+
+template <auto _Np>
+using __mconstant = __mconstant_<_Np>*;
+
template <class _Tp, class _Up>
using __mfirst = _Tp;
@@ -109,6 +115,9 @@
template <class _Tp, _Tp _Ip>
inline constexpr _Tp __v<std::integral_constant<_Tp, _Ip>> = _Ip;
+template <auto _Np>
+inline constexpr __mtypeof<_Np> __v<__mconstant<_Np>> = _Np;
+
template <std::size_t _Ip>
inline constexpr std::size_t __v<char[_Ip]> = _Ip - 1;
@@ -975,7 +984,13 @@
#if STDEXEC_HAS_BUILTIN(__type_pack_element)
template <std::size_t _Np, class... _Ts>
-using __m_at_c = __type_pack_element<_Np, _Ts...>;
+struct __m_at_
+{
+ using __t = __type_pack_element<_Np, _Ts...>;
+};
+
+template <std::size_t _Np, class... _Ts>
+using __m_at_c = __t<__m_at_<_Np, _Ts...>>;
#else
template <std::size_t>
using __void_ptr = void*;
diff --git a/include/sdbusplus/async/stdexec/__detail/__tuple.hpp b/include/sdbusplus/async/stdexec/__detail/__tuple.hpp
new file mode 100644
index 0000000..cc91dd1
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/__detail/__tuple.hpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2023 NVIDIA Corporation
+ *
+ * Licensed under the Apache License Version 2.0 with LLVM Exceptions
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://llvm.org/LICENSE.txt
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "__config.hpp"
+#include "__meta.hpp"
+
+namespace stdexec
+{
+namespace __tup
+{
+template <class _Ty, std::size_t _Idx>
+struct __box
+{
+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Ty __value;
+};
+
+template <class _Idx, class... _Ts>
+struct __tuple;
+
+template <std::size_t... _Idx, class... _Ts>
+struct __tuple<__indices<_Idx...>, _Ts...> : __box<_Ts, _Idx>...
+{};
+
+template <class... _Ts>
+STDEXEC_ATTRIBUTE((host, device))
+__tuple(_Ts...) -> __tuple<__indices_for<_Ts...>, _Ts...>;
+
+#if STDEXEC_GCC()
+template <class... _Ts>
+struct __mk_tuple
+{
+ using __t = __tuple<__indices_for<_Ts...>, _Ts...>;
+};
+template <class... _Ts>
+using __tuple_for = __t<__mk_tuple<_Ts...>>;
+#else
+template <class... _Ts>
+using __tuple_for = __tuple<__indices_for<_Ts...>, _Ts...>;
+#endif
+
+template <std::size_t _Idx, class _Ty>
+STDEXEC_ATTRIBUTE((always_inline))
+constexpr _Ty&& __get(__box<_Ty, _Idx>&& __self) noexcept
+{
+ return (_Ty&&)__self.__value;
+}
+
+template <std::size_t _Idx, class _Ty>
+STDEXEC_ATTRIBUTE((always_inline))
+constexpr _Ty& __get(__box<_Ty, _Idx>& __self) noexcept
+{
+ return __self.__value;
+}
+
+template <std::size_t _Idx, class _Ty>
+STDEXEC_ATTRIBUTE((always_inline))
+constexpr const _Ty& __get(const __box<_Ty, _Idx>& __self) noexcept
+{
+ return __self.__value;
+}
+
+template <std::size_t... _Idx, class... _Ts>
+void __tuple_like_(const __tuple<__indices<_Idx...>, _Ts...>&);
+
+template <class _Tup>
+concept __tuple_like = requires(_Tup& __tup) { __tup::__tuple_like_(__tup); };
+
+struct __apply_
+{
+ template <class _Fun, class _Tuple, std::size_t... _Idx, class... _Ts>
+ requires __callable<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
+ constexpr auto operator()(
+ _Fun&& __fun, _Tuple&& __tup,
+ const __tuple<
+ __indices<_Idx...>,
+ _Ts...>*) noexcept(__nothrow_callable<_Fun, __copy_cvref_t<_Tuple,
+ _Ts>...>)
+ -> __call_result_t<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
+ {
+ return ((_Fun&&)__fun)(
+ static_cast<__copy_cvref_t<_Tuple, __box<_Ts, _Idx>>&&>(__tup)
+ .__value...);
+ }
+};
+
+template <class _Fun, __tuple_like _Tuple>
+STDEXEC_ATTRIBUTE((always_inline))
+constexpr auto __apply(_Fun&& __fun, _Tuple&& __tup) noexcept(
+ noexcept(__apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup)))
+ -> decltype(__apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup))
+{
+ return __apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup);
+}
+} // namespace __tup
+
+using __tup::__tuple;
+
+// So we can use __tuple as a typelist and ignore the first template parameter
+template <class _Fn, class _Idx, class... _Ts>
+ requires __minvocable<_Fn, _Ts...>
+struct __uncurry_<_Fn, __tuple<_Idx, _Ts...>>
+{
+ using __t = __minvoke<_Fn, _Ts...>;
+};
+} // namespace stdexec
diff --git a/include/sdbusplus/async/stdexec/any_sender_of.hpp b/include/sdbusplus/async/stdexec/any_sender_of.hpp
index 443b64c..5336954 100644
--- a/include/sdbusplus/async/stdexec/any_sender_of.hpp
+++ b/include/sdbusplus/async/stdexec/any_sender_of.hpp
@@ -815,7 +815,7 @@
} __env_;
public:
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using __id = __ref;
using __t = __ref;
@@ -888,7 +888,7 @@
} __env_;
public:
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using __id = __ref;
using __t = __ref;
@@ -975,7 +975,7 @@
struct __t
{
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
__operation_base<_Receiver>* __op_;
template <same_as<set_next_t> _SetNext, same_as<__t> _Self, class _Item>
@@ -1188,7 +1188,7 @@
public:
using __id = __sender;
using completion_signatures = _Sigs;
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
__t(const __t&) = delete;
__t& operator=(const __t&) = delete;
@@ -1356,7 +1356,7 @@
}
public:
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using __t = any_receiver_ref;
using __id = any_receiver_ref;
@@ -1390,7 +1390,7 @@
}
public:
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
using completion_signatures =
typename __sender_base::completion_signatures;
diff --git a/include/sdbusplus/async/stdexec/async_scope.hpp b/include/sdbusplus/async/stdexec/async_scope.hpp
index 3da1840..4109299 100644
--- a/include/sdbusplus/async/stdexec/async_scope.hpp
+++ b/include/sdbusplus/async/stdexec/async_scope.hpp
@@ -110,7 +110,7 @@
struct __when_empty_sender
{
using _Constrained = __t<_ConstrainedId>;
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
template <class _Self, class _Receiver>
using __when_empty_op_t =
@@ -159,7 +159,7 @@
template <class _ReceiverId>
struct __nest_rcvr
{
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using _Receiver = __t<_ReceiverId>;
__nest_op_base<_ReceiverId>* __op_;
@@ -238,7 +238,7 @@
struct __nest_sender
{
using _Constrained = __t<_ConstrainedId>;
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
const __impl* __scope_;
STDEXEC_ATTRIBUTE((no_unique_address)) _Constrained __c_;
@@ -558,7 +558,7 @@
template <class _CompletionsId, class _EnvId>
struct __future_rcvr
{
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using _Completions = __t<_CompletionsId>;
using _Env = __t<_EnvId>;
__future_state_base<_Completions, _Env>* __state_;
@@ -643,7 +643,7 @@
friend struct async_scope;
public:
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
__future(__future&&) = default;
__future& operator=(__future&&) = default;
@@ -727,7 +727,7 @@
template <class _EnvId>
struct __spawn_rcvr
{
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using _Env = __t<_EnvId>;
__spawn_op_base<_EnvId>* __op_;
const __impl* __scope_;
diff --git a/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp b/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp
index e0e6235..f299244 100644
--- a/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp
+++ b/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp
@@ -44,7 +44,7 @@
{
struct __t
{
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using __id = __receiver_id;
_Receiver __receiver_;
@@ -84,7 +84,7 @@
struct __t
{
using __id = __sender_id;
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
_Sender __sender_;
diff --git a/include/sdbusplus/async/stdexec/commit.info b/include/sdbusplus/async/stdexec/commit.info
index 8556544..4ec6e44 100644
--- a/include/sdbusplus/async/stdexec/commit.info
+++ b/include/sdbusplus/async/stdexec/commit.info
@@ -1 +1 @@
-6b027bc6b6ace7b9047656cf8eb6f934e0535da3
+e05f158445ef957dc53731607d417ec6a7d834d7
diff --git a/include/sdbusplus/async/stdexec/env.hpp b/include/sdbusplus/async/stdexec/env.hpp
index 68fe431..32532d6 100644
--- a/include/sdbusplus/async/stdexec/env.hpp
+++ b/include/sdbusplus/async/stdexec/env.hpp
@@ -92,7 +92,7 @@
struct __sender
{
using _Default = __t<_DefaultId>;
- using is_sender = void;
+ using sender_concept = stdexec::sender_t;
STDEXEC_ATTRIBUTE((no_unique_address)) _Default __default_;
template <class _Env>
diff --git a/include/sdbusplus/async/stdexec/execution.hpp b/include/sdbusplus/async/stdexec/execution.hpp
index 78a5fff..8900d56 100644
--- a/include/sdbusplus/async/stdexec/execution.hpp
+++ b/include/sdbusplus/async/stdexec/execution.hpp
@@ -16,6 +16,8 @@
#pragma once
#include "__detail/__basic_sender.hpp"
+#include "__detail/__domain.hpp"
+#include "__detail/__env.hpp"
#include "__detail/__execution_fwd.hpp"
#include "__detail/__intrusive_ptr.hpp"
#include "__detail/__meta.hpp"
@@ -43,6 +45,7 @@
STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option")
STDEXEC_PRAGMA_IGNORE_GNU("-Wundefined-inline")
STDEXEC_PRAGMA_IGNORE_GNU("-Wsubobject-linkage")
+STDEXEC_PRAGMA_IGNORE_GNU("-Wmissing-braces")
STDEXEC_PRAGMA_IGNORE_EDG(1302)
STDEXEC_PRAGMA_IGNORE_EDG(497)
@@ -50,715 +53,6 @@
namespace stdexec
{
-// [exec.queries.queryable]
-template <class T>
-concept queryable = destructible<T>;
-
-template <class Tag>
-struct __query
-{
- template <class Sig>
- static inline constexpr Tag (*signature)(Sig) = nullptr;
-};
-
-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;
-
-template <class _Tag, class... _Args>
-using __legacy_c11n_fn = //
- __make_dispatcher<__legacy_c11n_for<_Tag>, __none_such, _Args...>;
-
-template <class _Tag, class... _Args>
-concept __has_legacy_c11n = //
- __callable<__legacy_c11n_fn<_Tag, _Args...>, _Args...>;
-
-struct __legacy_customization
-{
- template <class _Tag, class _Data, class... _Children>
- requires __has_legacy_c11n<_Tag, _Data, _Children...>
- decltype(auto) operator()(_Tag, _Data && __data,
- _Children&&... __children) const
- {
- return __legacy_c11n_fn<_Tag, _Data, _Children...>()(
- static_cast<_Data&&>(__data),
- static_cast<_Children&&>(__children)...);
- }
-};
-
-template <class _DomainOrTag, class _Sender, class... _Env>
-concept __has_transform_sender =
- requires(_DomainOrTag __tag, _Sender&& __sender, const _Env&... __env) {
- __tag.transform_sender((_Sender&&)__sender, __env...);
- };
-
-template <class _Sender, class... _Env>
-concept __has_default_transform_sender = //
- sender_expr<_Sender> //
- && __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) {
- __obj.transform_env((_Sender&&)__sender, (_Env&&)__env);
- };
-
-template <class _Sender, class _Env>
-concept __has_default_transform_env = //
- sender_expr<_Sender> //
- && __has_transform_env<tag_of_t<_Sender>, _Sender, _Env>;
-
-template <class _DomainOrTag, class... _Args>
-concept __has_apply_sender = requires(_DomainOrTag __tag, _Args&&... __args) {
- __tag.apply_sender((_Args&&)__args...);
- };
-} // namespace __domain
-
-namespace __write_
-{
-struct __write_t;
-}
-
-struct default_domain
-{
- default_domain() = default;
-
- // Called without the environment during eager customization
- template <class _Sender>
- STDEXEC_ATTRIBUTE((always_inline))
- decltype(auto) transform_sender(_Sender&& __sndr) const
- {
- // Look for a legacy customization for the given tag, and if found,
- // apply it.
- 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_t<_Sender>().transform_sender((_Sender&&)__sndr);
- }
- else
- {
- return static_cast<_Sender>((_Sender&&)__sndr);
- }
- STDEXEC_UNREACHABLE();
- }
-
- // Called with an environment during lazy customization
- template <class _Sender, class _Env>
- 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_t<_Sender>().transform_sender((_Sender&&)__sndr,
- __env);
- }
- else
- {
- return static_cast<_Sender>((_Sender&&)__sndr);
- }
- STDEXEC_UNREACHABLE();
- }
-
- template <class _Tag, class _Sender, class... _Args>
- requires __domain::__has_legacy_c11n<_Tag, _Sender, _Args...> ||
- __domain::__has_apply_sender<_Tag, _Sender, _Args...>
- STDEXEC_ATTRIBUTE((always_inline)) decltype(auto)
- apply_sender(_Tag, _Sender&& __sndr, _Args&&... __args) const
- {
- // Look for a legacy customization for the given tag, and if found,
- // apply it.
- if constexpr (__domain::__has_legacy_c11n<_Tag, _Sender, _Args...>)
- {
- return __domain::__legacy_c11n_fn<_Tag, _Sender, _Args...>()(
- static_cast<_Sender&&>(__sndr),
- static_cast<_Args&&>(__args)...);
- }
- else
- {
- return _Tag().apply_sender((_Sender&&)__sndr, (_Args&&)__args...);
- }
- STDEXEC_UNREACHABLE();
- }
-
- 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_t<_Sender>().transform_env((_Sender&&)__sndr,
- (_Env&&)__env);
- }
- else
- {
- return static_cast<_Env>((_Env&&)__env);
- }
- }
-};
-
-//////////////////////////////////////////////////////////////////////////////////////////////////
-// [exec.queries]
-namespace __queries
-{
-struct forwarding_query_t
-{
- template <class _Query>
- constexpr bool operator()(_Query __query) const noexcept
- {
- if constexpr (tag_invocable<forwarding_query_t, _Query>)
- {
- return tag_invoke(*this, (_Query&&)__query);
- }
- else if constexpr (std::derived_from<_Query, forwarding_query_t>)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-};
-
-struct query_or_t
-{
- template <class _Query, class _Queryable, class _Default>
- constexpr auto operator()(_Query, _Queryable&&, _Default&& __default) const
- noexcept(__nothrow_constructible_from<_Default, _Default&&>) -> _Default
- {
- return (_Default&&)__default;
- }
-
- template <class _Query, class _Queryable, class _Default>
- requires __callable<_Query, _Queryable>
- constexpr auto operator()(_Query __query, _Queryable&& __queryable,
- _Default&&) const
- noexcept(__nothrow_callable<_Query, _Queryable>)
- -> __call_result_t<_Query, _Queryable>
- {
- return ((_Query&&)__query)((_Queryable&&)__queryable);
- }
-};
-
-struct execute_may_block_caller_t : __query<execute_may_block_caller_t>
-{
- template <class _Tp>
- requires tag_invocable<execute_may_block_caller_t, __cref_t<_Tp>>
- constexpr bool operator()(_Tp&& __t) const noexcept
- {
- static_assert(
- same_as<bool, tag_invoke_result_t<execute_may_block_caller_t,
- __cref_t<_Tp>>>);
- static_assert(
- nothrow_tag_invocable<execute_may_block_caller_t, __cref_t<_Tp>>);
- return tag_invoke(execute_may_block_caller_t{}, std::as_const(__t));
- }
-
- constexpr bool operator()(auto&&) const noexcept
- {
- return true;
- }
-};
-
-struct get_forward_progress_guarantee_t :
- __query<get_forward_progress_guarantee_t>
-{
- template <class _Tp>
- requires tag_invocable<get_forward_progress_guarantee_t, __cref_t<_Tp>>
- constexpr auto operator()(_Tp&& __t) const noexcept(
- nothrow_tag_invocable<get_forward_progress_guarantee_t, __cref_t<_Tp>>)
- -> tag_invoke_result_t<get_forward_progress_guarantee_t, __cref_t<_Tp>>
- {
- return tag_invoke(get_forward_progress_guarantee_t{},
- std::as_const(__t));
- }
-
- constexpr stdexec::forward_progress_guarantee
- operator()(auto&&) const noexcept
- {
- return stdexec::forward_progress_guarantee::weakly_parallel;
- }
-};
-
-struct __has_algorithm_customizations_t :
- __query<__has_algorithm_customizations_t>
-{
- template <class _Tp>
- using __result_t =
- tag_invoke_result_t<__has_algorithm_customizations_t, __cref_t<_Tp>>;
-
- template <class _Tp>
- requires tag_invocable<__has_algorithm_customizations_t, __cref_t<_Tp>>
- constexpr __result_t<_Tp> operator()(_Tp&&) const
- noexcept(noexcept(__result_t<_Tp>{}))
- {
- using _Boolean = tag_invoke_result_t<__has_algorithm_customizations_t,
- __cref_t<_Tp>>;
- static_assert(_Boolean{}
- ? true
- : true); // must be contextually convertible to bool
- return _Boolean{};
- }
-
- constexpr std::false_type operator()(auto&&) const noexcept
- {
- return {};
- }
-};
-
-// TODO: implement allocator concept
-template <class _T0>
-concept __allocator_c = true;
-
-struct get_scheduler_t : __query<get_scheduler_t>
-{
- friend constexpr bool tag_invoke(forwarding_query_t,
- const get_scheduler_t&) noexcept
- {
- return true;
- }
-
- template <class _Env>
- requires tag_invocable<get_scheduler_t, const _Env&>
- auto operator()(const _Env& __env) const noexcept
- -> tag_invoke_result_t<get_scheduler_t, const _Env&>;
-
- auto operator()() const noexcept;
-};
-
-struct get_delegatee_scheduler_t : __query<get_delegatee_scheduler_t>
-{
- friend constexpr bool tag_invoke(forwarding_query_t,
- const get_delegatee_scheduler_t&) noexcept
- {
- return true;
- }
-
- template <class _Env>
- requires tag_invocable<get_delegatee_scheduler_t, const _Env&>
- auto operator()(const _Env& __t) const noexcept
- -> tag_invoke_result_t<get_delegatee_scheduler_t, const _Env&>;
-
- auto operator()() const noexcept;
-};
-
-struct get_allocator_t : __query<get_allocator_t>
-{
- friend constexpr bool tag_invoke(forwarding_query_t,
- const get_allocator_t&) noexcept
- {
- return true;
- }
-
- template <class _Env>
- requires tag_invocable<get_allocator_t, const _Env&>
- auto operator()(const _Env& __env) const noexcept
- -> tag_invoke_result_t<get_allocator_t, const _Env&>
- {
- static_assert(nothrow_tag_invocable<get_allocator_t, const _Env&>);
- static_assert(
- __allocator_c<tag_invoke_result_t<get_allocator_t, const _Env&>>);
- return tag_invoke(get_allocator_t{}, __env);
- }
-
- auto operator()() const noexcept;
-};
-
-struct get_stop_token_t : __query<get_stop_token_t>
-{
- friend constexpr bool tag_invoke(forwarding_query_t,
- const get_stop_token_t&) noexcept
- {
- return true;
- }
-
- template <class _Env>
- never_stop_token operator()(const _Env&) const noexcept
- {
- return {};
- }
-
- template <class _Env>
- requires tag_invocable<get_stop_token_t, const _Env&>
- auto operator()(const _Env& __env) const noexcept
- -> tag_invoke_result_t<get_stop_token_t, const _Env&>
- {
- static_assert(nothrow_tag_invocable<get_stop_token_t, const _Env&>);
- static_assert(stoppable_token<
- tag_invoke_result_t<get_stop_token_t, const _Env&>>);
- return tag_invoke(get_stop_token_t{}, __env);
- }
-
- auto operator()() const noexcept;
-};
-
-template <class _Queryable, class _CPO>
-concept __has_completion_scheduler_for =
- queryable<_Queryable> && //
- tag_invocable<get_completion_scheduler_t<_CPO>, const _Queryable&>;
-
-template <__completion_tag _CPO>
-struct get_completion_scheduler_t : __query<get_completion_scheduler_t<_CPO>>
-{
- friend constexpr bool
- tag_invoke(forwarding_query_t,
- const get_completion_scheduler_t<_CPO>&) noexcept
- {
- return true;
- }
-
- template <__has_completion_scheduler_for<_CPO> _Queryable>
- auto operator()(const _Queryable& __queryable) const noexcept
- -> tag_invoke_result_t<get_completion_scheduler_t<_CPO>,
- const _Queryable&>;
-};
-
-struct get_domain_t
-{
- template <class _Ty>
- requires tag_invocable<get_domain_t, const _Ty&>
- constexpr auto operator()(const _Ty& __ty) const noexcept
- -> tag_invoke_result_t<get_domain_t, const _Ty&>
- {
- static_assert(nothrow_tag_invocable<get_domain_t, const _Ty&>,
- "Customizations of get_domain must be noexcept.");
- static_assert(__class<tag_invoke_result_t<get_domain_t, const _Ty&>>,
- "Customizations of get_domain must return a class type.");
- return tag_invoke(get_domain_t{}, __ty);
- }
-
- friend constexpr bool tag_invoke(forwarding_query_t, get_domain_t) noexcept
- {
- return true;
- }
-};
-} // namespace __queries
-
-using __queries::__has_algorithm_customizations_t;
-using __queries::execute_may_block_caller_t;
-using __queries::forwarding_query_t;
-using __queries::get_allocator_t;
-using __queries::get_completion_scheduler_t;
-using __queries::get_delegatee_scheduler_t;
-using __queries::get_domain_t;
-using __queries::get_forward_progress_guarantee_t;
-using __queries::get_scheduler_t;
-using __queries::get_stop_token_t;
-using __queries::query_or_t;
-
-inline constexpr forwarding_query_t forwarding_query{};
-inline constexpr query_or_t query_or{}; // NOT TO SPEC
-inline constexpr execute_may_block_caller_t execute_may_block_caller{};
-inline constexpr __has_algorithm_customizations_t
- __has_algorithm_customizations{};
-inline constexpr get_forward_progress_guarantee_t
- get_forward_progress_guarantee{};
-inline constexpr get_scheduler_t get_scheduler{};
-inline constexpr get_delegatee_scheduler_t get_delegatee_scheduler{};
-inline constexpr get_allocator_t get_allocator{};
-inline constexpr get_stop_token_t get_stop_token{};
-#if !STDEXEC_GCC() || defined(__OPTIMIZE_SIZE__)
-template <__completion_tag _CPO>
-inline constexpr get_completion_scheduler_t<_CPO> get_completion_scheduler{};
-#else
-template <>
-inline constexpr get_completion_scheduler_t<set_value_t>
- get_completion_scheduler<set_value_t>{};
-template <>
-inline constexpr get_completion_scheduler_t<set_error_t>
- get_completion_scheduler<set_error_t>{};
-template <>
-inline constexpr get_completion_scheduler_t<set_stopped_t>
- get_completion_scheduler<set_stopped_t>{};
-#endif
-
-template <class _Tag>
-concept __forwarding_query = forwarding_query(_Tag{});
-
-inline constexpr get_domain_t get_domain{};
-
-template <class _Tag, class _Queryable, class _Default>
-using __query_result_or_t =
- __call_result_t<query_or_t, _Tag, _Queryable, _Default>;
-
-/////////////////////////////////////////////////////////////////////////////
-// env_of
-namespace __env
-{
-struct empty_env
-{
- using __t = empty_env;
- using __id = empty_env;
-};
-
-template <class _Descriptor>
-struct __prop;
-
-template <class _Value, class... _Tags>
-struct __prop<_Value(_Tags...)>
-{
- using __t = __prop;
- using __id = __prop;
- _Value __value_;
-
- template <__one_of<_Tags...> _Key>
- friend auto tag_invoke(_Key, const __prop& __self) //
- noexcept(__nothrow_decay_copyable<_Value>) -> _Value
- {
- return __self.__value_;
- }
-};
-
-template <class... _Tags>
-struct __prop<void(_Tags...)>
-{
- using __t = __prop;
- using __id = __prop;
-
- template <__one_of<_Tags...> _Key, class _Self>
- requires(std::is_base_of_v<__prop, __decay_t<_Self>>)
- friend auto tag_invoke(_Key, _Self&&) noexcept = delete;
-};
-
-struct __mkprop_t
-{
- template <class _Value, class _Tag, class... _Tags>
- auto operator()(_Value&& __value, _Tag, _Tags...) const
- noexcept(__nothrow_decay_copyable<_Value>)
- -> __prop<__decay_t<_Value>(_Tag, _Tags...)>
- {
- return {(_Value&&)__value};
- }
-
- template <class _Tag>
- auto operator()(_Tag) const -> __prop<void(_Tag)>
- {
- return {};
- }
-};
-
-template <__nothrow_move_constructible _Fun>
-struct __env_fn
-{
- using __t = __env_fn;
- using __id = __env_fn;
- STDEXEC_ATTRIBUTE((no_unique_address)) _Fun __fun_;
-
- template <class _Tag>
- requires __callable<const _Fun&, _Tag>
- friend auto tag_invoke(_Tag, const __env_fn& __self) //
- noexcept(__nothrow_callable<const _Fun&, _Tag>)
- -> __call_result_t<const _Fun&, _Tag>
- {
- return __self.__fun_(_Tag());
- }
-};
-
-template <class _Fun>
-__env_fn(_Fun) -> __env_fn<_Fun>;
-
-template <class _Env>
-struct __env_fwd
-{
- static_assert(__nothrow_move_constructible<_Env>);
- using __t = __env_fwd;
- using __id = __env_fwd;
- STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
-
- template <__forwarding_query _Tag>
- requires tag_invocable<_Tag, const _Env&>
- friend auto tag_invoke(_Tag, const __env_fwd& __self) //
- noexcept(nothrow_tag_invocable<_Tag, const _Env&>)
- -> tag_invoke_result_t<_Tag, const _Env&>
- {
- return _Tag()(__self.__env_);
- }
-};
-
-template <class _Env>
-__env_fwd(_Env&&) -> __env_fwd<_Env>;
-
-template <class _Env, class _Base = empty_env>
-struct __joined_env : __env_fwd<_Base>
-{
- static_assert(__nothrow_move_constructible<_Env>);
- using __t = __joined_env;
- using __id = __joined_env;
- STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
-
- const _Base& base() const noexcept
- {
- return this->__env_fwd<_Base>::__env_;
- }
-
- template <class _Tag>
- requires tag_invocable<_Tag, const _Env&>
- friend auto tag_invoke(_Tag, const __joined_env& __self) //
- noexcept(nothrow_tag_invocable<_Tag, const _Env&>)
- -> tag_invoke_result_t<_Tag, const _Env&>
- {
- return _Tag()(__self.__env_);
- }
-};
-
-template <class _Tag, class _Base>
-struct __joined_env<__prop<void(_Tag)>, _Base> : __env_fwd<_Base>
-{
- using __t = __joined_env;
- using __id = __joined_env;
- STDEXEC_ATTRIBUTE((no_unique_address)) __prop<void(_Tag)> __env_;
-
- friend void tag_invoke(_Tag, const __joined_env&) noexcept = delete;
-};
-
-struct __join_env_t
-{
- template <class _Env>
- _Env operator()(_Env&& __env) const noexcept
- {
- return (_Env&&)__env;
- }
-
- template <class _Env, class _Base>
- decltype(auto) operator()(_Env && __env, _Base && __base) const noexcept
- {
- using __env_t = __decay_t<_Env>;
- using __base_t = __decay_t<_Base>;
- if constexpr (__same_as<__env_t, empty_env>)
- {
- return _Base((_Base&&)__base);
- }
- else if constexpr (__same_as<__base_t, empty_env>)
- {
- return _Env((_Env&&)__env);
- }
- else
- {
- return __joined_env<_Env, _Base>{{(_Base&&)__base}, (_Env&&)__env};
- }
- }
-
- template <class _Env0, class _Env1, class _Env2, class... _Envs>
- decltype(auto) operator()(_Env0 && __env0, _Env1 && __env1, _Env2 && __env2,
- _Envs&&... __envs) const noexcept
- {
- const auto& __join_env = *this;
- return __join_env(
- (_Env0&&)__env0,
- __join_env((_Env1&&)__env1,
- __join_env((_Env2&&)__env2, (_Envs&&)__envs...)));
- }
-};
-
-template <class... _Envs>
-using __env_join_t = __call_result_t<__join_env_t, _Envs...>;
-
-// To be kept in sync with the promise type used in __connect_awaitable
-template <class _Env>
-struct __env_promise
-{
- template <class _Ty>
- _Ty&& await_transform(_Ty&& __value) noexcept
- {
- return (_Ty&&)__value;
- }
-
- template <class _Ty>
- requires tag_invocable<as_awaitable_t, _Ty, __env_promise&>
- auto await_transform(_Ty&& __value) //
- noexcept(nothrow_tag_invocable<as_awaitable_t, _Ty, __env_promise&>)
- -> tag_invoke_result_t<as_awaitable_t, _Ty, __env_promise&>
- {
- return tag_invoke(as_awaitable, (_Ty&&)__value, *this);
- }
-
- friend auto tag_invoke(get_env_t, const __env_promise&) noexcept
- -> const _Env&;
-};
-
-// For making an environment from key/value pairs and optionally
-// another environment.
-struct __make_env_t
-{
- template <__nothrow_move_constructible _Base,
- __nothrow_move_constructible _Env>
- auto operator()(_Base&& __base, _Env&& __env) const noexcept
- -> __env_join_t<_Env, _Base>
- {
- return __join_env_t()((_Env&&)__env, (_Base&&)__base);
- }
-
- template <__nothrow_move_constructible _Env>
- _Env operator()(_Env&& __env) const noexcept
- {
- return (_Env&&)__env;
- }
-};
-
-// For getting an evaluation environment from a receiver
-struct get_env_t
-{
- template <class _EnvProvider>
- requires tag_invocable<get_env_t, const _EnvProvider&>
- STDEXEC_ATTRIBUTE((always_inline)) //
- constexpr auto
- operator()(const _EnvProvider& __with_env) const noexcept
- -> tag_invoke_result_t<get_env_t, const _EnvProvider&>
- {
- static_assert(
- queryable<tag_invoke_result_t<get_env_t, const _EnvProvider&>>);
- static_assert(nothrow_tag_invocable<get_env_t, const _EnvProvider&>);
- return tag_invoke(*this, __with_env);
- }
-
- template <class _EnvProvider>
- constexpr empty_env operator()(const _EnvProvider&) const noexcept
- {
- return {};
- }
-};
-} // namespace __env
-
-using __env::empty_env;
-using __empty_env
- [[deprecated("Please use stdexec::empty_env now.")]] = empty_env;
-
-using __env::__env_promise;
-
-inline constexpr __env::__make_env_t __make_env{};
-inline constexpr __env::__join_env_t __join_env{};
-inline constexpr __env::get_env_t get_env{};
-
-// for making an environment from a single key/value pair
-inline constexpr __env::__mkprop_t __mkprop{};
-
-template <class _Tag, class _Value = void>
-using __with = __env::__prop<_Value(_Tag)>;
-
-template <class... _Ts>
-using __make_env_t = __call_result_t<__env::__make_env_t, _Ts...>;
-
-using __default_env = empty_env;
-
-template <class _EnvProvider>
-concept environment_provider = //
- requires(_EnvProvider& __ep) {
- {
- get_env(std::as_const(__ep))
- } -> queryable;
- };
-
/////////////////////////////////////////////////////////////////////////////
template <class _Sender, class _Scheduler, class _Tag = set_value_t>
concept __completes_on = __decays_to<
@@ -771,181 +65,6 @@
__decays_to<__call_result_t<get_scheduler_t, _Env>, _Scheduler>;
/////////////////////////////////////////////////////////////////////////////
-namespace __detail
-{
-template <class _Env, class _Tag>
-using __completion_scheduler_for =
- __meval_or<__call_result_t, __none_such, get_completion_scheduler_t<_Tag>,
- _Env>;
-
-template <class _Env, class _Tag>
-using __completion_domain_for =
- __meval_or<__call_result_t, __none_such, get_domain_t,
- __completion_scheduler_for<_Env, _Tag>>;
-
-// Check the value, error, and stopped channels for completion schedulers.
-// Of the completion schedulers that are known, they must all have compatible
-// domains. This computes that domain, or else returns __none_such if there
-// are no completion schedulers or if they don't specify a domain.
-template <class _Env>
-struct __completion_domain_or_none_ :
- __mdefer_<__transform<
- __mbind_front_q<__completion_domain_for, _Env>,
- __remove<__none_such, __munique<__msingle_or<__none_such>>>>,
- set_value_t, set_error_t, set_stopped_t>
-{};
-
-template <class _Sender>
-using __completion_domain_or_none =
- __t<__completion_domain_or_none_<env_of_t<_Sender>>>;
-
-template <class _Sender>
-concept __consistent_completion_domains =
- __mvalid<__completion_domain_or_none, _Sender>;
-
-template <class _Sender>
-concept __has_completion_domain =
- (!same_as<__completion_domain_or_none<_Sender>, __none_such>);
-
-template <__has_completion_domain _Sender>
-using __completion_domain_of = __completion_domain_or_none<_Sender>;
-} // namespace __detail
-
-/////////////////////////////////////////////////////////////////////////////
-inline constexpr struct __get_early_domain_t
-{
- template <class _Sender, class _Default = default_domain>
- auto operator()(const _Sender&, _Default __def = {}) const noexcept
- {
- if constexpr (__callable<get_domain_t, env_of_t<_Sender>>)
- {
- return __call_result_t<get_domain_t, env_of_t<_Sender>>();
- }
- else if constexpr (__detail::__has_completion_domain<_Sender>)
- {
- return __detail::__completion_domain_of<_Sender>();
- }
- else
- {
- return __def;
- }
- STDEXEC_UNREACHABLE();
- }
-} __get_early_domain{};
-
-template <class _Sender, class _Default = default_domain>
-using __early_domain_of_t =
- __call_result_t<__get_early_domain_t, _Sender, _Default>;
-
-/////////////////////////////////////////////////////////////////////////////
-inline constexpr struct __get_late_domain_t
-{
- // When connect is looking for a customization, it first checks the sender's
- // domain. If the sender knows the domain in which it completes, then that
- // is where the subsequent task will execute. Otherwise, look to the
- // receiver for late-bound information about the current execution context.
- template <class _Sender, class _Env>
- auto operator()(const _Sender& __sndr, const _Env& __env) const noexcept
- {
- if constexpr (!same_as<dependent_domain,
- __early_domain_of_t<_Sender, dependent_domain>>)
- {
- return __get_early_domain(__sndr);
- }
- else if constexpr (__callable<get_domain_t, const _Env&>)
- {
- return get_domain(__env);
- }
- else if constexpr (__callable<__composed<get_domain_t, get_scheduler_t>,
- const _Env&>)
- {
- return get_domain(get_scheduler(__env));
- }
- else
- {
- return default_domain();
- }
- STDEXEC_UNREACHABLE();
- }
-
- // The transfer algorithm is the exception to the rule. It ignores the
- // domain of the predecessor, and dispatches based on the domain of the
- // scheduler to which execution is being transferred.
- template <sender_expr_for<transfer_t> _Sender, class _Env>
- auto operator()(const _Sender& __sndr, const _Env&) const noexcept
- {
- return __sexpr_apply(__sndr,
- [](__ignore, auto& __data, __ignore) noexcept {
- auto __sched = get_completion_scheduler<set_value_t>(__data);
- return query_or(get_domain, __sched, default_domain());
- });
- }
-} __get_late_domain{};
-
-template <class _Sender, class _Env>
-using __late_domain_of_t = __call_result_t<__get_late_domain_t, _Sender, _Env>;
-
-namespace __domain
-{
-struct __common_domain_fn
-{
- static default_domain __common_domain() noexcept
- {
- return {};
- }
-
- template <class _Domain, class... _OtherDomains>
- requires __all_of<_Domain, _OtherDomains...>
- static _Domain __common_domain(_Domain __domain, _OtherDomains...) noexcept
- {
- return (_Domain&&)__domain;
- }
-
- template <class... _Domains>
- static auto __common_domain(_Domains...) noexcept //
- -> __if_c<__one_of<dependent_domain, _Domains...>, dependent_domain,
- __none_such>
- {
- return {};
- }
-
- auto operator()(__ignore, __ignore, const auto&... __sndrs) const noexcept
- {
- return __common_domain(__get_early_domain(__sndrs)...);
- }
-};
-
-template <class... _Senders>
-using __common_domain_t = //
- __call_result_t<__common_domain_fn, int, int, _Senders...>;
-
-template <class... _Senders>
-concept __has_common_domain = //
- __none_of<__none_such, __common_domain_t<_Senders...>>;
-
-template <class _Tag>
-struct __get_env_common_domain
-{
- template <sender_expr_for<_Tag> _Self>
- static auto get_env(const _Self& __self) noexcept
- {
- using _Domain =
- __call_result_t<__sexpr_apply_t, const _Self&, __common_domain_fn>;
- if constexpr (same_as<_Domain, default_domain>)
- {
- return empty_env();
- }
- else
- {
- return __mkprop(__sexpr_apply(__self, __common_domain_fn()),
- get_domain);
- }
- STDEXEC_UNREACHABLE();
- }
-};
-} // namespace __domain
-
-/////////////////////////////////////////////////////////////////////////////
// [execution.receivers]
namespace __receivers
{
@@ -1168,7 +287,7 @@
template <class _Completions>
concept __valid_completion_signatures = //
- __is_instance_of<_Completions, completion_signatures>;
+ __ok<_Completions> && __is_instance_of<_Completions, completion_signatures>;
template <class _Completions>
using __invalid_completion_signatures_t = //
@@ -1231,17 +350,25 @@
/////////////////////////////////////////////////////////////////////////////
// [execution.receivers]
-struct __receiver_base
-{};
+struct receiver_t
+{
+ using receiver_concept = receiver_t; // NOT TO SPEC
+};
+namespace __detail
+{
template <class _Receiver>
-concept __enable_receiver = //
- requires { typename _Receiver::is_receiver; } ||
- STDEXEC_IS_BASE_OF(__receiver_base, _Receiver);
+concept __enable_receiver = //
+ (STDEXEC_NVHPC(requires { typename _Receiver::receiver_concept; }&&) //
+ derived_from<typename _Receiver::receiver_concept, receiver_t>) ||
+ requires { typename _Receiver::is_receiver; } // back-compat, NOT TO SPEC
+ || STDEXEC_IS_BASE_OF(receiver_t,
+ _Receiver); // NOT TO SPEC, for receiver_adaptor
+} // namespace __detail
template <class _Receiver>
inline constexpr bool enable_receiver =
- __enable_receiver<_Receiver>; // NOT TO SPEC
+ __detail::__enable_receiver<_Receiver>; // NOT TO SPEC
template <class _Receiver>
concept receiver = enable_receiver<__decay_t<_Receiver>> && //
@@ -1335,7 +462,7 @@
{
using __t = __debug_receiver;
using __id = __debug_receiver;
- using is_receiver = void;
+ using receiver_concept = receiver_t;
};
template <class _CvrefSenderId, class _Env, class... _Sigs>
@@ -1345,7 +472,7 @@
{
using __t = __debug_receiver;
using __id = __debug_receiver;
- using is_receiver = void;
+ using receiver_concept = receiver_t;
template <same_as<get_env_t> _Tag>
STDEXEC_ATTRIBUTE((host, device))
@@ -1799,12 +926,18 @@
/////////////////////////////////////////////////////////////////////////////
// [execution.senders]
+struct sender_t
+{
+ using sender_concept = sender_t;
+};
+
namespace __detail
{
template <class _Sender>
-concept __enable_sender = //
- requires { typename _Sender::is_sender; } || //
- __awaitable<_Sender, __env_promise<empty_env>>;
+concept __enable_sender = //
+ derived_from<typename _Sender::sender_concept, sender_t> ||
+ requires { typename _Sender::is_sender; } // NOT TO SPEC back compat
+ || __awaitable<_Sender, __env_promise<empty_env>>;
} // namespace __detail
template <class _Sender>
@@ -2506,10 +1639,6 @@
template <class _Sender, class _Receiver>
static constexpr auto __select_impl() noexcept
{
-#if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
- static_assert(__check_signatures<_Sender, env_of_t<_Receiver>>());
-#endif
-
using _Domain = __late_domain_of_t<_Sender, env_of_t<_Receiver&>>;
constexpr bool _NothrowTfxSender =
__nothrow_callable<get_env_t, _Receiver&> &&
@@ -2517,6 +1646,10 @@
env_of_t<_Receiver&>>;
using _TfxSender = __tfx_sender<_Sender, _Receiver&>;
+#if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING()
+ static_assert(__check_signatures<_TfxSender, env_of_t<_Receiver>>());
+#endif
+
if constexpr (__connectable_with_tag_invoke<_Sender, _Receiver>)
{
using _Result =
@@ -2632,7 +1765,7 @@
template <class _Value>
struct __receiver_base
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
template <same_as<set_value_t> _Tag, class... _Us>
requires constructible_from<__value_or_void_t<_Value>, _Us...>
@@ -2995,7 +2128,7 @@
template <class _OpRef>
struct __receiver
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
using __t = __receiver;
using __id = __receiver;
@@ -3102,45 +2235,19 @@
namespace __inln
{
-struct __scheduler;
-
-template <class _Receiver>
-struct __op : __immovable
-{
- _Receiver __recv_;
-
- friend void tag_invoke(start_t, __op& __self) noexcept
- {
- set_value((_Receiver&&)__self.__recv_);
- }
-};
-
struct __schedule_t
-{
- static auto get_env(__ignore) noexcept
- -> __env::__prop<__scheduler(get_completion_scheduler_t<set_value_t>)>;
-
- using __compl_sigs = stdexec::completion_signatures<set_value_t()>;
- static __compl_sigs get_completion_signatures(__ignore, __ignore);
-
- template <receiver_of<__compl_sigs> _Receiver>
- static auto
- connect(__ignore,
- _Receiver __rcvr) noexcept(__nothrow_decay_copyable<_Receiver>)
- {
- return __op<_Receiver>{{}, (_Receiver&&)__rcvr};
- }
-};
+{};
struct __scheduler
{
using __t = __scheduler;
using __id = __scheduler;
+ template <class _Tag = __schedule_t>
STDEXEC_ATTRIBUTE((host, device))
friend auto tag_invoke(schedule_t, __scheduler)
{
- return __make_sexpr<__schedule_t>();
+ return __make_sexpr<_Tag>();
}
friend forward_progress_guarantee
@@ -3151,14 +2258,30 @@
bool operator==(const __scheduler&) const noexcept = default;
};
-
-inline auto __schedule_t::get_env(__ignore) noexcept
- -> __env::__prop<__scheduler(get_completion_scheduler_t<set_value_t>)>
-{
- return __mkprop(__scheduler{}, get_completion_scheduler<set_value_t>);
-}
} // namespace __inln
+template <>
+struct __sexpr_impl<__inln::__schedule_t> : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ [](__ignore) noexcept -> __env::__prop<__inln::__scheduler(
+ get_completion_scheduler_t<set_value_t>)> {
+ return __mkprop(__inln::__scheduler{},
+ get_completion_scheduler<set_value_t>);
+ };
+
+ static constexpr auto get_completion_signatures = //
+ [](__ignore,
+ __ignore) noexcept -> completion_signatures<set_value_t()> {
+ return {};
+ };
+
+ static constexpr auto start = //
+ []<class _Receiver>(__ignore, _Receiver& __rcvr) noexcept -> void {
+ set_value((_Receiver&&)__rcvr);
+ };
+};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.consumer.start_detached]
namespace __start_detached
@@ -3170,7 +2293,7 @@
struct __t
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
using __id = __detached_receiver;
STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
@@ -3243,105 +2366,64 @@
// [execution.senders.factories]
namespace __just
{
-template <class _ReceiverId, class _Tag, class _Tuple>
-struct __operation
+template <class _JustTag>
+struct __impl : __sexpr_defaults
{
- using _Receiver = stdexec::__t<_ReceiverId>;
+ using __tag_t = typename _JustTag::__tag_t;
- struct __t : __immovable
- {
- using __id = __operation;
- _Tuple __vals_;
- _Receiver __rcvr_;
+ static constexpr auto get_completion_signatures =
+ []<class _Sender>(_Sender&&, __ignore) noexcept {
+ static_assert(sender_expr_for<_Sender, _JustTag>);
+ return completion_signatures<
+ __mapply<__qf<__tag_t>, __decay_t<__data_of<_Sender>>>>{};
+ };
- friend void tag_invoke(start_t, __t& __op_state) noexcept
- {
- using __tag_t = _Tag;
- using __receiver_t = _Receiver;
- __apply(
- [&__op_state]<class... _Ts>(_Ts&... __ts) {
- __tag_t()((__receiver_t&&)__op_state.__rcvr_, (_Ts&&)__ts...);
- },
- __op_state.__vals_);
- }
+ static constexpr auto start =
+ []<class _State, class _Receiver>(_State& __state,
+ _Receiver& __rcvr) noexcept -> void {
+ __tup::__apply(
+ [&]<class... _Ts>(_Ts&... __ts) noexcept {
+ __tag_t()(std::move(__rcvr), std::move(__ts)...);
+ },
+ __state);
};
};
-template <class _SetTag, class _Receiver>
-struct __connect_fn
+struct just_t
{
- _Receiver& __rcvr_;
+ using __tag_t = set_value_t;
- template <class _Tuple>
- auto operator()(__ignore, _Tuple&& __tup) const
- noexcept(__nothrow_decay_copyable<_Tuple>)
- -> __t<__operation<__id<_Receiver>, _SetTag, __decay_t<_Tuple>>>
- {
- return {{}, (_Tuple&&)__tup, (_Receiver&&)__rcvr_};
- }
-};
-
-template <class _JustTag, class _SetTag>
-struct __just_impl
-{
- template <class _Sender>
- using __compl_sigs = //
- completion_signatures< //
- __mapply< //
- __qf<_SetTag>, __decay_t<__data_of<_Sender>>>>;
-
- template <sender_expr_for<_JustTag> _Sender>
- static __compl_sigs<_Sender> get_completion_signatures(_Sender&&, __ignore)
- {
- return {};
- }
-
- template <sender_expr_for<_JustTag> _Sender,
- receiver_of<__compl_sigs<_Sender>> _Receiver>
- static auto connect(_Sender&& __sndr, _Receiver __rcvr) noexcept(
- __nothrow_callable<__sexpr_apply_t, _Sender,
- __connect_fn<_SetTag, _Receiver>>)
- -> __call_result_t<__sexpr_apply_t, _Sender,
- __connect_fn<_SetTag, _Receiver>>
- {
- return __sexpr_apply((_Sender&&)__sndr,
- __connect_fn<_SetTag, _Receiver>{__rcvr});
- }
-
- static empty_env get_env(__ignore) noexcept
- {
- return {};
- }
-};
-
-struct just_t : __just_impl<just_t, set_value_t>
-{
template <__movable_value... _Ts>
STDEXEC_ATTRIBUTE((host, device))
auto operator()(_Ts&&... __ts) const
noexcept((__nothrow_decay_copyable<_Ts> && ...))
{
- return __make_sexpr<just_t>(__decayed_tuple<_Ts...>{(_Ts&&)__ts...});
+ return __make_sexpr<just_t>(__tuple{(_Ts&&)__ts...});
}
};
-struct just_error_t : __just_impl<just_error_t, set_error_t>
+struct just_error_t
{
+ using __tag_t = set_error_t;
+
template <__movable_value _Error>
STDEXEC_ATTRIBUTE((host, device))
auto operator()(_Error&& __err) const
noexcept(__nothrow_decay_copyable<_Error>)
{
- return __make_sexpr<just_error_t>(
- __decayed_tuple<_Error>{(_Error&&)__err});
+ return __make_sexpr<just_error_t>(__tuple{(_Error&&)__err});
}
};
-struct just_stopped_t : __just_impl<just_stopped_t, set_stopped_t>
+struct just_stopped_t
{
- STDEXEC_ATTRIBUTE((host, device)) auto operator()() const noexcept
+ using __tag_t = set_stopped_t;
+
+ template <class _Tag = just_stopped_t>
+ STDEXEC_ATTRIBUTE((host, device))
+ auto operator()() const noexcept
{
- return __make_sexpr<just_stopped_t>(__decayed_tuple<>());
+ return __make_sexpr<_Tag>(__tuple{});
}
};
} // namespace __just
@@ -3350,6 +2432,18 @@
using __just::just_stopped_t;
using __just::just_t;
+template <>
+struct __sexpr_impl<just_t> : __just::__impl<just_t>
+{};
+
+template <>
+struct __sexpr_impl<just_error_t> : __just::__impl<just_error_t>
+{};
+
+template <>
+struct __sexpr_impl<just_stopped_t> : __just::__impl<just_stopped_t>
+{};
+
inline constexpr just_t just{};
inline constexpr just_error_t just_error{};
inline constexpr just_stopped_t just_stopped{};
@@ -3361,7 +2455,7 @@
template <class _Fun>
struct __as_receiver
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
_Fun __fun_;
template <same_as<set_value_t> _Tag>
@@ -3556,7 +2650,7 @@
struct __receiver : __nope
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
};
template <same_as<set_error_t> _Tag>
@@ -3569,47 +2663,39 @@
using __not_a_receiver = __no::__receiver;
template <class _Base>
-struct __adaptor
+struct __adaptor_base
{
- struct __t
+ template <class _T1>
+ requires constructible_from<_Base, _T1>
+ explicit __adaptor_base(_T1&& __base) : __base_((_T1&&)__base)
+ {}
+
+ private:
+ STDEXEC_ATTRIBUTE((no_unique_address)) _Base __base_;
+
+ protected:
+ STDEXEC_ATTRIBUTE((host, device, always_inline)) //
+ _Base& base() & noexcept
{
- template <class _T1>
- requires constructible_from<_Base, _T1>
- explicit __t(_T1&& __base) : __base_((_T1&&)__base)
- {}
+ return __base_;
+ }
- private:
- STDEXEC_ATTRIBUTE((no_unique_address)) _Base __base_;
+ STDEXEC_ATTRIBUTE((host, device, always_inline)) //
+ const _Base& base() const& noexcept
+ {
+ return __base_;
+ }
- protected:
- STDEXEC_ATTRIBUTE((host, device, always_inline)) //
- _Base& base() & noexcept
- {
- return __base_;
- }
-
- STDEXEC_ATTRIBUTE((host, device, always_inline)) //
- const _Base& base() const& noexcept
- {
- return __base_;
- }
-
- STDEXEC_ATTRIBUTE((host, device, always_inline)) //
- _Base&& base() && noexcept
- {
- return (_Base&&)__base_;
- }
- };
+ STDEXEC_ATTRIBUTE((host, device, always_inline)) //
+ _Base&& base() && noexcept
+ {
+ return (_Base&&)__base_;
+ }
};
template <derived_from<__no::__nope> _Base>
-struct __adaptor<_Base>
-{
- struct __t : __no::__nope
- {};
-};
-template <class _Base>
-using __adaptor_base = typename __adaptor<_Base>::__t;
+struct __adaptor_base<_Base>
+{};
// BUGBUG Not to spec: on gcc and nvc++, member functions in derived classes
// don't shadow type aliases of the same name in base classes. :-O
@@ -3642,148 +2728,143 @@
static constexpr int _TAG = 1 /**/
#endif
-template <__class _Derived, class _Base>
-struct receiver_adaptor
+template <__class _Derived, class _Base = __not_a_receiver>
+struct receiver_adaptor : __adaptor_base<_Base>, receiver_t
{
- class __t : __adaptor_base<_Base>, __receiver_base
+ friend _Derived;
+ _DEFINE_MEMBER(set_value);
+ _DEFINE_MEMBER(set_error);
+ _DEFINE_MEMBER(set_stopped);
+ _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());
+
+ using __get_base_t =
+ __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 _Dp>
+ STDEXEC_ATTRIBUTE((host, device))
+ static __base_t<_Dp> __get_base(_Dp&& __self) noexcept
{
- friend _Derived;
- _DEFINE_MEMBER(set_value);
- _DEFINE_MEMBER(set_error);
- _DEFINE_MEMBER(set_stopped);
- _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());
-
- using __get_base_t =
- __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 _Dp>
- STDEXEC_ATTRIBUTE((host, device))
- static __base_t<_Dp> __get_base(_Dp&& __self) noexcept
+ if constexpr (__has_base)
{
- if constexpr (__has_base)
- {
- return __c_cast<__t>((_Dp&&)__self).base();
- }
- else
- {
- return ((_Dp&&)__self).base();
- }
+ return __c_cast<receiver_adaptor>((_Dp&&)__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(_CALL_MEMBER(set_value, (_Derived&&)__self,
- (_As&&)__as...))>
+ else
{
- static_assert(noexcept(
- _CALL_MEMBER(set_value, (_Derived&&)__self, (_As&&)__as...)));
- _CALL_MEMBER(set_value, (_Derived&&)__self, (_As&&)__as...);
+ return ((_Dp&&)__self).base();
}
+ }
- template <same_as<set_value_t> _SetValue, class _Dp = _Derived,
- class... _As>
- requires _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((_Dp&&)__self), (_As&&)__as...);
- }
+ 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(_CALL_MEMBER(set_value, (_Derived&&)__self,
+ (_As&&)__as...))>
+ {
+ static_assert(noexcept(
+ _CALL_MEMBER(set_value, (_Derived&&)__self, (_As&&)__as...)));
+ _CALL_MEMBER(set_value, (_Derived&&)__self, (_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(_CALL_MEMBER(set_error, (_Derived&&)__self,
- (_Error&&)__err))>
- {
- static_assert(noexcept(
- _CALL_MEMBER(set_error, (_Derived&&)__self, (_Error&&)__err)));
- _CALL_MEMBER(set_error, (_Derived&&)__self, (_Error&&)__err);
- }
+ template <same_as<set_value_t> _SetValue, class _Dp = _Derived,
+ class... _As>
+ requires _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((_Dp&&)__self), (_As&&)__as...);
+ }
- template <same_as<set_error_t> _SetError, class _Error,
- class _Dp = _Derived>
- requires _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((_Derived&&)__self), (_Error&&)__err);
- }
+ 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(_CALL_MEMBER(set_error, (_Derived&&)__self,
+ (_Error&&)__err))>
+ {
+ static_assert(noexcept(
+ _CALL_MEMBER(set_error, (_Derived&&)__self, (_Error&&)__err)));
+ _CALL_MEMBER(set_error, (_Derived&&)__self, (_Error&&)__err);
+ }
- 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(_CALL_MEMBER(set_stopped, (_Dp&&)__self))>
- {
- static_assert(
- noexcept(_CALL_MEMBER(set_stopped, (_Derived&&)__self)));
- _CALL_MEMBER(set_stopped, (_Derived&&)__self);
- }
+ template <same_as<set_error_t> _SetError, class _Error,
+ class _Dp = _Derived>
+ requires _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((_Derived&&)__self), (_Error&&)__err);
+ }
- template <same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
- requires _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((_Derived&&)__self));
- }
+ 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(_CALL_MEMBER(set_stopped, (_Dp&&)__self))>
+ {
+ static_assert(noexcept(_CALL_MEMBER(set_stopped, (_Derived&&)__self)));
+ _CALL_MEMBER(set_stopped, (_Derived&&)__self);
+ }
- // Pass through the get_env receiver query
- template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
- STDEXEC_ATTRIBUTE((host, device, always_inline)) //
+ template <same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
+ requires _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((_Derived&&)__self));
+ }
+
+ // 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(_CALL_MEMBER(get_env, (const _Dp&)__self))
+ {
+ static_assert(noexcept(_CALL_MEMBER(get_env, __self)));
+ return _CALL_MEMBER(get_env, __self);
+ }
+
+ template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
+ requires _MISSING_MEMBER
+ (_Dp, get_env) STDEXEC_ATTRIBUTE((host, device, always_inline)) //
friend auto tag_invoke(_GetEnv, const _Derived& __self) noexcept
- -> decltype(_CALL_MEMBER(get_env, (const _Dp&)__self))
- {
- static_assert(noexcept(_CALL_MEMBER(get_env, __self)));
- return _CALL_MEMBER(get_env, __self);
- }
+ -> env_of_t<__base_t<const _Dp&>>
+ {
+ return stdexec::get_env(__get_base(__self));
+ }
- template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
- requires _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));
- }
+ public:
+ receiver_adaptor() = default;
+ using __adaptor_base<_Base>::__adaptor_base;
- public:
- __t() = default;
- using __adaptor_base<_Base>::__adaptor_base;
-
- using is_receiver = void;
- };
+ using receiver_concept = receiver_t;
};
} // namespace __adaptors
template <__class _Derived, receiver _Base = __adaptors::__not_a_receiver>
-using receiver_adaptor =
- typename __adaptors::receiver_adaptor<_Derived, _Base>::__t;
+using receiver_adaptor = __adaptors::receiver_adaptor<_Derived, _Base>;
template <class _Receiver, class _Fun, class... _As>
concept __receiver_of_invoke_result = //
@@ -3865,112 +2946,10 @@
completion_signatures<__minvoke<__remove<void, __qf<set_value_t>>,
__invoke_result_t<_Fun, _Args...>>>;
-struct __default_get_env_fn
-{
- // BUGBUG This should hide all but the forwarding queries
- template <class _Sender>
- env_of_t<_Sender> operator()(__ignore, __ignore,
- const _Sender& __child) const noexcept
- {
- return get_env(__child);
- }
-
- template <class... _Senders>
- requires(sizeof...(_Senders) != 1)
- empty_env operator()(__ignore, __ignore, const _Senders&...) const noexcept
- {
- return {};
- }
-};
-
-template <class _Tag>
-struct __with_default_get_env
-{
- template <sender_expr_for<_Tag> _Sender>
- static auto get_env(const _Sender& __sndr) noexcept
- -> __call_result_t<__sexpr_apply_t, const _Sender&,
- __default_get_env_fn>
- {
- return __sexpr_apply(__sndr, __default_get_env_fn());
- }
-};
-
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.then]
namespace __then
{
-template <class _ReceiverId, class _Fun>
-struct __receiver
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __data
- {
- _Receiver __rcvr_;
- STDEXEC_ATTRIBUTE((no_unique_address)) _Fun __fun_;
- };
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver;
- __data* __op_;
-
- // Customize set_value by invoking the invocable and passing the result
- // to the downstream receiver
- template <__same_as<set_value_t> _Tag, class... _As>
- requires __invocable<_Fun, _As...> &&
- __receiver_of_invoke_result<_Receiver, _Fun, _As...>
- friend void tag_invoke(_Tag, __t&& __self, _As&&... __as) noexcept
- {
- stdexec::__set_value_invoke((_Receiver&&)__self.__op_->__rcvr_,
- (_Fun&&)__self.__op_->__fun_,
- (_As&&)__as...);
- }
-
- template <__one_of<set_error_t, set_stopped_t> _Tag, class... _As>
- requires __callable<_Tag, _Receiver, _As...>
- friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
- {
- __tag((_Receiver&&)__self.__op_->__rcvr_, (_As&&)__as...);
- }
-
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept
- -> env_of_t<const _Receiver&>
- {
- return get_env(__self.__op_->__rcvr_);
- }
- };
-};
-
-template <class _CvrefSender, class _ReceiverId, class _Fun>
-struct __operation
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using __receiver_id = __receiver<_ReceiverId, _Fun>;
- using __receiver_t = stdexec::__t<__receiver_id>;
-
- struct __t : __immovable
- {
- using __id = __operation;
- typename __receiver_id::__data __data_;
- connect_result_t<_CvrefSender, __receiver_t> __op_;
-
- __t(_CvrefSender&& __sndr, _Receiver __rcvr, _Fun __fun) //
- noexcept(__nothrow_decay_copyable<_Receiver> //
- && __nothrow_decay_copyable<_Fun> //
- && __nothrow_connectable<_CvrefSender, __receiver_t>) :
- __data_{(_Receiver&&)__rcvr, (_Fun&&)__fun},
- __op_(connect((_CvrefSender&&)__sndr, __receiver_t{&__data_}))
- {}
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- start(__self.__op_);
- }
- };
-};
-
inline constexpr __mstring __then_context =
"In stdexec::then(Sender, Function)..."__csz;
using __on_not_callable = __callable_error<__then_context>;
@@ -3984,28 +2963,8 @@
__mbind_front<__mtry_catch_q<__set_value_invoke_t, __on_not_callable>,
_Fun>>;
-template <class _Receiver>
-struct __connect_fn
-{
- _Receiver& __rcvr_;
-
- template <class _Fun, class _Child>
- using __operation_t =
- __t<__operation<_Child, __id<_Receiver>, __decay_t<_Fun>>>;
-
- template <class _Fun, class _Child>
- auto operator()(__ignore, _Fun&& __fun, _Child&& __child) const
- noexcept(__nothrow_constructible_from<__operation_t<_Fun, _Child>,
- _Child, _Receiver, _Fun>)
- -> __operation_t<_Fun, _Child>
- {
- return __operation_t<_Fun, _Child>{(_Child&&)__child,
- (_Receiver&&)__rcvr_, (_Fun&&)__fun};
- }
-};
-
////////////////////////////////////////////////////////////////////////////////////////////////
-struct then_t : __with_default_get_env<then_t>
+struct then_t
{
template <sender _Sender, __movable_value _Fun>
auto operator()(_Sender&& __sndr, _Fun __fun) const
@@ -4030,111 +2989,46 @@
get_env_t(_Sender&)),
_Sender, _Fun),
tag_invoke_t(then_t, _Sender, _Fun)>;
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
- template <sender_expr_for<then_t> _Sender, class _Env>
- static auto get_completion_signatures(_Sender&&, _Env&&)
+struct __then_impl : __sexpr_defaults
+{
+ static constexpr auto get_completion_signatures = //
+ []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
-> __completion_signatures_t<__decay_t<__data_of<_Sender>>,
- __child_of<_Sender>, _Env>
- {
+ __child_of<_Sender>, _Env> {
+ static_assert(sender_expr_for<_Sender, then_t>);
return {};
- }
+ };
- template <sender_expr_for<then_t> _Sender, receiver _Receiver>
- static auto connect(_Sender&& __sndr, _Receiver __rcvr) noexcept(
- __nothrow_callable<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>)
- -> __call_result_t<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>
- {
- return __sexpr_apply((_Sender&&)__sndr,
- __connect_fn<_Receiver>{__rcvr});
- }
+ static constexpr auto complete = //
+ []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
+ _Tag,
+ _Args&&... __args) noexcept -> void {
+ if constexpr (std::same_as<_Tag, set_value_t>)
+ {
+ stdexec::__set_value_invoke(std::move(__rcvr), std::move(__state),
+ (_Args&&)__args...);
+ }
+ else
+ {
+ _Tag()(std::move(__rcvr), (_Args&&)__args...);
+ }
+ };
};
} // namespace __then
using __then::then_t;
inline constexpr then_t then{};
+template <>
+struct __sexpr_impl<then_t> : __then::__then_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.upon_error]
namespace __upon_error
{
-template <class _ReceiverId, class _Fun>
-struct __receiver
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __data
- {
- _Receiver __rcvr_;
- STDEXEC_ATTRIBUTE((no_unique_address)) _Fun __fun_;
- };
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver;
- __data* __op_;
-
- // Customize set_value by invoking the invocable and passing the result
- // to the downstream receiver
- template <__same_as<set_error_t> _Tag, class _Error>
- requires __invocable<_Fun, _Error> &&
- __receiver_of_invoke_result<_Receiver, _Fun, _Error>
- friend void tag_invoke(_Tag, __t&& __self, _Error&& __error) noexcept
- {
- stdexec::__set_value_invoke((_Receiver&&)__self.__op_->__rcvr_,
- (_Fun&&)__self.__op_->__fun_,
- (_Error&&)__error);
- }
-
- template <__one_of<set_value_t, set_stopped_t> _Tag, class... _As>
- requires __callable<_Tag, _Receiver, _As...>
- friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
- {
- __tag((_Receiver&&)__self.__op_->__rcvr_, (_As&&)__as...);
- }
-
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept
- -> env_of_t<const _Receiver&>
- {
- return get_env(__self.__op_->__rcvr_);
- }
- };
-};
-
-template <class _CvrefSender, class _ReceiverId, class _Fun>
-struct __operation
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using __receiver_id = __receiver<_ReceiverId, _Fun>;
- using __receiver_t = stdexec::__t<__receiver_id>;
-
- struct __t : __immovable
- {
- using __id = __operation;
- typename __receiver_id::__data __data_;
- connect_result_t<_CvrefSender, __receiver_t> __op_;
-
- __t(_CvrefSender&& __sndr, _Receiver __rcvr, _Fun __fun) //
- noexcept(__nothrow_decay_copyable<_Receiver> //
- && __nothrow_decay_copyable<_Fun> //
- && __nothrow_connectable<_CvrefSender, __receiver_t>) :
- __data_{(_Receiver&&)__rcvr, (_Fun&&)__fun},
- __op_(connect((_CvrefSender&&)__sndr, __receiver_t{&__data_}))
- {}
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- start(__self.__op_);
- }
- };
-};
-
inline constexpr __mstring __upon_error_context =
"In stdexec::upon_error(Sender, Function)..."__csz;
using __on_not_callable = __callable_error<__upon_error_context>;
@@ -4149,28 +3043,8 @@
__mbind_front<__mtry_catch_q<__set_value_invoke_t, __on_not_callable>,
_Fun>>;
-template <class _Receiver>
-struct __connect_fn
-{
- _Receiver& __rcvr_;
-
- template <class _Fun, class _Child>
- using __operation_t =
- __t<__operation<_Child, __id<_Receiver>, __decay_t<_Fun>>>;
-
- template <class _Fun, class _Child>
- auto operator()(__ignore, _Fun&& __fun, _Child&& __child) const
- noexcept(__nothrow_constructible_from<__operation_t<_Fun, _Child>,
- _Child, _Receiver, _Fun>)
- -> __operation_t<_Fun, _Child>
- {
- return __operation_t<_Fun, _Child>{(_Child&&)__child,
- (_Receiver&&)__rcvr_, (_Fun&&)__fun};
- }
-};
-
////////////////////////////////////////////////////////////////////////////////////////////////
-struct upon_error_t : __with_default_get_env<upon_error_t>
+struct upon_error_t
{
template <sender _Sender, __movable_value _Fun>
auto operator()(_Sender&& __sndr, _Fun __fun) const
@@ -4196,110 +3070,46 @@
get_env_t(_Sender&)),
_Sender, _Fun),
tag_invoke_t(upon_error_t, _Sender, _Fun)>;
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
- template <sender_expr_for<upon_error_t> _Sender, class _Env>
- static auto get_completion_signatures(_Sender&&, _Env&&)
+struct __upon_error_impl : __sexpr_defaults
+{
+ static constexpr auto get_completion_signatures = //
+ []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
-> __completion_signatures_t<__decay_t<__data_of<_Sender>>,
- __child_of<_Sender>, _Env>
- {
+ __child_of<_Sender>, _Env> {
+ static_assert(sender_expr_for<_Sender, upon_error_t>);
return {};
- }
+ };
- template <sender_expr_for<upon_error_t> _Sender, receiver _Receiver>
- static auto connect(_Sender&& __sndr, _Receiver __rcvr) noexcept(
- __nothrow_callable<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>)
- -> __call_result_t<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>
- {
- return __sexpr_apply((_Sender&&)__sndr,
- __connect_fn<_Receiver>{__rcvr});
- }
+ static constexpr auto complete = //
+ []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
+ _Tag,
+ _Args&&... __args) noexcept -> void {
+ if constexpr (std::same_as<_Tag, set_error_t>)
+ {
+ stdexec::__set_value_invoke(std::move(__rcvr), std::move(__state),
+ (_Args&&)__args...);
+ }
+ else
+ {
+ _Tag()(std::move(__rcvr), (_Args&&)__args...);
+ }
+ };
};
} // namespace __upon_error
using __upon_error::upon_error_t;
inline constexpr upon_error_t upon_error{};
+template <>
+struct __sexpr_impl<upon_error_t> : __upon_error::__upon_error_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.upon_stopped]
namespace __upon_stopped
{
-template <class _ReceiverId, class _Fun>
-struct __receiver
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __data
- {
- _Receiver __rcvr_;
- STDEXEC_ATTRIBUTE((no_unique_address)) _Fun __fun_;
- };
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver;
- __data* __op_;
-
- // Customize set_value by invoking the invocable and passing the result
- // to the downstream receiver
- template <__same_as<set_stopped_t> _Tag>
- requires __invocable<_Fun> &&
- __receiver_of_invoke_result<_Receiver, _Fun>
- friend void tag_invoke(_Tag, __t&& __self) noexcept
- {
- stdexec::__set_value_invoke((_Receiver&&)__self.__op_->__rcvr_,
- (_Fun&&)__self.__op_->__fun_);
- }
-
- template <__one_of<set_value_t, set_error_t> _Tag, class... _As>
- requires __callable<_Tag, _Receiver, _As...>
- friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
- {
- __tag((_Receiver&&)__self.__op_->__rcvr_, (_As&&)__as...);
- }
-
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept
- -> env_of_t<const _Receiver&>
- {
- return get_env(__self.__op_->__rcvr_);
- }
- };
-};
-
-template <class _CvrefSender, class _ReceiverId, class _Fun>
-struct __operation
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using __receiver_id = __receiver<_ReceiverId, _Fun>;
- using __receiver_t = stdexec::__t<__receiver_id>;
-
- struct __t : __immovable
- {
- using __id = __operation;
- typename __receiver_id::__data __data_;
- connect_result_t<_CvrefSender, __receiver_t> __op_;
-
- __t(_CvrefSender&& __sndr, _Receiver __rcvr, _Fun __fun) //
- noexcept(__nothrow_decay_copyable<_Receiver> //
- && __nothrow_decay_copyable<_Fun> //
- && __nothrow_connectable<_CvrefSender, __receiver_t>) :
- __data_{(_Receiver&&)__rcvr, (_Fun&&)__fun},
- __op_(connect((_CvrefSender&&)__sndr, __receiver_t{&__data_}))
- {}
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- start(__self.__op_);
- }
- };
-};
-
inline constexpr __mstring __upon_stopped_context =
"In stdexec::upon_stopped(Sender, Function)..."__csz;
using __on_not_callable = __callable_error<__upon_stopped_context>;
@@ -4313,28 +3123,8 @@
__q<__compl_sigs::__default_set_value>,
__q<__compl_sigs::__default_set_error>, __set_value_invoke_t<_Fun>>;
-template <class _Receiver>
-struct __connect_fn
-{
- _Receiver& __rcvr_;
-
- template <class _Fun, class _Child>
- using __operation_t =
- __t<__operation<_Child, __id<_Receiver>, __decay_t<_Fun>>>;
-
- template <class _Fun, class _Child>
- auto operator()(__ignore, _Fun&& __fun, _Child&& __child) const
- noexcept(__nothrow_constructible_from<__operation_t<_Fun, _Child>,
- _Child, _Receiver, _Fun>)
- -> __operation_t<_Fun, _Child>
- {
- return __operation_t<_Fun, _Child>{(_Child&&)__child,
- (_Receiver&&)__rcvr_, (_Fun&&)__fun};
- }
-};
-
////////////////////////////////////////////////////////////////////////////////////////////////
-struct upon_stopped_t : __with_default_get_env<upon_stopped_t>
+struct upon_stopped_t
{
template <sender _Sender, __movable_value _Fun>
requires __callable<_Fun>
@@ -4363,35 +3153,42 @@
get_env_t(_Sender&)),
_Sender, _Fun),
tag_invoke_t(upon_stopped_t, _Sender, _Fun)>;
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
- template <sender_expr_for<upon_stopped_t> _Sender, class _Env>
- static auto get_completion_signatures(_Sender&&, _Env&&)
+struct __upon_stopped_impl : __sexpr_defaults
+{
+ static constexpr auto get_completion_signatures = //
+ []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
-> __completion_signatures_t<__decay_t<__data_of<_Sender>>,
- __child_of<_Sender>, _Env>
- {
+ __child_of<_Sender>, _Env> {
+ static_assert(sender_expr_for<_Sender, upon_stopped_t>);
return {};
- }
+ };
- template <sender_expr_for<upon_stopped_t> _Sender, receiver _Receiver>
- static auto connect(_Sender&& __sndr, _Receiver __rcvr) noexcept(
- __nothrow_callable<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>)
- -> __call_result_t<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>
- {
- return __sexpr_apply((_Sender&&)__sndr,
- __connect_fn<_Receiver>{__rcvr});
- }
+ static constexpr auto complete = //
+ []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
+ _Tag,
+ _Args&&... __args) noexcept -> void {
+ if constexpr (std::same_as<_Tag, set_stopped_t>)
+ {
+ stdexec::__set_value_invoke(std::move(__rcvr), std::move(__state),
+ (_Args&&)__args...);
+ }
+ else
+ {
+ _Tag()(std::move(__rcvr), (_Args&&)__args...);
+ }
+ };
};
} // namespace __upon_stopped
using __upon_stopped::upon_stopped_t;
inline constexpr upon_stopped_t upon_stopped{};
+template <>
+struct __sexpr_impl<upon_stopped_t> : __upon_stopped::__upon_stopped_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.bulk]
namespace __bulk
@@ -4411,110 +3208,6 @@
template <class _Shape, class _Fun>
__data(_Shape, _Fun) -> __data<_Shape, _Fun>;
-template <class _ReceiverId, class _Shape, class _Fun>
-struct __receiver
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __op_state : __data<_Shape, _Fun>
- {
- STDEXEC_ATTRIBUTE((no_unique_address)) _Receiver __rcvr_;
- };
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver;
- __op_state* __op_;
-
- template <same_as<set_value_t> _Tag, class... _As>
- requires __callable<_Tag, _Receiver, _As...>
- friend void tag_invoke(_Tag, __t&& __self, _As&&... __as) noexcept
- requires __nothrow_callable<_Fun, _Shape, _As&...>
- {
- for (_Shape __i{}; __i != __self.__op_->__shape_; ++__i)
- {
- __self.__op_->__fun_(__i, __as...);
- }
- stdexec::set_value((_Receiver&&)__self.__op_->__rcvr_,
- (_As&&)__as...);
- }
-
- template <same_as<set_value_t> _Tag, class... _As>
- requires __callable<_Tag, _Receiver, _As...>
- friend void tag_invoke(_Tag, __t&& __self, _As&&... __as) noexcept
- requires __callable<_Fun, _Shape, _As&...>
- {
- try
- {
- for (_Shape __i{}; __i != __self.__op_->__shape_; ++__i)
- {
- __self.__op_->__fun_(__i, __as...);
- }
- stdexec::set_value((_Receiver&&)__self.__op_->__rcvr_,
- (_As&&)__as...);
- }
- catch (...)
- {
- stdexec::set_error((_Receiver&&)__self.__op_->__rcvr_,
- std::current_exception());
- }
- }
-
- template <same_as<set_error_t> _Tag, class _Error>
- requires __callable<_Tag, _Receiver, _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>
- requires __callable<_Tag, _Receiver>
- friend void tag_invoke(_Tag, __t&& __self) noexcept
- {
- stdexec::set_stopped((_Receiver&&)__self.__op_->__rcvr_);
- }
-
- friend env_of_t<_Receiver> tag_invoke(get_env_t,
- const __t& __self) noexcept
- {
- return stdexec::get_env(__self.__op_->__rcvr_);
- }
- };
-};
-
-template <class _CvrefSenderId, class _ReceiverId, class _Shape, class _Fun>
-struct __operation
-{
- using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
- using _Receiver = stdexec::__t<_ReceiverId>;
- using __receiver_id = __receiver<_ReceiverId, _Shape, _Fun>;
- using __receiver_t = stdexec::__t<__receiver_id>;
-
- struct __t : __immovable
- {
- using __id = __operation;
- using __data_t = __data<_Shape, _Fun>;
-
- typename __receiver_id::__op_state __state_;
- connect_result_t<_CvrefSender, __receiver_t> __op_;
-
- __t(_CvrefSender&& __sndr, _Receiver __rcvr, __data_t __data) //
- noexcept(__nothrow_decay_copyable<_Receiver> //
- && __nothrow_decay_copyable<__data_t> //
- && __nothrow_connectable<_CvrefSender, __receiver_t>) :
- __state_{(__data_t&&)__data, (_Receiver&&)__rcvr},
- __op_(connect((_CvrefSender&&)__sndr, __receiver_t{&__state_}))
- {}
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- start(__self.__op_);
- }
- };
-};
-
template <class _Ty>
using __decay_ref = __decay_t<_Ty>&;
@@ -4536,28 +3229,7 @@
__with_error_invoke_t<_CvrefSender, _Env, _Shape, _Fun,
__on_not_callable>>;
-template <class _Receiver>
-struct __connect_fn
-{
- _Receiver& __rcvr_;
-
- template <class _Child, class _Data>
- using __operation_t = //
- __t<__operation<__cvref_id<_Child>, __id<_Receiver>,
- decltype(_Data::__shape_), decltype(_Data::__fun_)>>;
-
- template <class _Data, class _Child>
- auto operator()(__ignore, _Data __data, _Child&& __child) const
- noexcept(__nothrow_constructible_from<__operation_t<_Child, _Data>,
- _Child, _Receiver, _Data>)
- -> __operation_t<_Child, _Data>
- {
- return __operation_t<_Child, _Data>{
- (_Child&&)__child, (_Receiver&&)__rcvr_, (_Data&&)__data};
- }
-};
-
-struct bulk_t : __with_default_get_env<bulk_t>
+struct bulk_t
{
template <sender _Sender, integral _Shape, __movable_value _Fun>
STDEXEC_ATTRIBUTE((host, device))
@@ -4588,72 +3260,157 @@
get_env_t(_Sender&)),
_Sender, _Shape, _Fun),
tag_invoke_t(bulk_t, _Sender, _Shape, _Fun)>;
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
+struct __bulk_impl : __sexpr_defaults
+{
template <class _Sender>
using __fun_t = decltype(__decay_t<__data_of<_Sender>>::__fun_);
template <class _Sender>
using __shape_t = decltype(__decay_t<__data_of<_Sender>>::__shape_);
- template <sender_expr_for<bulk_t> _Sender, class _Env>
- static auto get_completion_signatures(_Sender&&, _Env&&)
+ static constexpr auto get_completion_signatures = //
+ []<class _Sender, class _Env>(_Sender&&, _Env&&) noexcept
-> __completion_signatures<__child_of<_Sender>, _Env,
- __shape_t<_Sender>, __fun_t<_Sender>>
- {
+ __shape_t<_Sender>, __fun_t<_Sender>> {
+ static_assert(sender_expr_for<_Sender, bulk_t>);
return {};
- }
+ };
- template <sender_expr_for<bulk_t> _Sender, receiver _Receiver>
- static auto connect(_Sender&& __sndr, _Receiver __rcvr) noexcept(
- __nothrow_callable<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>)
- -> __call_result_t<__sexpr_apply_t, _Sender, __connect_fn<_Receiver>>
- {
- return __sexpr_apply((_Sender&&)__sndr,
- __connect_fn<_Receiver>{__rcvr});
- }
+ static constexpr auto complete = //
+ []<class _Tag, class... _Args>(__ignore, auto& __state, auto& __rcvr,
+ _Tag,
+ _Args&&... __args) noexcept -> void {
+ if constexpr (std::same_as<_Tag, set_value_t>)
+ {
+ using __shape_t = decltype(__state.__shape_);
+ if constexpr (noexcept(__state.__fun_(__shape_t{}, __args...)))
+ {
+ for (__shape_t __i{}; __i != __state.__shape_; ++__i)
+ {
+ __state.__fun_(__i, __args...);
+ }
+ _Tag()(std::move(__rcvr), (_Args&&)__args...);
+ }
+ else
+ {
+ try
+ {
+ for (__shape_t __i{}; __i != __state.__shape_; ++__i)
+ {
+ __state.__fun_(__i, __args...);
+ }
+ _Tag()(std::move(__rcvr), (_Args&&)__args...);
+ }
+ catch (...)
+ {
+ set_error(std::move(__rcvr), std::current_exception());
+ }
+ }
+ }
+ else
+ {
+ _Tag()(std::move(__rcvr), (_Args&&)__args...);
+ }
+ };
};
} // namespace __bulk
using __bulk::bulk_t;
inline constexpr bulk_t bulk{};
+template <>
+struct __sexpr_impl<bulk_t> : __bulk::__bulk_impl
+{};
+
////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.split]
namespace __split
{
+struct __on_stop_request
+{
+ in_place_stop_source& __stop_source_;
+
+ void operator()() noexcept
+ {
+ __stop_source_.request_stop();
+ }
+};
+
+template <class _Receiver>
+auto __notify_visitor(_Receiver&& __rcvr) noexcept
+{
+ return [&](const auto& __tupl) noexcept -> void {
+ __apply(
+ [&](auto __tag, const auto&... __args) noexcept -> void {
+ __tag(std::move(__rcvr), __args...);
+ },
+ __tupl);
+ };
+}
+
+struct __split_state_base : __immovable
+{
+ using __notify_fn = void(__split_state_base*) noexcept;
+
+ __split_state_base* __next_{};
+ __notify_fn* __notify_{};
+};
+
+template <class _Sender, class _Receiver>
+struct __split_state :
+ __split_state_base,
+ __enable_receiver_from_this<_Sender, _Receiver>
+{
+ using __shared_state_ptr = __decay_t<__data_of<_Sender>>;
+ using __on_stop_cb = //
+ typename stop_token_of_t<env_of_t<_Receiver>&>::template callback_type<
+ __on_stop_request>;
+
+ explicit __split_state(_Sender&& __sndr) noexcept :
+ __split_state_base{{}, nullptr, __notify}, __on_stop_(),
+ __shared_state_(STDEXEC_CALL_EXPLICIT_THIS_MEMFN(
+ (_Sender&&)__sndr, apply)(__detail::__get_data()))
+ {}
+
+ static void __notify(__split_state_base* __self) noexcept
+ {
+ __split_state* __op = static_cast<__split_state*>(__self);
+ __op->__on_stop_.reset();
+ std::visit(__split::__notify_visitor(__op->__receiver()),
+ __op->__shared_state_->__data_);
+ }
+
+ std::optional<__on_stop_cb> __on_stop_;
+ __shared_state_ptr __shared_state_;
+};
+
+template <class _CvrefSender, class _Env>
+struct __sh_state;
+
template <class _BaseEnv>
using __env_t = //
__make_env_t<_BaseEnv, // BUGBUG NOT TO SPEC
__with<get_stop_token_t, in_place_stop_token>>;
template <class _CvrefSenderId, class _EnvId>
-struct __sh_state;
-
-template <class _CvrefSenderId, class _EnvId>
struct __receiver
{
using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
using _Env = stdexec::__t<_EnvId>;
- class __t
+ struct __t
{
- stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>& __sh_state_;
+ __sh_state<_CvrefSender, _Env>& __sh_state_;
- public:
- using is_receiver = void;
+ using receiver_concept = receiver_t;
using __id = __receiver;
template <__completion_tag _Tag, class... _As>
friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
{
- stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>& __state =
- __self.__sh_state_;
+ __sh_state<_CvrefSender, _Env>& __state = __self.__sh_state_;
try
{
@@ -4676,252 +3433,83 @@
{
return __self.__sh_state_.__env_;
}
-
- explicit __t(stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>&
- __sh_state) noexcept :
- __sh_state_(__sh_state)
- {}
};
};
-struct __operation_base
-{
- using __notify_fn = void(__operation_base*) noexcept;
-
- __operation_base* __next_{};
- __notify_fn* __notify_{};
-};
-
-template <class _CvrefSenderId, class _EnvId = __id<empty_env>>
+template <class _CvrefSender, class _Env = empty_env>
struct __sh_state
{
- using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
- using _Env = stdexec::__t<_EnvId>;
+ using __t = __sh_state;
+ using __id = __sh_state;
- struct __t
+ template <class... _Ts>
+ using __bind_tuples = //
+ __mbind_front_q<__variant,
+ std::tuple<set_stopped_t>, // Initial state of the
+ // variant is set_stopped
+ std::tuple<set_error_t, std::exception_ptr>, _Ts...>;
+
+ using __bound_values_t = //
+ __value_types_of_t<_CvrefSender, __env_t<_Env>,
+ __mbind_front_q<__decayed_tuple, set_value_t>,
+ __q<__bind_tuples>>;
+
+ using __variant_t = //
+ __error_types_of_t<
+ _CvrefSender, __env_t<_Env>,
+ __transform<__mbind_front_q<__decayed_tuple, set_error_t>,
+ __bound_values_t>>;
+
+ using __receiver_t =
+ stdexec::__t<__receiver<__cvref_id<_CvrefSender>, stdexec::__id<_Env>>>;
+
+ in_place_stop_source __stop_source_{};
+ __variant_t __data_;
+ std::atomic<void*> __head_{nullptr};
+ __env_t<_Env> __env_;
+ connect_result_t<_CvrefSender, __receiver_t> __op_state2_;
+
+ explicit __sh_state(_CvrefSender&& __sndr, _Env __env = {}) :
+ __env_(__make_env((_Env&&)__env, __mkprop(__stop_source_.get_token(),
+ get_stop_token))),
+ __op_state2_(connect((_CvrefSender&&)__sndr, __receiver_t{*this}))
+ {}
+
+ void __notify() noexcept
{
- using __id = __sh_state;
+ void* const __completion_state = static_cast<void*>(this);
+ void* __old = __head_.exchange(__completion_state,
+ std::memory_order_acq_rel);
+ __split_state_base* __state = static_cast<__split_state_base*>(__old);
- template <class... _Ts>
- using __bind_tuples = //
- __mbind_front_q<__variant,
- std::tuple<set_stopped_t>, // Initial state of the
- // variant is set_stopped
- std::tuple<set_error_t, std::exception_ptr>,
- _Ts...>;
-
- using __bound_values_t = //
- __value_types_of_t<_CvrefSender, __env_t<_Env>,
- __mbind_front_q<__decayed_tuple, set_value_t>,
- __q<__bind_tuples>>;
-
- using __variant_t = //
- __error_types_of_t<
- _CvrefSender, __env_t<_Env>,
- __transform<__mbind_front_q<__decayed_tuple, set_error_t>,
- __bound_values_t>>;
-
- using __receiver_ = stdexec::__t<__receiver<_CvrefSenderId, _EnvId>>;
-
- in_place_stop_source __stop_source_{};
- __variant_t __data_;
- std::atomic<void*> __head_{nullptr};
- __env_t<_Env> __env_;
- connect_result_t<_CvrefSender, __receiver_> __op_state2_;
-
- explicit __t(_CvrefSender&& __sndr, _Env __env = {}) :
- __env_(
- __make_env((_Env&&)__env, __mkprop(__stop_source_.get_token(),
- get_stop_token))),
- __op_state2_(connect((_CvrefSender&&)__sndr, __receiver_{*this}))
- {}
-
- void __notify() noexcept
+ while (__state != nullptr)
{
- void* const __completion_state = static_cast<void*>(this);
- void* __old = __head_.exchange(__completion_state,
- std::memory_order_acq_rel);
- __operation_base* __op_state =
- static_cast<__operation_base*>(__old);
-
- while (__op_state != nullptr)
- {
- __operation_base* __next = __op_state->__next_;
- __op_state->__notify_(__op_state);
- __op_state = __next;
- }
+ __split_state_base* __next = __state->__next_;
+ __state->__notify_(__state);
+ __state = __next;
}
- };
+ }
};
-template <class _CvrefSenderId, class _EnvId, class _ReceiverId>
- requires sender_to<__cvref_t<_CvrefSenderId>,
- __t<__receiver<_CvrefSenderId, _EnvId>>>
-struct __operation
-{
- using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
- using _Env = stdexec::__t<_EnvId>;
- using _Receiver = stdexec::__t<_ReceiverId>;
+template <class... _Tys>
+using __set_value_t =
+ completion_signatures<set_value_t(const __decay_t<_Tys>&...)>;
- class __t : public __operation_base
- {
- struct __on_stop_requested
- {
- in_place_stop_source& __stop_source_;
+template <class _Ty>
+using __set_error_t = completion_signatures<set_error_t(const __decay_t<_Ty>&)>;
- void operator()() noexcept
- {
- __stop_source_.request_stop();
- }
- };
-
- using __on_stop = //
- std::optional<typename stop_token_of_t<env_of_t<_Receiver>&>::
- template callback_type<__on_stop_requested>>;
-
- _Receiver __rcvr_;
- __on_stop __on_stop_{};
- std::shared_ptr<stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>>
- __shared_state_;
-
- public:
- using __id = __operation;
-
- __t( //
- _Receiver&& __rcvr,
- std::shared_ptr<stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>>
- __shared_state) //
- noexcept(std::is_nothrow_move_constructible_v<_Receiver>) :
- __operation_base{nullptr, __notify},
- __rcvr_((_Receiver&&)__rcvr),
- __shared_state_(std::move(__shared_state))
- {}
-
- STDEXEC_IMMOVABLE(__t);
-
- static void __notify(__operation_base* __self) noexcept
- {
- __t* __op = static_cast<__t*>(__self);
- __op->__on_stop_.reset();
-
- std::visit(
- [&](const auto& __tupl) noexcept -> void {
- __apply(
- [&](auto __tag, const auto&... __args) noexcept -> void {
- __tag((_Receiver&&)__op->__rcvr_, __args...);
- },
- __tupl);
- },
- __op->__shared_state_->__data_);
- }
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>* __shared_state =
- __self.__shared_state_.get();
- std::atomic<void*>& __head = __shared_state->__head_;
- void* const __completion_state = static_cast<void*>(__shared_state);
- void* __old = __head.load(std::memory_order_acquire);
-
- if (__old != __completion_state)
- {
- __self.__on_stop_.emplace(
- get_stop_token(get_env(__self.__rcvr_)),
- __on_stop_requested{__shared_state->__stop_source_});
- }
-
- do
- {
- if (__old == __completion_state)
- {
- __self.__notify(&__self);
- return;
- }
- __self.__next_ = static_cast<__operation_base*>(__old);
- } while (!__head.compare_exchange_weak(
- __old, static_cast<void*>(&__self), std::memory_order_release,
- std::memory_order_acquire));
-
- if (__old == nullptr)
- {
- // the inner sender isn't running
- if (__shared_state->__stop_source_.stop_requested())
- {
- // 1. resets __head to completion state
- // 2. notifies waiting threads
- // 3. propagates "stopped" signal to `out_r'`
- __shared_state->__notify();
- }
- else
- {
- start(__shared_state->__op_state2_);
- }
- }
- }
- };
-};
+template <class _CvrefSenderId, class _EnvId>
+using __completions_t = //
+ __try_make_completion_signatures<
+ // NOT TO SPEC:
+ // See https://github.com/brycelelbach/wg21_p2300_execution/issues/26
+ __cvref_t<_CvrefSenderId>, __env_t<__t<_EnvId>>,
+ completion_signatures<set_error_t(const std::exception_ptr&),
+ set_stopped_t()>, // NOT TO SPEC
+ __q<__set_value_t>, __q<__set_error_t>>;
struct __split_t
-{
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
- template <class... _Tys>
- using __set_value_t =
- completion_signatures<set_value_t(const __decay_t<_Tys>&...)>;
-
- template <class _Ty>
- using __set_error_t =
- completion_signatures<set_error_t(const __decay_t<_Ty>&)>;
-
- template <class _CvrefSenderId, class _EnvId>
- using __completions_t = //
- __try_make_completion_signatures<
- // NOT TO SPEC:
- // See
- // https://github.com/brycelelbach/wg21_p2300_execution/issues/26
- __cvref_t<_CvrefSenderId>, __env_t<__t<_EnvId>>,
- completion_signatures<set_error_t(const std::exception_ptr&),
- set_stopped_t()>, // NOT TO SPEC
- __q<__set_value_t>, __q<__set_error_t>>;
-
- static inline constexpr auto __connect_fn =
- []<class _Receiver>(_Receiver& __rcvr) noexcept {
- return
- [&]<class _ShState>(auto, std::shared_ptr<_ShState> __sh_state) //
- noexcept(__nothrow_decay_copyable<_Receiver>)
- -> __t<__mapply<__mbind_back_q<__operation, __id<_Receiver>>,
- __id<_ShState>>> {
- return {(_Receiver&&)__rcvr, std::move(__sh_state)};
- };
- };
-
- static inline constexpr auto __get_completion_signatures_fn =
- []<class _ShState>(auto, const std::shared_ptr<_ShState>&) //
- -> __mapply<__q<__completions_t>, __id<_ShState>> { return {}; };
-
- template <sender_expr_for<__split_t> _Self, class _Receiver>
- static auto connect(_Self&& __self, _Receiver __rcvr) noexcept(
- __nothrow_callable<
- __sexpr_apply_t, _Self,
- __call_result_t<__mtypeof<__connect_fn>, _Receiver&>>)
- -> __call_result_t<__sexpr_apply_t, _Self,
- __call_result_t<__mtypeof<__connect_fn>, _Receiver&>>
- {
- return __sexpr_apply((_Self&&)__self, __connect_fn(__rcvr));
- }
-
- template <sender_expr_for<__split_t> _Self, class _OtherEnv>
- static auto get_completion_signatures(_Self&&, _OtherEnv&&)
- -> __call_result_t<__sexpr_apply_t, _Self,
- __mtypeof<__get_completion_signatures_fn>>
- {
- return {};
- }
-};
+{};
struct split_t : __split_t
{
@@ -4965,19 +3553,94 @@
return __sexpr_apply(
(_Sender&&)__sndr,
[&]<class _Child>(__ignore, __ignore, _Child&& __child) {
- using __sh_state_t =
- __t<__sh_state<__cvref_id<_Child>, __id<_Env>...>>;
+ using __sh_state_t = __sh_state<_Child, _Env...>;
auto __sh_state = std::make_shared<__sh_state_t>(
(_Child&&)__child, std::move(__env)...);
return __make_sexpr<__split_t>(std::move(__sh_state));
});
}
};
+
+struct __split_impl : __sexpr_defaults
+{
+ static constexpr auto get_state = //
+ []<class _Sender, class _Receiver>(
+ _Sender&& __sndr,
+ _Receiver&) noexcept -> __split_state<_Sender, _Receiver> {
+ static_assert(sender_expr_for<_Sender, __split_t>);
+ return __split_state<_Sender, _Receiver>{(_Sender&&)__sndr};
+ };
+
+ static constexpr auto start = //
+ []<class _Sender, class _Receiver>(
+ __split_state<_Sender, _Receiver>& __state,
+ _Receiver& __rcvr) noexcept -> void {
+ auto* __shared_state = __state.__shared_state_.get();
+ std::atomic<void*>& __head = __shared_state->__head_;
+ void* const __completion_state = static_cast<void*>(__shared_state);
+ void* __old = __head.load(std::memory_order_acquire);
+
+ if (__old != __completion_state)
+ {
+ __state.__on_stop_.emplace(
+ get_stop_token(stdexec::get_env(__rcvr)),
+ __on_stop_request{__shared_state->__stop_source_});
+ }
+
+ do
+ {
+ if (__old == __completion_state)
+ {
+ __state.__notify(&__state);
+ return;
+ }
+ __state.__next_ = static_cast<__split_state_base*>(__old);
+ } while (!__head.compare_exchange_weak(
+ __old, static_cast<void*>(&__state), std::memory_order_release,
+ std::memory_order_acquire));
+
+ if (__old == nullptr)
+ {
+ // the inner sender isn't running
+ if (__shared_state->__stop_source_.stop_requested())
+ {
+ // 1. resets __head to completion state
+ // 2. notifies waiting threads
+ // 3. propagates "stopped" signal to `out_r'`
+ __shared_state->__notify();
+ }
+ else
+ {
+ stdexec::start(__shared_state->__op_state2_);
+ }
+ }
+ };
+
+ static constexpr auto __get_completion_signatures_fn = //
+ []<class _ShState>(auto, const std::shared_ptr<_ShState>&) //
+ -> __mapply<__q<__completions_t>, __id<_ShState>> { return {}; };
+
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _OtherEnv>(_Self&&, _OtherEnv&&) noexcept
+ -> __call_result_t<__sexpr_apply_t, _Self,
+ __mtypeof<__get_completion_signatures_fn>> {
+ static_assert(sender_expr_for<_Self, __split_t>);
+ return {};
+ };
+};
} // namespace __split
using __split::split_t;
inline constexpr split_t split{};
+template <>
+struct __sexpr_impl<__split::__split_t> : __split::__split_impl
+{};
+
+template <>
+struct __sexpr_impl<split_t> : __split::__split_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.ensure_started]
namespace __ensure_started
@@ -5002,7 +3665,7 @@
__shared_state_;
public:
- using is_receiver = void;
+ using receiver_concept = receiver_t;
using __id = __receiver;
explicit __t(stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>&
@@ -5123,7 +3786,7 @@
class __t : public __operation_base
{
- struct __on_stop_requested
+ struct __on_stop_request
{
in_place_stop_source& __stop_source_;
@@ -5135,7 +3798,7 @@
using __on_stop = //
std::optional<typename stop_token_of_t<env_of_t<_Receiver>&>::
- template callback_type<__on_stop_requested>>;
+ template callback_type<__on_stop_request>>;
_Receiver __rcvr_;
__on_stop __on_stop_{};
@@ -5200,7 +3863,7 @@
// register stop callback:
__self.__on_stop_.emplace(
get_stop_token(get_env(__self.__rcvr_)),
- __on_stop_requested{__shared_state->__stop_source_});
+ __on_stop_request{__shared_state->__stop_source_});
// Check if the stop_source has requested cancellation
if (__shared_state->__stop_source_.stop_requested())
{
@@ -5252,68 +3915,74 @@
__intrusive_ptr<_ShState> __sh_state_;
};
-struct __ensure_started_t
+template <class... _Tys>
+using __set_value_t = completion_signatures<set_value_t(__decay_t<_Tys>&&...)>;
+
+template <class _Ty>
+using __set_error_t = completion_signatures<set_error_t(__decay_t<_Ty>&&)>;
+
+template <class _CvrefSenderId, class _EnvId>
+using __completions_t = //
+ __try_make_completion_signatures<
+ // NOT TO SPEC:
+ // See https://github.com/brycelelbach/wg21_p2300_execution/issues/26
+ __cvref_t<_CvrefSenderId>, __env_t<__t<_EnvId>>,
+ completion_signatures<set_error_t(std::exception_ptr&&),
+ set_stopped_t()>, // NOT TO SPEC
+ __q<__set_value_t>, __q<__set_error_t>>;
+
+template <class _Receiver>
+auto __connect_fn_(_Receiver& __rcvr) noexcept
{
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
- friend struct ensure_started_t;
-#endif
+ return [&]<class _ShState>(auto, __data<_ShState> __dat) //
+ noexcept(__nothrow_decay_copyable<_Receiver>)
+ -> __t<__mapply<__mbind_back_q<__operation, __id<_Receiver>>,
+ __id<_ShState>>> {
+ return {(_Receiver&&)__rcvr, std::move(__dat.__sh_state_)};
+ };
+}
- template <class... _Tys>
- using __set_value_t =
- completion_signatures<set_value_t(__decay_t<_Tys>&&...)>;
+template <class _Receiver>
+auto __connect_fn(_Receiver& __rcvr) noexcept -> decltype(__connect_fn_(__rcvr))
+{
+ return __connect_fn_(__rcvr);
+}
- template <class _Ty>
- using __set_error_t = completion_signatures<set_error_t(__decay_t<_Ty>&&)>;
+inline auto __get_completion_signatures_fn() noexcept
+{
+ return []<class _ShState>(auto, const __data<_ShState>&) //
+ -> __mapply<__q<__completions_t>, __id<_ShState>> { return {}; };
+}
- template <class _CvrefSenderId, class _EnvId>
- using __completions_t = //
- __try_make_completion_signatures<
- // NOT TO SPEC:
- // See
- // https://github.com/brycelelbach/wg21_p2300_execution/issues/26
- __cvref_t<_CvrefSenderId>, __env_t<__t<_EnvId>>,
- completion_signatures<set_error_t(std::exception_ptr&&),
- set_stopped_t()>, // NOT TO SPEC
- __q<__set_value_t>, __q<__set_error_t>>;
+struct __ensure_started_t
+{};
- static inline constexpr auto __connect_fn =
- []<class _Receiver>(_Receiver& __rcvr) noexcept {
- return [&]<class _ShState>(auto, __data<_ShState> __dat) //
- noexcept(__nothrow_decay_copyable<_Receiver>)
- -> __t<__mapply<__mbind_back_q<__operation, __id<_Receiver>>,
- __id<_ShState>>> {
- return {(_Receiver&&)__rcvr, std::move(__dat.__sh_state_)};
- };
+struct __ensure_started_impl : __sexpr_defaults
+{
+ static constexpr auto connect = //
+ []<class _Self, class _Receiver>(
+ _Self&& __self,
+ _Receiver
+ __rcvr) noexcept(__nothrow_callable<__sexpr_apply_t, _Self,
+ decltype(__connect_fn(
+ __declval<
+ _Receiver&>()))>)
+ -> __call_result_t<__sexpr_apply_t, _Self,
+ decltype(__connect_fn(__declval<_Receiver&>()))> {
+ static_assert(sender_expr_for<_Self, __ensure_started_t>);
+ return __sexpr_apply((_Self&&)__self, __connect_fn(__rcvr));
};
- static inline constexpr auto __get_completion_signatures_fn =
- []<class _ShState>(auto, const __data<_ShState>&) //
- -> __mapply<__q<__completions_t>, __id<_ShState>> { return {}; };
-
- template <sender_expr_for<__ensure_started_t> _Self, class _Receiver>
- static auto connect(_Self&& __self, _Receiver __rcvr) noexcept(
- __nothrow_callable<
- __sexpr_apply_t, _Self,
- __call_result_t<__mtypeof<__connect_fn>, _Receiver&>>)
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _OtherEnv>(_Self&&, _OtherEnv&&) noexcept
-> __call_result_t<__sexpr_apply_t, _Self,
- __call_result_t<__mtypeof<__connect_fn>, _Receiver&>>
- {
- return __sexpr_apply((_Self&&)__self, __connect_fn(__rcvr));
- }
-
- template <sender_expr_for<__ensure_started_t> _Self, class _OtherEnv>
- static auto get_completion_signatures(_Self&&, _OtherEnv&&)
- -> __call_result_t<__sexpr_apply_t, _Self,
- __mtypeof<__get_completion_signatures_fn>>
- {
+ __result_of<__get_completion_signatures_fn>> {
+ static_assert(sender_expr_for<_Self, __ensure_started_t>);
return {};
- }
+ };
};
-struct ensure_started_t : __with_default_get_env<ensure_started_t>
+struct ensure_started_t
{
template <sender _Sender>
requires sender_in<_Sender, empty_env> &&
@@ -5393,6 +4062,11 @@
using __ensure_started::ensure_started_t;
inline constexpr ensure_started_t ensure_started{};
+template <>
+struct __sexpr_impl<__ensure_started::__ensure_started_t> :
+ __ensure_started::__ensure_started_impl
+{};
+
STDEXEC_PRAGMA_PUSH()
STDEXEC_PRAGMA_IGNORE_EDG(not_used_in_partial_spec_arg_list)
@@ -5433,11 +4107,12 @@
STDEXEC_PRAGMA_POP()
//////////////////////////////////////////////////////////////////////////////
-// [execution.senders.adaptors.let_value]
-// [execution.senders.adaptors.let_error]
-// [execution.senders.adaptors.let_stopped]
+// [exec.let]
namespace __let
{
+template <class _SetTag, class _Domain = dependent_domain>
+struct __let_t;
+
template <class _Set>
struct __on_not_callable_
{
@@ -5465,25 +4140,6 @@
template <class _Tp>
using __decay_ref = __decay_t<_Tp>&;
-template <class _ReceiverId, class _SchedulerId>
-struct __operation_base_base_ : __immovable
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using _Scheduler = stdexec::__t<_SchedulerId>;
-
- _Receiver __rcvr_; // the input (outer) receiver
- STDEXEC_ATTRIBUTE((no_unique_address))
- _Scheduler __sched_; // the input sender's completion scheduler
-};
-
-inline constexpr auto __get_scheduler_prop = [](auto* __op) noexcept {
- return __mkprop(__op->__sched_, get_scheduler);
-};
-
-inline constexpr auto __get_domain_prop = [](auto*) noexcept {
- return __mkprop(get_domain);
-};
-
// A metafunction that computes the result sender type for a given set of
// argument types
template <class _Fun, class _Set>
@@ -5499,15 +4155,31 @@
concept __unknown_context =
__one_of<_Scheduler, __none_such, __inln::__scheduler>;
-// The receiver that gets connected to the result sender is the input receiver,
-// possibly augmented with the input sender's completion scheduler (which is
-// where the result sender will be started).
template <class _Receiver, class _Scheduler>
-using __result_receiver_t = __if_c<
- __unknown_context<_Scheduler>, _Receiver,
- __t<__detail::__receiver_with<
- &__operation_base_base_<__id<_Receiver>, __id<_Scheduler>>::__rcvr_,
- __get_scheduler_prop, __get_domain_prop>>>;
+struct __receiver_with_sched
+{
+ using receiver_concept = receiver_t;
+ _Receiver __rcvr_;
+ _Scheduler __sched_;
+
+ template <__completion_tag _Tag, same_as<__receiver_with_sched> _Self,
+ class... _As>
+ friend void tag_invoke(_Tag, _Self&& __self, _As&&... __as) noexcept
+ {
+ _Tag()((_Receiver&&)__self.__rcvr_, (_As&&)__as...);
+ }
+
+ template <same_as<get_env_t> _Tag>
+ friend auto tag_invoke(_Tag, const __receiver_with_sched& __self) noexcept
+ {
+ return __join_env(__mkprop(__self.__sched_, get_scheduler),
+ __mkprop(get_domain), get_env(__self.__rcvr_));
+ }
+};
+
+template <class _Receiver, class _Scheduler>
+__receiver_with_sched(_Receiver, _Scheduler)
+ -> __receiver_with_sched<_Receiver, _Scheduler>;
// If the input sender knows its completion scheduler, make it the current
// scheduler in the environment seen by the result sender.
@@ -5517,8 +4189,14 @@
__env::__env_join_t<__env::__prop<_Scheduler(get_scheduler_t)>,
__env::__prop<void(get_domain_t)>, _Env>>;
-// A metafunction that computes the type of the resulting operation state for a
-// given set of argument types.
+// The receiver that gets connected to the result sender is the input receiver,
+// possibly augmented with the input sender's completion scheduler (which is
+// where the result sender will be started).
+template <class _Receiver, class _Scheduler>
+using __result_receiver_t =
+ __if_c<__unknown_context<_Scheduler>, _Receiver,
+ __receiver_with_sched<_Receiver, _Scheduler>>;
+
template <class _Receiver, class _Fun, class _Set, class _Sched>
using __op_state_for = //
__mcompose<__mbind_back_q<connect_result_t,
@@ -5526,14 +4204,14 @@
__result_sender_t<_Fun, _Set>>;
template <class _Set, class _Sig>
-struct __tfx_signal_
+struct __tfx_signal_fn
{
template <class, class, class>
using __f = completion_signatures<_Sig>;
};
template <class _Set, class... _Args>
-struct __tfx_signal_<_Set, _Set(_Args...)>
+struct __tfx_signal_fn<_Set, _Set(_Args...)>
{
template <class _Env, class _Fun, class _Sched>
using __f = //
@@ -5548,254 +4226,104 @@
// `_Sched` is the input sender's completion scheduler, or __none_such if it
// doesn't have one.
template <class _Env, class _Fun, class _Set, class _Sched, class _Sig>
-using __tfx_signal_t = __minvoke<__tfx_signal_<_Set, _Sig>, _Env, _Fun, _Sched>;
-
-template <class _ReceiverId, class _Fun, class _Set, class _SchedId,
- class... _Tuples>
-struct __operation_base_
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using _Sched = stdexec::__t<_SchedId>;
-
- struct __t : __operation_base_base_<_ReceiverId, _SchedId>
- {
- using __id = __operation_base_;
- using __results_variant_t = std::variant<std::monostate, _Tuples...>;
- using __op_state_variant_t = //
- __minvoke<
- __transform<
- __uncurry<__op_state_for<_Receiver, _Fun, _Set, _Sched>>,
- __nullable_variant_t>,
- _Tuples...>;
-
- _Fun __fun_;
- __results_variant_t __args_;
- __op_state_variant_t __op_state3_;
- };
-};
-
-template <class _ReceiverId, class _Fun, class _Set, class _SchedId,
- class... _Tuples>
-struct __receiver_
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using _Sched = stdexec::__t<_SchedId>;
- using _Env = env_of_t<_Receiver>;
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver_;
-
- decltype(auto) __get_result_receiver() noexcept
- {
- if constexpr (same_as<__result_receiver_t<_Receiver, _Sched>,
- _Receiver>)
- {
- return static_cast<_Receiver&&>(__op_state_->__rcvr_);
- }
- else
- {
- return __result_receiver_t<_Receiver, _Sched>{{}, __op_state_};
- }
- }
-
- template <__one_of<_Set> _Tag, class... _As>
- requires(1 == __v<__minvoke<__mcount<__decayed_tuple<_As...>>,
- _Tuples...>>) &&
- __minvocable<__result_sender_t<_Fun, _Set>, _As...> &&
- sender_to<__minvoke<__result_sender_t<_Fun, _Set>, _As...>,
- __result_receiver_t<_Receiver, _Sched>>
- friend void tag_invoke(_Tag, __t&& __self, _As&&... __as) noexcept
- {
- try
- {
- using __tuple_t = __decayed_tuple<_As...>;
- using __op_state_t =
- __minvoke<__op_state_for<_Receiver, _Fun, _Set, _Sched>,
- _As...>;
- auto& __args =
- __self.__op_state_->__args_.template emplace<__tuple_t>(
- (_As&&)__as...);
- auto& __op = __self.__op_state_->__op_state3_
- .template emplace<__op_state_t>(__conv{[&] {
- return connect(
- __apply(std::move(__self.__op_state_->__fun_), __args),
- __self.__get_result_receiver());
- }});
- start(__op);
- }
- catch (...)
- {
- set_error(std::move(__self.__op_state_->__rcvr_),
- std::current_exception());
- }
- }
-
- template <__completion_tag _Tag, class... _As>
- requires __none_of<_Tag, _Set> &&
- __callable<_Tag, _Receiver, _As...>
- friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
- {
- __tag(std::move(__self.__op_state_->__rcvr_), (_As&&)__as...);
- }
-
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept
- -> env_of_t<_Receiver>
- {
- return get_env(__self.__op_state_->__rcvr_);
- }
-
- using __operation_base_t = stdexec::__t<
- __operation_base_<_ReceiverId, _Fun, _Set, _SchedId, _Tuples...>>;
- __operation_base_t* __op_state_;
- };
-};
+using __tfx_signal_t =
+ __minvoke<__tfx_signal_fn<_Set, _Sig>, _Env, _Fun, _Sched>;
template <class _Sender, class _Set>
using __completion_sched = __query_result_or_t<get_completion_scheduler_t<_Set>,
env_of_t<_Sender>, __none_such>;
-template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Set>
-using __receiver = //
- stdexec::__t<__gather_completions_for<
- _Set, __cvref_t<_CvrefSenderId>, env_of_t<__t<_ReceiverId>>,
- __q<__decayed_tuple>,
- __munique<__mbind_front_q<
- __receiver_, _ReceiverId, _Fun, _Set,
- __id<__completion_sched<__cvref_t<_CvrefSenderId>, _Set>>>>>>;
+template <class _CvrefSender, class _Env, class _LetTag, class _Fun>
+using __completions = //
+ __mapply<__transform<__mbind_front_q<
+ __tfx_signal_t, _Env, _Fun, __t<_LetTag>,
+ __completion_sched<_CvrefSender, __t<_LetTag>>>,
+ __q<__concat_completion_signatures_t>>,
+ __completion_signatures_of_t<_CvrefSender, _Env>>;
-template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Set>
-using __operation_base = typename __receiver<_CvrefSenderId, _ReceiverId, _Fun,
- _Set>::__operation_base_t;
+// Compute all the domains of all the result senders and make sure they're all
+// the same
+template <class _SetTag, class _Child, class _Fun, class _Env>
+using __result_domain_t = __gather_completions_for<
+ _SetTag, _Child, _Env,
+ __mtry_catch<
+ __transform<__q<__decay_ref>, __mbind_front_q<__call_result_t, _Fun>>,
+ __on_not_callable<_SetTag>>,
+ __q<__domain::__common_domain_t>>;
-template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Set>
-struct __operation
+template <class _LetTag, class _Env>
+auto __mk_transform_env_fn(const _Env& __env) noexcept
{
- using _Sender = stdexec::__cvref_t<_CvrefSenderId>;
-
- struct __t : __operation_base<_CvrefSenderId, _ReceiverId, _Fun, _Set>
- {
- using __id = __operation;
- using __op_base_t =
- __operation_base<_CvrefSenderId, _ReceiverId, _Fun, _Set>;
- using __receiver_t =
- __receiver<_CvrefSenderId, _ReceiverId, _Fun, _Set>;
-
- friend void tag_invoke(start_t, __t& __self) noexcept
+ using _SetTag = __t<_LetTag>;
+ return [&]<class _Fun, sender_in<_Env> _Child>(
+ __ignore, _Fun&&, _Child&& __child) -> decltype(auto) {
+ using _Scheduler = __completion_sched<_Child, _SetTag>;
+ if constexpr (__unknown_context<_Scheduler>)
{
- start(__self.__op_state2_);
+ return (__env);
}
-
- template <class _Receiver2>
- __t(_Sender&& __sndr, _Receiver2&& __rcvr, _Fun __fun) :
- __op_base_t{{{},
- (_Receiver2&&)__rcvr,
- query_or(get_completion_scheduler<_Set>,
- get_env(__sndr), __none_such())},
- (_Fun&&)__fun,
- {},
- {}},
- __op_state2_(connect((_Sender&&)__sndr, __receiver_t{this}))
- {}
-
- connect_result_t<_Sender, __receiver_t> __op_state2_;
- };
-};
-
-template <class _Sender, class _Fun, class _SetId>
-struct __sender_base
-{
- using _Set = stdexec::__t<_SetId>;
- using is_sender = void;
-
- template <class _Self, class _Receiver>
- using __operation_t = //
- stdexec::__t<__operation<stdexec::__cvref_id<_Self, _Sender>,
- stdexec::__id<_Receiver>, _Fun, _Set>>;
- template <class _Self, class _Receiver>
- using __receiver_t = __receiver<stdexec::__cvref_id<_Self, _Sender>,
- stdexec::__id<_Receiver>, _Fun, _Set>;
-
- template <class _CvrefSender>
- using __completion_sched =
- __query_result_or_t<get_completion_scheduler_t<_Set>,
- env_of_t<_CvrefSender>, __none_such>;
-
- template <class _CvrefSender, class _Env>
- using __completions = //
- __mapply<__transform<__mbind_front_q<__tfx_signal_t, _Env, _Fun, _Set,
- __completion_sched<_Sender>>,
- __q<__concat_completion_signatures_t>>,
- __completion_signatures_of_t<_Sender, _Env>>;
-
- template <__decays_to_derived_from<__sender_base> _Self, receiver _Receiver>
- requires sender_to<__copy_cvref_t<_Self, _Sender>,
- __receiver_t<_Self, _Receiver>>
- friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr)
- -> __operation_t<_Self, _Receiver>
- {
- return __operation_t<_Self, _Receiver>{((_Self&&)__self).__sndr_,
- (_Receiver&&)__rcvr,
- ((_Self&&)__self).__fun_};
- }
-
- template <__decays_to_derived_from<__sender_base> _Self, class _Env>
- friend auto tag_invoke(get_completion_signatures_t, _Self&&, _Env&&)
- -> __completions<__copy_cvref_t<_Self, _Sender>, _Env>
- {
- return {};
- }
-
- // BUGBUG better would be to port the `let_[value|error|stopped]` algorithms
- // to __sexpr
- template <class _Self, class _ApplyFun>
- static auto apply(_Self&& __self, _ApplyFun __fun) -> __call_result_t<
- _ApplyFun,
- _SetId, // Actually one of let_value_t, let_error_t, let_stopped_t
- __copy_cvref_t<_Self, _Fun>, __copy_cvref_t<_Self, _Sender>>
- {
- return ((_ApplyFun&&)__fun)(_SetId(), ((_Self&&)__self).__fun_,
- ((_Self&&)__self).__sndr_);
- }
-
- _Sender __sndr_;
- _Fun __fun_;
-};
-
-template <class _SenderId, class _Fun, class _SetId,
- class _Domain = dependent_domain>
-struct __sender
-{
- struct __t : __sender_base<stdexec::__t<_SenderId>, _Fun, _SetId>
- {
- using __id = __sender;
-
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept
- /*-> env_of_t<const _Sender&>*/ {
- return __join_env(__mkprop(_Domain(), get_domain),
- get_env(__self.__sndr_));
+ else
+ {
+ return __join_env(__mkprop(get_completion_scheduler<_SetTag>(
+ stdexec::get_env(__child)),
+ get_scheduler),
+ __mkprop(get_domain), __env);
}
+ STDEXEC_UNREACHABLE();
};
+}
+
+template <class _LetTag, class _Env>
+auto __mk_transform_sender_fn(const _Env&) noexcept
+{
+ using _SetTag = __t<_LetTag>;
+ return []<class _Fun, sender_in<_Env> _Child>(__ignore, _Fun&& __fun,
+ _Child&& __child) {
+ using _Domain = __result_domain_t<_SetTag, _Child, _Fun, _Env>;
+ static_assert(__none_of<_Domain, __none_such, dependent_domain>);
+ return __make_sexpr<__let_t<_SetTag, _Domain>>((_Fun&&)__fun,
+ (_Child&&)__child);
+ };
+}
+
+template <class _Receiver, class _Fun, class _Set, class _Sched,
+ class... _Tuples>
+struct __let_state
+{
+ using __fun_t = _Fun;
+ using __sched_t = _Sched;
+
+ using __result_variant = std::variant<std::monostate, _Tuples...>;
+
+ using __op_state_variant = //
+ __minvoke<__transform<
+ __uncurry<__op_state_for<_Receiver, _Fun, _Set, _Sched>>,
+ __nullable_variant_t>,
+ _Tuples...>;
+
+ decltype(auto) __get_result_receiver(_Receiver&& __rcvr)
+ {
+ if constexpr (__unknown_context<_Sched>)
+ {
+ return (_Receiver&&)__rcvr;
+ }
+ else
+ {
+ return __receiver_with_sched{(_Receiver&&)__rcvr, this->__sched_};
+ }
+ }
+
+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Fun __fun_;
+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Sched __sched_;
+ __result_variant __args_;
+ __op_state_variant __op_state3_;
};
-template <class _LetTag, class _SetTag>
-struct __let_xxx_t : __with_default_get_env<_LetTag>
+template <class _SetTag, class _Domain>
+struct __let_t
{
- using _Sender = __1;
- using _Function = __0;
- using __legacy_customizations_t =
- __types<tag_invoke_t(_LetTag,
- get_completion_scheduler_t<set_value_t>(
- get_env_t(const _Sender&)),
- _Sender, _Function),
- tag_invoke_t(_LetTag, _Sender, _Function)>;
-
+ using __domain_t = _Domain;
using __t = _SetTag;
- template <class _Sender, class _Fun, class _Domain = dependent_domain>
- using __sender =
- stdexec::__t<__let::__sender<stdexec::__id<__decay_t<_Sender>>, _Fun,
- _LetTag, _Domain>>;
template <sender _Sender, __movable_value _Fun>
auto operator()(_Sender&& __sndr, _Fun __fun) const
@@ -5803,186 +4331,143 @@
auto __domain = __get_early_domain(__sndr);
return stdexec::transform_sender(
__domain,
- __sender<_Sender, _Fun>{{(_Sender&&)__sndr, (_Fun&&)__fun}});
+ __make_sexpr<__let_t<_SetTag>>((_Fun&&)__fun, (_Sender&&)__sndr));
}
template <class _Fun>
STDEXEC_ATTRIBUTE((always_inline)) //
- __binder_back<_LetTag, _Fun> operator()(_Fun __fun) const
+ __binder_back<__let_t, _Fun> operator()(_Fun __fun) const
{
return {{}, {}, {(_Fun&&)__fun}};
}
- // Compute all the domains of all the result senders and make sure they're
- // all the same
- template <class _Child, class _Fun, class _Env>
- using __result_domain_t = __gather_completions_for<
- _SetTag, _Child, _Env,
- __mtry_catch<__mbind_front_q<__call_result_t, _Fun>,
- __on_not_callable<_SetTag>>,
- __q<__domain::__common_domain_t>>;
+ using _Sender = __1;
+ using _Function = __0;
+ using __legacy_customizations_t =
+ __types<tag_invoke_t(__let_t,
+ get_completion_scheduler_t<set_value_t>(
+ get_env_t(const _Sender&)),
+ _Sender, _Function),
+ tag_invoke_t(__let_t, _Sender, _Function)>;
- static auto get_env(__ignore) noexcept
- {
- return __mkprop(dependent_domain(), get_domain);
- }
-
- template <sender_expr_for<_LetTag> _Sender, class _Env>
+ template <sender_expr_for<__let_t<_SetTag>> _Sender, class _Env>
static decltype(auto) transform_env(_Sender&& __sndr, const _Env& __env)
{
- return __sexpr_apply(
- (_Sender&&)__sndr,
- [&]<class _Fun, sender_in<_Env> _Child>(
- __ignore, _Fun&&, _Child&& __child) -> decltype(auto) {
- using _Scheduler = __completion_sched<_Child, _SetTag>;
- if constexpr (__unknown_context<_Scheduler>)
- {
- return (__env);
- }
- else
- {
- return __join_env(__mkprop(get_completion_scheduler<_SetTag>(
- stdexec::get_env(__child)),
- get_scheduler),
- __mkprop(get_domain), __env);
- }
- STDEXEC_UNREACHABLE();
- });
+ return __sexpr_apply((_Sender&&)__sndr,
+ __mk_transform_env_fn<__let_t<_SetTag>>(__env));
}
- template <sender_expr_for<_LetTag> _Sender, class _Env>
+ template <sender_expr_for<__let_t<_SetTag>> _Sender, class _Env>
requires same_as<__early_domain_of_t<_Sender>, dependent_domain>
static decltype(auto) transform_sender(_Sender&& __sndr, const _Env& __env)
{
return __sexpr_apply((_Sender&&)__sndr,
- [&]<class _Fun, sender_in<_Env> _Child>(
- __ignore, _Fun&& __fun, _Child&& __child) {
- // TODO: propagate errors here
- using _Domain = __result_domain_t<_Child, _Fun, _Env>;
- static_assert(__none_of<_Domain, __none_such, dependent_domain>);
- return __sender<_Child, _Fun, _Domain>{
- {(_Child&&)__child, (_Fun&&)__fun}};
- });
+ __mk_transform_sender_fn<__let_t<_SetTag>>(__env));
}
};
-struct let_value_t : __let::__let_xxx_t<let_value_t, set_value_t>
-{};
+template <class _SetTag, class _Domain>
+struct __let_impl : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ []<class _Child>(__ignore, const _Child& __child) noexcept {
+ return __join_env(__mkprop(_Domain(), get_domain),
+ stdexec::get_env(__child));
+ };
-struct let_error_t : __let::__let_xxx_t<let_error_t, set_error_t>
-{};
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _Env>(_Self&&, _Env&&) noexcept
+ -> __completions<__child_of<_Self>, _Env, __let_t<_SetTag, _Domain>,
+ __data_of<_Self>> {
+ static_assert(sender_expr_for<_Self, __let_t<_SetTag, _Domain>>);
+ return {};
+ };
-struct let_stopped_t : __let::__let_xxx_t<let_stopped_t, set_stopped_t>
-{};
+ static constexpr auto get_state = //
+ []<class _Sender, class _Receiver>(_Sender&& __sndr,
+ _Receiver& __rcvr) {
+ static_assert(sender_expr_for<_Sender, __let_t<_SetTag, _Domain>>);
+ using _Fun = __data_of<_Sender>;
+ using _Sched = __completion_sched<_Sender, _SetTag>;
+ using __mk_let_state =
+ __mbind_front_q<__let_state, _Receiver, _Fun, _SetTag, _Sched>;
+
+ using __let_state_t =
+ __gather_completions_for<_SetTag, __child_of<_Sender>,
+ env_of_t<_Receiver>, __q<__decayed_tuple>,
+ __mk_let_state>;
+
+ _Sched __sched = query_or(get_completion_scheduler<_SetTag>,
+ stdexec::get_env(__sndr), __none_such());
+ return __let_state_t{
+ STDEXEC_CALL_EXPLICIT_THIS_MEMFN((_Sender&&)__sndr,
+ apply)(__detail::__get_data()),
+ __sched};
+ };
+
+ template <class _State, class _Receiver, class... _As>
+ static void __bind(_State&& __state, _Receiver&& __rcvr,
+ _As&&... __as) noexcept
+ {
+ try
+ {
+ using __fun_t = typename _State::__fun_t;
+ using __sched_t = typename _State::__sched_t;
+ using __tuple_t = __decayed_tuple<_As...>;
+ using __op_state_t = __minvoke<
+ __op_state_for<_Receiver, __fun_t, _SetTag, __sched_t>, _As...>;
+ auto& __args =
+ __state.__args_.template emplace<__tuple_t>((_As&&)__as...);
+ auto& __op =
+ __state.__op_state3_.template emplace<__op_state_t>(__conv{[&] {
+ return stdexec::connect(
+ __apply(std::move(__state.__fun_), __args),
+ __state.__get_result_receiver((_Receiver&&)__rcvr));
+ }});
+ stdexec::start(__op);
+ }
+ catch (...)
+ {
+ set_error(std::move(__rcvr), std::current_exception());
+ }
+ }
+
+ static constexpr auto complete = //
+ []<class _State, class _Receiver, class _Tag, class... _As>(
+ __ignore, _State& __state, _Receiver& __rcvr, _Tag,
+ _As&&... __as) noexcept -> void {
+ if constexpr (std::same_as<_Tag, _SetTag>)
+ {
+ __bind((_State&&)__state, (_Receiver&&)__rcvr, (_As&&)__as...);
+ }
+ else
+ {
+ _Tag()((_Receiver&&)__rcvr, (_As&&)__as...);
+ }
+ };
+};
} // namespace __let
-using __let::let_value_t;
+using let_value_t = __let::__let_t<set_value_t>;
inline constexpr let_value_t let_value{};
-using __let::let_error_t;
+
+using let_error_t = __let::__let_t<set_error_t>;
inline constexpr let_error_t let_error{};
-using __let::let_stopped_t;
+
+using let_stopped_t = __let::__let_t<set_stopped_t>;
inline constexpr let_stopped_t let_stopped{};
-// BUGBUG this will also be unnecessary when `on` returns a __sexpr
-namespace __detail
-{
-template <class _SenderId, class _Fun, class _SetId>
-extern __mconst<__let::__sender<__name_of<__t<_SenderId>>, _Fun, _SetId>>
- __name_of_v<__let::__sender<_SenderId, _Fun, _SetId>>;
-}
+template <class _SetTag, class _Domain>
+struct __sexpr_impl<__let::__let_t<_SetTag, _Domain>> :
+ __let::__let_impl<_SetTag, _Domain>
+{};
/////////////////////////////////////////////////////////////////////////////
// [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>
+struct stopped_as_optional_t
{
template <sender _Sender>
auto operator()(_Sender&& __sndr) const
@@ -5995,47 +4480,10 @@
{
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});
- }
-
+struct __stopped_as_optional_impl : __sexpr_defaults
+{
template <class... _Tys>
requires(sizeof...(_Tys) == 1)
using __set_value_t =
@@ -6044,15 +4492,55 @@
template <class _Ty>
using __set_error_t = completion_signatures<set_error_t(_Ty)>;
- template <sender_expr_for<stopped_as_optional_t> _Self, class _Env>
- static auto get_completion_signatures(_Self&&, _Env&&)
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _Env>(_Self&&, _Env&&) noexcept //
-> make_completion_signatures<
__child_of<_Self>, _Env,
completion_signatures<set_error_t(std::exception_ptr)>,
- __set_value_t, __set_error_t, completion_signatures<>>
- {
+ __set_value_t, __set_error_t, completion_signatures<>> {
+ static_assert(sender_expr_for<_Self, stopped_as_optional_t>);
return {};
- }
+ };
+
+ static constexpr auto get_state = //
+ []<class _Self, class _Receiver>(_Self&&, _Receiver&) noexcept
+ requires __single_typed_sender<__child_of<_Self>, env_of_t<_Receiver>>
+ {
+ static_assert(sender_expr_for<_Self, stopped_as_optional_t>);
+ using _Value = __decay_t<
+ __single_sender_value_t<__child_of<_Self>, env_of_t<_Receiver>>>;
+ return __mtype<_Value>();
+ };
+
+ static constexpr auto complete = //
+ []<class _State, class _Receiver, __completion_tag _Tag,
+ class... _Args>(__ignore, _State&, _Receiver& __rcvr, _Tag,
+ _Args&&... __args) noexcept -> void {
+ 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
@@ -6083,6 +4571,11 @@
using __stopped_as_xxx::stopped_as_error_t;
inline constexpr stopped_as_error_t stopped_as_error{};
+template <>
+struct __sexpr_impl<stopped_as_optional_t> :
+ __stopped_as_xxx::__stopped_as_optional_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// run_loop
namespace __loop
@@ -6173,7 +4666,7 @@
{
using __t = __schedule_task;
using __id = __schedule_task;
- using is_sender = void;
+ using sender_concept = sender_t;
using completion_signatures = //
__completion_signatures_<set_value_t(),
set_error_t(std::exception_ptr),
@@ -6380,7 +4873,7 @@
struct __t
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
using __id = __receiver2;
__operation1_base<_SchedulerId, _VariantId, _ReceiverId>* __op_state_;
@@ -6426,7 +4919,7 @@
struct __t
{
using __id = __receiver1;
- using is_receiver = void;
+ using receiver_concept = receiver_t;
__operation1_base<_SchedulerId, _VariantId, _ReceiverId>* __op_state_;
template <class... _Args>
@@ -6589,14 +5082,6 @@
__mconst<completion_signatures<>>>,
__decay_signature<set_value_t>, __decay_signature<set_error_t>>;
-inline auto __get_env_fn() noexcept
-{
- return [](__ignore, const auto& __data,
- const auto& __child) noexcept -> decltype(auto) {
- return __join_env(__data, stdexec::get_env(__child));
- };
-}
-
struct schedule_from_t
{
template <scheduler _Scheduler, sender _Sender>
@@ -6615,16 +5100,15 @@
using __legacy_customizations_t = __types<tag_invoke_t(
schedule_from_t, get_completion_scheduler_t<set_value_t>(_Env&),
_Sender)>;
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
+struct __schedule_from_impl : __sexpr_defaults
+{
+ template <class, class _Data, class _Child>
+ using __env_ = __env::__env_join_t<_Data, env_of_t<_Child>>;
template <class _Sender>
- using __env_t =
- __sexpr_apply_result_t<const _Sender&, __result_of<__get_env_fn>>;
+ using __env_t = __mapply<__q<__env_>, _Sender>;
template <class _Sender>
using __scheduler_t =
@@ -6645,25 +5129,27 @@
stdexec::__cvref_id<__child_of<_Sender>>,
stdexec::__id<_Receiver>>>;
- template <sender_expr_for<schedule_from_t> _Sender>
- static __env_t<_Sender> get_env(const _Sender& __sndr) noexcept
- {
- return __sexpr_apply(__sndr, __get_env_fn());
- }
+ static constexpr auto get_attrs = //
+ []<class _Data, class _Child>(const _Data& __data,
+ const _Child& __child) noexcept {
+ return __join_env(__data, stdexec::get_env(__child));
+ };
- template <sender_expr_for<schedule_from_t> _Sender, class _Env>
- static auto get_completion_signatures(_Sender&&, const _Env&) noexcept
- -> __completions_t<__scheduler_t<_Sender>, __child_of<_Sender>, _Env>
- {
+ static constexpr auto get_completion_signatures = //
+ []<class _Sender, class _Env>(_Sender&&, const _Env&) noexcept
+ -> __completions_t<__scheduler_t<_Sender>, __child_of<_Sender>, _Env> {
+ static_assert(sender_expr_for<_Sender, schedule_from_t>);
return {};
- }
+ };
- template <sender_expr_for<schedule_from_t> _Sender, receiver _Receiver>
+ static constexpr auto connect = //
+ []<class _Sender, receiver _Receiver>(_Sender&& __sndr,
+ _Receiver __rcvr) //
+ -> __operation_t<_Sender, _Receiver> //
requires sender_to<__child_of<_Sender>,
__receiver_t<_Sender, _Receiver>>
- static auto connect(_Sender&& __sndr, _Receiver __rcvr) //
- -> __operation_t<_Sender, _Receiver>
{
+ static_assert(sender_expr_for<_Sender, schedule_from_t>);
return __sexpr_apply((_Sender&&)__sndr,
[&]<class _Data, class _Child>(
__ignore, _Data&& __data, _Child&& __child)
@@ -6671,13 +5157,17 @@
auto __sched = get_completion_scheduler<set_value_t>(__data);
return {__sched, (_Child&&)__child, (_Receiver&&)__rcvr};
});
- }
+ };
};
} // namespace __schedule_from
using __schedule_from::schedule_from_t;
inline constexpr schedule_from_t schedule_from{};
+template <>
+struct __sexpr_impl<schedule_from_t> : __schedule_from::__schedule_from_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.transfer]
namespace __transfer
@@ -6692,13 +5182,6 @@
__result_of<schedule_from, __scheduler_t<__data_of<_Sender>>,
__child_of<_Sender>>;
-inline auto __get_env_fn() noexcept
-{
- return [](__ignore, const auto& __data, const auto& __child) noexcept {
- return __join_env(__data, stdexec::get_env(__child));
- };
-}
-
struct transfer_t
{
template <sender _Sender, scheduler _Scheduler>
@@ -6731,12 +5214,6 @@
tag_invoke_t(transfer_t, _Sender,
get_completion_scheduler_t<set_value_t>(_Env))>;
- template <sender_expr_for<transfer_t> _Sender>
- static decltype(auto) get_env(const _Sender& __sndr) noexcept
- {
- return __sexpr_apply(__sndr, __get_env_fn());
- }
-
template <class _Env>
static auto __transform_sender_fn(const _Env&)
{
@@ -6753,11 +5230,25 @@
return __sexpr_apply((_Sender&&)__sndr, __transform_sender_fn(__env));
}
};
+
+struct __transfer_impl : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ []<class _Data, class _Child>(
+ const _Data& __data,
+ const _Child& __child) noexcept -> decltype(auto) {
+ return __join_env(__data, stdexec::get_env(__child));
+ };
+};
} // namespace __transfer
using __transfer::transfer_t;
inline constexpr transfer_t transfer{};
+template <>
+struct __sexpr_impl<transfer_t> : __transfer::__transfer_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.transfer_just]
namespace __transfer_just
@@ -6771,22 +5262,6 @@
};
}
-inline auto __make_env_fn() noexcept
-{
- return []<class _Scheduler>(const _Scheduler& __sched,
- const auto&...) noexcept {
- using _Env = __t<__schedule_from::__environ<__id<_Scheduler>>>;
- return _Env{{__sched}};
- };
-}
-
-inline auto __get_env_fn() noexcept
-{
- return [](__ignore, const auto& __data) noexcept {
- return __apply(__make_env_fn(), __data);
- };
-}
-
template <class _Env>
auto __make_transform_fn(const _Env& __env)
{
@@ -6819,23 +5294,38 @@
(_Scheduler&&)__sched, (_Values&&)__vals...}));
}
- template <sender_expr_for<transfer_just_t> _Sender>
- static auto get_env(const _Sender& __sndr) noexcept
- {
- return __sexpr_apply((_Sender&&)__sndr, __get_env_fn());
- }
-
template <class _Sender, class _Env>
static auto transform_sender(_Sender&& __sndr, const _Env& __env)
{
return __sexpr_apply((_Sender&&)__sndr, __transform_sender_fn(__env));
}
};
+
+inline auto __make_env_fn() noexcept
+{
+ return []<class _Scheduler>(const _Scheduler& __sched,
+ const auto&...) noexcept {
+ using _Env = __t<__schedule_from::__environ<__id<_Scheduler>>>;
+ return _Env{{__sched}};
+ };
+}
+
+struct __transfer_just_impl : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ []<class _Data>(const _Data& __data) noexcept {
+ return __apply(__make_env_fn(), __data);
+ };
+};
} // namespace __transfer_just
using __transfer_just::transfer_just_t;
inline constexpr transfer_just_t transfer_just{};
+template <>
+struct __sexpr_impl<transfer_just_t> : __transfer_just::__transfer_just_impl
+{};
+
//////////////////////////////////////////////////////////////////////////////////////////////////
// __write adaptor
namespace __write_
@@ -6878,7 +5368,7 @@
}
};
-struct __write_t : __with_default_get_env<__write_t>
+struct __write_t
{
template <sender _Sender, class... _Envs>
auto operator()(_Sender&& __sndr, _Envs... __envs) const
@@ -6908,13 +5398,10 @@
{
return __sexpr_apply(__self, __transform_env_fn((_Env&&)__env));
}
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
+struct __write_impl : __sexpr_defaults
+{
template <class _Self, class _Receiver>
using __receiver_t =
__write_::__receiver_t<__id<_Receiver>, __decay_t<__data_of<_Self>>>;
@@ -6924,33 +5411,38 @@
__operation<__cvref_id<__child_of<_Self>>, __id<_Receiver>,
__decay_t<__data_of<_Self>>>;
- template <sender_expr_for<__write_t> _Self, receiver _Receiver>
+ static constexpr auto connect = //
+ []<class _Self, receiver _Receiver>(_Self&& __self, _Receiver __rcvr) //
+ -> __operation_t<_Self, _Receiver> //
requires sender_to<__child_of<_Self>, __receiver_t<_Self, _Receiver>>
- static auto connect(_Self&& __self, _Receiver __rcvr)
- -> __operation_t<_Self, _Receiver>
{
+ static_assert(sender_expr_for<_Self, __write_t>);
return __sexpr_apply((_Self&&)__self,
[&]<class _Env, class _Child>(
__write_t, _Env&& __env, _Child&& __child) //
-> __operation_t<_Self, _Receiver> {
return {(_Child&&)__child, (_Receiver&&)__rcvr, (_Env&&)__env};
});
- }
+ };
- template <sender_expr_for<__write_t> _Self, class _Env>
- static auto get_completion_signatures(_Self&&, _Env&&)
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _Env>(_Self&&, _Env&&) noexcept
-> stdexec::__completion_signatures_of_t<
__child_of<_Self>,
- __env::__env_join_t<const __decay_t<__data_of<_Self>>&, _Env>>
- {
+ __env::__env_join_t<const __decay_t<__data_of<_Self>>&, _Env>> {
+ static_assert(sender_expr_for<_Self, __write_t>);
return {};
- }
+ };
};
} // namespace __write_
using __write_::__write_t;
inline constexpr __write_t __write{};
+template <>
+struct __sexpr_impl<__write_t> : __write_::__write_impl
+{};
+
namespace __detail
{
template <class _Scheduler>
@@ -7099,7 +5591,7 @@
struct __t
{
using __id = __sender;
- using is_sender = void;
+ using sender_concept = sender_t;
using __schedule_sender_t = __result_of<schedule, _Scheduler>;
template <class _ReceiverId>
@@ -7160,7 +5652,7 @@
};
};
-struct on_t : __with_default_get_env<on_t>
+struct on_t
{
using _Sender = __1;
using _Scheduler = __0;
@@ -7228,64 +5720,9 @@
requires sender_in<_Sender, _Env>
using __into_variant_result_t = value_types_of_t<_Sender, _Env>;
-template <class _ReceiverId, class _Variant>
-struct __receiver
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver;
- using _Receiver = stdexec::__t<_ReceiverId>;
- _Receiver __rcvr_;
-
- // Customize set_value by building a variant and passing the result
- // to the base class
- template <same_as<set_value_t> _Tag, class... _As>
- requires constructible_from<_Variant, std::tuple<_As&&...>>
- friend void tag_invoke(_Tag, __t&& __self, _As&&... __as) noexcept
- {
- try
- {
- set_value((_Receiver&&)__self.__rcvr_,
- _Variant{std::tuple<_As&&...>{(_As&&)__as...}});
- }
- catch (...)
- {
- set_error((_Receiver&&)__self.__rcvr_,
- std::current_exception());
- }
- }
-
- template <same_as<set_error_t> _Tag, class _Error>
- friend void tag_invoke(_Tag, __t&& __self, _Error&& __err) noexcept
- {
- set_error((_Receiver&&)__self.__rcvr_, (_Error&&)__err);
- }
-
- template <same_as<set_stopped_t> _Tag>
- friend void tag_invoke(_Tag, __t&& __self) noexcept
- {
- set_stopped((_Receiver&&)__self.__rcvr_);
- }
-
- friend env_of_t<_Receiver> tag_invoke(get_env_t,
- const __t& __self) noexcept
- {
- return get_env(__self.__rcvr_);
- }
- };
-};
-
template <class _Sender, class _Env>
using __variant_t = __try_value_types_of_t<_Sender, _Env>;
-template <class _Sender, class _Receiver>
-using __receiver_t = //
- stdexec::__t<
- __receiver<__id<_Receiver>, __variant_t<_Sender, env_of_t<_Receiver>>>>;
-
template <class _Variant>
using __variant_completions =
completion_signatures<set_value_t(_Variant),
@@ -7298,7 +5735,7 @@
__meval<__variant_completions, __variant_t<_Sender, _Env>>,
__mconst<completion_signatures<>>>;
-struct into_variant_t : __with_default_get_env<into_variant_t>
+struct into_variant_t
{
template <sender _Sender>
auto operator()(_Sender&& __sndr) const
@@ -7313,43 +5750,57 @@
{
return __binder_back<into_variant_t>{};
}
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
+struct __into_variant_impl : __sexpr_defaults
+{
+ static constexpr auto get_state = //
+ []<class _Self, class _Receiver>(_Self&&, _Receiver&) noexcept {
+ using __variant_t =
+ value_types_of_t<__child_of<_Self>, env_of_t<_Receiver>>;
+ return __mtype<__variant_t>();
+ };
- template <sender_expr_for<into_variant_t> _Self, receiver _Receiver>
- requires sender_to<__child_of<_Self>,
- __receiver_t<__child_of<_Self>, _Receiver>>
- static auto connect(_Self&& __self, _Receiver __rcvr) //
- noexcept(__nothrow_connectable<
- __child_of<_Self>, __receiver_t<__child_of<_Self>, _Receiver>>)
- -> connect_result_t<__child_of<_Self>,
- __receiver_t<__child_of<_Self>, _Receiver>>
- {
- return __sexpr_apply(
- (_Self&&)__self,
- [&]<class _Child>(__ignore, __ignore, _Child&& __child) {
- return stdexec::connect(
- (_Child&&)__child,
- __receiver_t<_Child, _Receiver>{(_Receiver&&)__rcvr});
- });
- }
+ static constexpr auto complete = //
+ []<class _State, class _Receiver, class _Tag, class... _Args>(
+ __ignore, _State, _Receiver& __rcvr, _Tag,
+ _Args&&... __args) noexcept -> void {
+ if constexpr (same_as<_Tag, set_value_t>)
+ {
+ using __variant_t = __t<_State>;
+ try
+ {
+ set_value(
+ (_Receiver&&)__rcvr,
+ __variant_t{std::tuple<_Args&&...>{(_Args&&)__args...}});
+ }
+ catch (...)
+ {
+ set_error((_Receiver&&)__rcvr, std::current_exception());
+ }
+ }
+ else
+ {
+ _Tag()((_Receiver&&)__rcvr, (_Args&&)__args...);
+ }
+ };
- template <sender_expr_for<into_variant_t> _Self, class _Env>
- static auto get_completion_signatures(_Self&&, _Env&&) //
- -> __compl_sigs<__child_of<_Self>, _Env>
- {
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _Env>(_Self&&, _Env&&) noexcept //
+ -> __compl_sigs<__child_of<_Self>, _Env> {
+ static_assert(sender_expr_for<_Self, into_variant_t>);
return {};
- }
+ };
};
} // namespace __into_variant
using __into_variant::into_variant_t;
inline constexpr into_variant_t into_variant{};
+template <>
+struct __sexpr_impl<into_variant_t> : __into_variant::__into_variant_impl
+{};
+
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.when_all]
// [execution.senders.adaptors.when_all_with_variant]
@@ -7362,7 +5813,7 @@
__stopped
};
-struct __on_stop_requested
+struct __on_stop_request
{
in_place_stop_source& __stop_source_;
@@ -7373,18 +5824,15 @@
};
template <class _Env>
-auto __make_env(_Env&& __env, in_place_stop_source& __stop_source) noexcept
+auto __mkenv(_Env&& __env, in_place_stop_source& __stop_source) noexcept
{
- return __join_env(__env::__env_fn{[&](get_stop_token_t) noexcept {
- return __stop_source.get_token();
- }},
+ return __join_env(__mkprop(__stop_source.get_token(), get_stop_token),
(_Env&&)__env);
}
template <class _Env>
using __env_t = //
- decltype(__when_all::__make_env(__declval<_Env>(),
- __declval<in_place_stop_source&>()));
+ decltype(__mkenv(__declval<_Env>(), __declval<in_place_stop_source&>()));
template <class _Tp>
using __decay_rvalue_ref = __decay_t<_Tp>&&;
@@ -7464,215 +5912,27 @@
};
template <class _Tag, class _Receiver>
-struct __complete_fn
+auto __complete_fn(_Tag, _Receiver& __rcvr) noexcept
{
- _Receiver& __rcvr_;
-
- __complete_fn(_Tag, _Receiver& __rcvr) noexcept : __rcvr_(__rcvr) {}
-
- template <class _Ty, class... _Ts>
- void operator()(_Ty& __t, _Ts&... __ts) const noexcept
- {
- if constexpr (!same_as<_Ty, __not_an_error>)
+ return [&]<class... _Ts>(_Ts&... __ts) noexcept {
+ if constexpr (!same_as<__types<_Ts...>, __types<__not_an_error>>)
{
- _Tag{}((_Receiver&&)__rcvr_, (_Ty&&)__t, (_Ts&&)__ts...);
+ _Tag()((_Receiver&&)__rcvr, (_Ts&&)__ts...);
}
- }
-
- void operator()() const noexcept
- {
- _Tag{}((_Receiver&&)__rcvr_);
- }
-};
+ };
+}
template <class _Receiver, class _ValuesTuple>
void __set_values(_Receiver& __rcvr, _ValuesTuple& __values) noexcept
{
__apply(
[&](auto&... __opt_vals) noexcept -> void {
- __apply(__complete_fn{set_value, __rcvr},
+ __apply(__complete_fn(set_value, __rcvr), //
std::tuple_cat(__apply(__tie_fn{}, *__opt_vals)...));
},
__values);
}
-template <class _ReceiverId, class _ValuesTuple, class _ErrorsVariant>
-struct __operation_base : __immovable
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- void __arrive() noexcept
- {
- if (0 == --__count_)
- {
- __complete();
- }
- }
-
- void __complete() noexcept
- {
- // Stop callback is no longer needed. Destroy it.
- __on_stop_.reset();
- // All child operations have completed and arrived at the barrier.
- switch (__state_.load(std::memory_order_relaxed))
- {
- case __started:
- if constexpr (!same_as<_ValuesTuple, __ignore>)
- {
- // All child operations completed successfully:
- __when_all::__set_values(__rcvr_, __values_);
- }
- break;
- case __error:
- if constexpr (!same_as<_ErrorsVariant,
- std::variant<std::monostate>>)
- {
- // One or more child operations completed with an error:
- std::visit(__complete_fn{set_error, __rcvr_}, __errors_);
- }
- break;
- case __stopped:
- stdexec::set_stopped((_Receiver&&)__rcvr_);
- break;
- default:;
- }
- }
-
- _Receiver __rcvr_;
- std::atomic<std::size_t> __count_;
- in_place_stop_source __stop_source_{};
- // Could be non-atomic here and atomic_ref everywhere except __completion_fn
- std::atomic<__state_t> __state_{__started};
- _ErrorsVariant __errors_{};
- STDEXEC_ATTRIBUTE((no_unique_address)) _ValuesTuple __values_{};
- std::optional<typename stop_token_of_t<
- env_of_t<_Receiver>&>::template callback_type<__on_stop_requested>>
- __on_stop_{};
-};
-
-template <std::size_t _Index, class _ReceiverId, class _ValuesTuple,
- class _ErrorsVariant>
-struct __receiver
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- template <class _Tuple>
- using __tuple_type =
- typename std::tuple_element_t<_Index, _Tuple>::value_type;
- using _TupleType =
- __minvoke<__with_default<__q<__tuple_type>, __ignore>, _ValuesTuple>;
-
- struct __t
- {
- using is_receiver = void;
- using __id = __receiver;
-
- template <class _Error>
- void __set_error(_Error&& __err) noexcept
- {
- // TODO: What memory orderings are actually needed here?
- if (__error != __op_state_->__state_.exchange(__error))
- {
- __op_state_->__stop_source_.request_stop();
- // We won the race, free to write the error into the operation
- // state without worry.
- if constexpr (__nothrow_decay_copyable<_Error>)
- {
- __op_state_->__errors_.template emplace<__decay_t<_Error>>(
- (_Error&&)__err);
- }
- else
- {
- try
- {
- __op_state_->__errors_
- .template emplace<__decay_t<_Error>>(
- (_Error&&)__err);
- }
- catch (...)
- {
- __op_state_->__errors_
- .template emplace<std::exception_ptr>(
- std::current_exception());
- }
- }
- }
- }
-
- template <same_as<set_value_t> _Tag, class... _Values>
- requires same_as<_ValuesTuple, __ignore> ||
- constructible_from<_TupleType, _Values...>
- friend void tag_invoke(_Tag, __t&& __self, _Values&&... __vals) noexcept
- {
- if constexpr (!same_as<_ValuesTuple, __ignore>)
- {
- static_assert(
- same_as<_TupleType, std::tuple<__decay_t<_Values>...>>,
- "One of the senders in this when_all() is fibbing about what types it sends");
- // We only need to bother recording the completion values
- // if we're not already in the "error" or "stopped" state.
- if (__self.__op_state_->__state_ == __started)
- {
- if constexpr ((__nothrow_decay_copyable<_Values> && ...))
- {
- std::get<_Index>(__self.__op_state_->__values_)
- .emplace((_Values&&)__vals...);
- }
- else
- {
- try
- {
- std::get<_Index>(__self.__op_state_->__values_)
- .emplace((_Values&&)__vals...);
- }
- catch (...)
- {
- __self.__set_error(std::current_exception());
- }
- }
- }
- }
- __self.__op_state_->__arrive();
- }
-
- template <same_as<set_error_t> _Tag, class _Error>
- requires requires(_ErrorsVariant& __errors, _Error&& __err) {
- __errors.template emplace<__decay_t<_Error>>(
- (_Error&&)__err);
- }
- friend void tag_invoke(_Tag, __t&& __self, _Error&& __err) noexcept
- {
- __self.__set_error((_Error&&)__err);
- __self.__op_state_->__arrive();
- }
-
- template <same_as<set_stopped_t> _Tag>
- requires receiver_of<_Receiver, completion_signatures<_Tag()>>
- friend void tag_invoke(_Tag, __t&& __self) noexcept
- {
- __state_t __expected = __started;
- // Transition to the "stopped" state if and only if we're in the
- // "started" state. (If this fails, it's because we're in an
- // error state, which trumps cancellation.)
- if (__self.__op_state_->__state_.compare_exchange_strong(__expected,
- __stopped))
- {
- __self.__op_state_->__stop_source_.request_stop();
- }
- __self.__op_state_->__arrive();
- }
-
- friend __env_t<env_of_t<_Receiver>>
- tag_invoke(get_env_t, const __t& __self) noexcept
- {
- return __when_all::__make_env(get_env(__self.__op_state_->__rcvr_),
- __self.__op_state_->__stop_source_);
- }
-
- __operation_base<_ReceiverId, _ValuesTuple, _ErrorsVariant>*
- __op_state_;
- };
-};
-
template <class _Env, class _Sender>
using __values_opt_tuple_t = //
__value_types_of_t<_Sender, __env_t<_Env>,
@@ -7680,7 +5940,7 @@
__q<__msingle>>;
template <class _Env, __max1_sender<__env_t<_Env>>... _Senders>
-struct __traits_
+struct __traits
{
// tuple<optional<tuple<Vs1...>>, optional<tuple<Vs2...>>, ...>
using __values_tuple = //
@@ -7705,102 +5965,82 @@
std::exception_ptr>>;
};
-template <receiver _Receiver,
- __max1_sender<__env_t<env_of_t<_Receiver>>>... _Senders>
-struct __traits : __traits_<env_of_t<_Receiver>, _Senders...>
-{
- using _Traits = __traits_<env_of_t<_Receiver>, _Senders...>;
- using typename _Traits::__errors_variant;
- using typename _Traits::__values_tuple;
-
- template <std::size_t _Index>
- using __receiver =
- __t<__when_all::__receiver<_Index, __id<_Receiver>, __values_tuple,
- __errors_variant>>;
-
- using __operation_base =
- __when_all::__operation_base<__id<_Receiver>, __values_tuple,
- __errors_variant>;
-
- template <class _Sender, class _Index>
- using __op_state = connect_result_t<_Sender, __receiver<__v<_Index>>>;
-
- template <class _Tuple = __q<std::tuple>>
- using __op_states_tuple = //
- __minvoke<__mzip_with2<__q<__op_state>, _Tuple>, __types<_Senders...>,
- __mindex_sequence_for<_Senders...>>;
-};
-
-template <class _Cvref, class _ReceiverId, class... _SenderIds>
-using __traits_ex =
- __traits<__t<_ReceiverId>, __minvoke<_Cvref, __t<_SenderIds>>...>;
-
-template <class _Cvref, class _ReceiverId, class... _SenderIds>
-using __op_states_tuple_ex =
- typename __traits_ex<_Cvref, _ReceiverId,
- _SenderIds...>::template __op_states_tuple<>;
-
-template <class _Cvref, class _ReceiverId, class... _SenderIds>
- requires __mvalid<__op_states_tuple_ex, _Cvref, _ReceiverId, _SenderIds...>
-struct __operation
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
- using _Traits = __traits_ex<_Cvref, _ReceiverId, _SenderIds...>;
-
- using __operation_base_t = typename _Traits::__operation_base;
- using __op_states_tuple_t =
- __op_states_tuple_ex<_Cvref, _ReceiverId, _SenderIds...>;
-
- template <std::size_t _Index>
- using __receiver_t = typename _Traits::template __receiver<_Index>;
-
- struct __t : __operation_base_t
- {
- using __id = __operation;
-
- template <std::size_t... _Is, class... _Senders>
- __t(_Receiver __rcvr, __indices<_Is...>, _Senders&&... __sndrs) :
- __operation_base_t{{}, (_Receiver&&)__rcvr, {sizeof...(_Is)}},
- __op_states_{__conv{[&, this]() {
- return stdexec::connect((_Senders&&)__sndrs,
- __receiver_t<_Is>{this});
- }}...}
- {}
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- // register stop callback:
- __self.__on_stop_.emplace(
- get_stop_token(get_env(__self.__rcvr_)),
- __on_stop_requested{__self.__stop_source_});
- if (__self.__stop_source_.stop_requested())
- {
- // Stop has already been requested. Don't bother starting
- // the child operations.
- stdexec::set_stopped((_Receiver&&)__self.__rcvr_);
- }
- else
- {
- __apply(
- [](auto&... __child_ops) noexcept -> void {
- (stdexec::start(__child_ops), ...);
- },
- __self.__op_states_);
- if constexpr (sizeof...(_SenderIds) == 0)
- {
- __self.__complete();
- }
- }
- }
-
- __op_states_tuple_t __op_states_;
- };
-};
-
struct _INVALID_ARGUMENTS_TO_WHEN_ALL_
{};
-struct when_all_t : __domain::__get_env_common_domain<when_all_t>
+template <class _ErrorsVariant, class _ValuesTuple, class _StopToken>
+struct __when_all_state
+{
+ using __stop_callback_t =
+ typename _StopToken::template callback_type<__on_stop_request>;
+
+ template <class _Receiver>
+ void __arrive(_Receiver& __rcvr) noexcept
+ {
+ if (0 == --__count_)
+ {
+ __complete(__rcvr);
+ }
+ }
+
+ template <class _Receiver>
+ void __complete(_Receiver& __rcvr) noexcept
+ {
+ // Stop callback is no longer needed. Destroy it.
+ __on_stop_.reset();
+ // All child operations have completed and arrived at the barrier.
+ switch (__state_.load(std::memory_order_relaxed))
+ {
+ case __started:
+ if constexpr (!same_as<_ValuesTuple, __ignore>)
+ {
+ // All child operations completed successfully:
+ __when_all::__set_values(__rcvr, __values_);
+ }
+ break;
+ case __error:
+ if constexpr (!same_as<_ErrorsVariant,
+ std::variant<std::monostate>>)
+ {
+ // One or more child operations completed with an error:
+ std::visit(__complete_fn(set_error, __rcvr), __errors_);
+ }
+ break;
+ case __stopped:
+ stdexec::set_stopped((_Receiver&&)__rcvr);
+ break;
+ default:;
+ }
+ }
+
+ std::atomic<std::size_t> __count_;
+ in_place_stop_source __stop_source_{};
+ // Could be non-atomic here and atomic_ref everywhere except __completion_fn
+ std::atomic<__state_t> __state_{__started};
+ _ErrorsVariant __errors_{};
+ STDEXEC_ATTRIBUTE((no_unique_address)) _ValuesTuple __values_{};
+ std::optional<__stop_callback_t> __on_stop_{};
+};
+
+template <class _Env>
+static auto __mk_state_fn(const _Env& __env) noexcept
+{
+ return [&]<__max1_sender<__env_t<_Env>>... _Child>(__ignore, __ignore,
+ _Child&&...) {
+ using _Traits = __traits<_Env, _Child...>;
+ using _ErrorsVariant = typename _Traits::__errors_variant;
+ using _ValuesTuple = typename _Traits::__values_tuple;
+ using _State = __when_all_state<_ErrorsVariant, _ValuesTuple,
+ stop_token_of_t<_Env>>;
+ return _State{sizeof...(_Child), in_place_stop_source{}, __started,
+ _ErrorsVariant{}, _ValuesTuple{}, std::nullopt};
+ };
+}
+
+template <class _Env>
+using __mk_state_fn_t = decltype(__when_all::__mk_state_fn(__declval<_Env>()));
+
+struct when_all_t
{
// Used by the default_domain to find legacy customizations:
using _Sender = __1;
@@ -7816,73 +6056,161 @@
return stdexec::transform_sender(
__domain, __make_sexpr<when_all_t>(__(), (_Senders&&)__sndrs...));
}
+};
-#if STDEXEC_FRIENDSHIP_IS_LEXICAL()
- private:
- template <class...>
- friend struct stdexec::__sexpr;
-#endif
-
+struct __when_all_impl : __sexpr_defaults
+{
template <class _Self, class _Env>
- using __error = __mexception<_INVALID_ARGUMENTS_TO_WHEN_ALL_,
- __children_of<_Self, __q<_WITH_SENDERS_>>,
- _WITH_ENVIRONMENT_<_Env>>;
+ using __error_t = __mexception<_INVALID_ARGUMENTS_TO_WHEN_ALL_,
+ __children_of<_Self, __q<_WITH_SENDERS_>>,
+ _WITH_ENVIRONMENT_<_Env>>;
template <class _Self, class _Env>
using __completions = //
__children_of<_Self, __mbind_front_q<__completions_t, __env_t<_Env>>>;
- template <sender_expr_for<when_all_t> _Self, class _Env>
- static auto get_completion_signatures(_Self&&, _Env&&)
- {
- return __minvoke<__mtry_catch<__q<__completions>, __q<__error>>, _Self,
- _Env>();
- }
-
- template <class _Receiver, class _Indices>
- struct __connect_fn;
-
- template <class _Receiver, std::size_t... _Indices>
- struct __connect_fn<_Receiver, __indices<_Indices...>>
- {
- _Receiver* __rcvr_;
-
- template <std::size_t _Index, class... _Senders>
- using __receiver_t =
- typename __traits<_Receiver,
- _Senders...>::template __receiver<_Index>;
-
- template <class... _Senders>
- requires(sender_to<_Senders, __receiver_t<_Indices, _Senders...>> &&
- ...)
- auto operator()(__ignore, __ignore, _Senders&&... __sndrs) const
+ static constexpr auto get_attrs = //
+ []<class... _Child>(__ignore, const _Child&...) noexcept {
+ using _Domain = __domain::__common_domain_t<_Child...>;
+ if constexpr (same_as<_Domain, default_domain>)
{
- using _Cvref = __copy_cvref_fn<__mfront<_Senders..., int>>;
- using __operation_t =
- __t<__operation<_Cvref, __id<_Receiver>,
- __id<__decay_t<_Senders>>...>>;
- return __operation_t{(_Receiver&&)*__rcvr_,
- __indices<_Indices...>(),
- (_Senders&&)__sndrs...};
+ return empty_env();
+ }
+ else
+ {
+ return __mkprop(_Domain(), get_domain);
+ }
+ STDEXEC_UNREACHABLE();
+ };
+
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _Env>(_Self&&, _Env&&) noexcept {
+ static_assert(sender_expr_for<_Self, when_all_t>);
+ return __minvoke<__mtry_catch<__q<__completions>, __q<__error_t>>,
+ _Self, _Env>();
+ };
+
+ static constexpr auto get_env = //
+ []<class _State, class _Receiver>(__ignore, _State& __state,
+ const _Receiver& __rcvr) noexcept //
+ -> __env_t<env_of_t<const _Receiver&>> {
+ return __mkenv(stdexec::get_env(__rcvr), __state.__stop_source_);
+ };
+
+ static constexpr auto get_state = //
+ []<class _Self, class _Receiver>(_Self&& __self, _Receiver& __rcvr)
+ -> __sexpr_apply_result_t<_Self, __mk_state_fn_t<env_of_t<_Receiver>>> {
+ return __sexpr_apply((_Self&&)__self, __when_all::__mk_state_fn(
+ stdexec::get_env(__rcvr)));
+ };
+
+ static constexpr auto start = //
+ []<class _State, class _Receiver, class... _Operations>(
+ _State& __state, _Receiver& __rcvr,
+ _Operations&... __child_ops) noexcept -> void {
+ // register stop callback:
+ __state.__on_stop_.emplace(get_stop_token(stdexec::get_env(__rcvr)),
+ __on_stop_request{__state.__stop_source_});
+ if (__state.__stop_source_.stop_requested())
+ {
+ // Stop has already been requested. Don't bother starting
+ // the child operations.
+ stdexec::set_stopped(std::move(__rcvr));
+ }
+ else
+ {
+ (stdexec::start(__child_ops), ...);
+ if constexpr (sizeof...(__child_ops) == 0)
+ {
+ __state.__complete(__rcvr);
+ }
}
};
- template <class _Self, class _Receiver>
- using __connect_fn_for = //
- __connect_fn<_Receiver, __make_indices<__nbr_children_of<_Self>>>;
-
- template <sender_expr_for<when_all_t> _Self, class _Receiver>
- requires __callable<__sexpr_apply_t, _Self,
- __connect_fn_for<_Self, _Receiver>>
- static auto connect(_Self&& __self, _Receiver __rcvr)
+ template <class _State, class _Receiver, class _Error>
+ static void __set_error(_State& __state, _Receiver& __rcvr,
+ _Error&& __err) noexcept
{
- using __connect_fn = __connect_fn_for<_Self, _Receiver>;
- return __sexpr_apply((_Self&&)__self, __connect_fn{&__rcvr});
+ // TODO: What memory orderings are actually needed here?
+ if (__error != __state.__state_.exchange(__error))
+ {
+ __state.__stop_source_.request_stop();
+ // We won the race, free to write the error into the operation
+ // state without worry.
+ if constexpr (__nothrow_decay_copyable<_Error>)
+ {
+ __state.__errors_.template emplace<__decay_t<_Error>>(
+ (_Error&&)__err);
+ }
+ else
+ {
+ try
+ {
+ __state.__errors_.template emplace<__decay_t<_Error>>(
+ (_Error&&)__err);
+ }
+ catch (...)
+ {
+ __state.__errors_.template emplace<std::exception_ptr>(
+ std::current_exception());
+ }
+ }
+ }
}
+
+ static constexpr auto complete = //
+ []<class _Index, class _State, class _Receiver, class _SetTag,
+ class... _Args>(_Index, _State& __state, _Receiver& __rcvr, _SetTag,
+ _Args&&... __args) noexcept -> void {
+ if constexpr (same_as<_SetTag, set_error_t>)
+ {
+ __set_error(__state, __rcvr, (_Args&&)__args...);
+ }
+ else if constexpr (same_as<_SetTag, set_stopped_t>)
+ {
+ __state_t __expected = __started;
+ // Transition to the "stopped" state if and only if we're in the
+ // "started" state. (If this fails, it's because we're in an
+ // error state, which trumps cancellation.)
+ if (__state.__state_.compare_exchange_strong(__expected, __stopped))
+ {
+ __state.__stop_source_.request_stop();
+ }
+ }
+ else if constexpr (!same_as<decltype(_State::__values_), __ignore>)
+ {
+ // We only need to bother recording the completion values
+ // if we're not already in the "error" or "stopped" state.
+ if (__state.__state_ == __started)
+ {
+ auto& __opt_values = std::get<__v<_Index>>(__state.__values_);
+ static_assert(
+ same_as<decltype(*__opt_values),
+ __decayed_tuple<_Args...>&>,
+ "One of the senders in this when_all() is fibbing about what types it sends");
+ if constexpr ((__nothrow_decay_copyable<_Args> && ...))
+ {
+ __opt_values.emplace((_Args&&)__args...);
+ }
+ else
+ {
+ try
+ {
+ __opt_values.emplace((_Args&&)__args...);
+ }
+ catch (...)
+ {
+ __set_error(__state, __rcvr, std::current_exception());
+ }
+ }
+ }
+ }
+
+ __state.__arrive(__rcvr);
+ };
};
-struct when_all_with_variant_t :
- __domain::__get_env_common_domain<when_all_with_variant_t>
+struct when_all_with_variant_t
{
using _Sender = __1;
using __legacy_customizations_t = //
@@ -7912,6 +6240,23 @@
}
};
+struct __when_all_with_variant_impl : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ []<class... _Child>(__ignore, const _Child&...) noexcept {
+ using _Domain = __domain::__common_domain_t<_Child...>;
+ if constexpr (same_as<_Domain, default_domain>)
+ {
+ return empty_env();
+ }
+ else
+ {
+ return __mkprop(_Domain(), get_domain);
+ }
+ STDEXEC_UNREACHABLE();
+ };
+};
+
struct transfer_when_all_t
{
using _Env = __0;
@@ -7934,12 +6279,6 @@
(_Senders&&)__sndrs...));
}
- template <sender_expr_for<transfer_when_all_t> _Sender>
- static __data_of<const _Sender&> get_env(const _Sender& __self) noexcept
- {
- return __sexpr_apply(__self, __detail::__get_data());
- }
-
template <class _Sender, class _Env>
static auto transform_sender(_Sender&& __sndr, const _Env& __env)
{
@@ -7956,6 +6295,15 @@
}
};
+struct __transfer_when_all_impl : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ []<class _Data>(const _Data& __data,
+ const auto&...) noexcept -> const _Data& {
+ return __data;
+ };
+};
+
struct transfer_when_all_with_variant_t
{
using _Env = __0;
@@ -7978,16 +6326,10 @@
_Env{{(_Scheduler&&)__sched}}, (_Senders&&)__sndrs...));
}
- template <sender_expr_for<transfer_when_all_with_variant_t> _Sender>
- static __data_of<const _Sender&> get_env(const _Sender& __self) noexcept
- {
- return __sexpr_apply(__self, __detail::__get_data());
- }
-
template <class _Sender, class _Env>
static auto transform_sender(_Sender&& __sndr, const _Env& __env)
{
- // transform the transfer_when_allwith_variant into regular
+ // transform the transfer_when_all_with_variant into regular
// transform_when_all and into_variant calls/ (looking for early
// customizations), then transform it again to look for late
// customizations.
@@ -8001,6 +6343,15 @@
});
}
};
+
+struct __transfer_when_all_with_variant_impl : __sexpr_defaults
+{
+ static constexpr auto get_attrs = //
+ []<class _Data>(const _Data& __data,
+ const auto&...) noexcept -> const _Data& {
+ return __data;
+ };
+};
} // namespace __when_all
using __when_all::when_all_t;
@@ -8016,6 +6367,24 @@
inline constexpr transfer_when_all_with_variant_t
transfer_when_all_with_variant{};
+template <>
+struct __sexpr_impl<when_all_t> : __when_all::__when_all_impl
+{};
+
+template <>
+struct __sexpr_impl<when_all_with_variant_t> :
+ __when_all::__when_all_with_variant_impl
+{};
+
+template <>
+struct __sexpr_impl<transfer_when_all_t> : __when_all::__transfer_when_all_impl
+{};
+
+template <>
+struct __sexpr_impl<transfer_when_all_with_variant_t> :
+ __when_all::__transfer_when_all_with_variant_impl
+{};
+
namespace __read
{
template <class _Tag, class _ReceiverId>
@@ -8025,57 +6394,6 @@
concept __nothrow_t =
__nothrow_callable<_Tag, env_of_t<stdexec::__t<_ReceiverId>>>;
-// NOT TO SPEC: if the query returns a value, store the value in the operation
-// state and pass an rvalue reference to it.
-template <class _Tag, class _ReceiverId>
-struct __operation
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __t : __immovable
- {
- using __id = __operation;
- _Receiver __rcvr_;
- std::optional<__result_t<_Tag, _ReceiverId>> __result_;
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- constexpr bool _Nothrow =
- __nothrow_callable<_Tag, env_of_t<_Receiver>>;
- auto __query =
- [&]() noexcept(_Nothrow) -> __result_t<_Tag, _ReceiverId>&& {
- __self.__result_.emplace(__conv{[&]() noexcept(_Nothrow) {
- return _Tag()(get_env(__self.__rcvr_));
- }});
- return std::move(*__self.__result_);
- };
- stdexec::__set_value_invoke(std::move(__self.__rcvr_), __query);
- }
- };
-};
-
-// if the query returns a reference type, pass it straight through to the
-// receiver.
-template <class _Tag, class _ReceiverId>
- requires std::same_as<__result_t<_Tag, _ReceiverId>&&,
- __result_t<_Tag, _ReceiverId>>
-struct __operation<_Tag, _ReceiverId>
-{
- using _Receiver = stdexec::__t<_ReceiverId>;
-
- struct __t : __immovable
- {
- using __id = __operation;
- _Receiver __rcvr_;
-
- friend void tag_invoke(start_t, __t& __self) noexcept
- {
- stdexec::__set_value_invoke(std::move(__self.__rcvr_), _Tag(),
- get_env(__self.__rcvr_));
- }
- };
-};
-
inline constexpr __mstring __query_failed_diag =
"The current execution environment doesn't have a value for the given query."__csz;
@@ -8096,52 +6414,87 @@
completion_signatures<set_value_t(__call_result_t<_Tag, _Env>),
set_error_t(std::exception_ptr)>>;
-template <class _Tag>
-struct __sender
+template <class _Tag, class _Ty>
+struct __state
{
- using __t = __sender;
- using __id = __sender;
- using is_sender = void;
+ using __query = _Tag;
+ using __result = _Ty;
+ std::optional<_Ty> __result_;
+};
- template <class _Env>
- using __completions_t = __minvoke<
- __mtry_catch_q<__read::__completions_t, __q<__query_failed_error>>,
- _Tag, _Env>;
-
- template <class _Receiver>
- requires receiver_of<_Receiver, __completions_t<env_of_t<_Receiver>>>
- friend auto tag_invoke(connect_t, __sender, _Receiver __rcvr) //
- noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
- -> stdexec::__t<__operation<_Tag, stdexec::__id<_Receiver>>>
- {
- return {{}, (_Receiver&&)__rcvr};
- }
-
- template <class _Env>
- friend auto tag_invoke(get_completion_signatures_t, __sender, _Env&&)
- -> __completions_t<_Env>
- {
- return {};
- }
-
- friend empty_env tag_invoke(get_env_t, const __t&) noexcept
- {
- return {};
- }
+template <class _Tag, class _Ty>
+ requires same_as<_Ty, _Ty&&>
+struct __state<_Tag, _Ty>
+{
+ using __query = _Tag;
+ using __result = _Ty;
};
struct __read_t
{
template <class _Tag>
- constexpr __sender<_Tag> operator()(_Tag) const noexcept
+ constexpr auto operator()(_Tag) const noexcept
{
- return {};
+ return __make_sexpr<__read_t>(_Tag());
}
};
+
+struct __read_impl : __sexpr_defaults
+{
+ template <class _Tag, class _Env>
+ using __completions_t = __minvoke<
+ __mtry_catch_q<__read::__completions_t, __q<__query_failed_error>>,
+ _Tag, _Env>;
+
+ static constexpr auto get_completion_signatures = //
+ []<class _Self, class _Env>(const _Self&, _Env&&) noexcept //
+ -> __completions_t<__data_of<_Self>, _Env> {
+ static_assert(sender_expr_for<_Self, __read_t>);
+ return {};
+ };
+
+ static constexpr auto get_state = //
+ []<class _Self, class _Receiver>(const _Self&,
+ _Receiver& __rcvr) noexcept {
+ using __query = __data_of<_Self>;
+ using __result = __call_result_t<__query, env_of_t<_Receiver>>;
+ return __state<__query, __result>();
+ };
+
+ static constexpr auto start = //
+ []<class _State, class _Receiver>(_State& __state,
+ _Receiver& __rcvr) noexcept -> void {
+ using __query = typename _State::__query;
+ using __result = typename _State::__result;
+ if constexpr (same_as<__result, __result&&>)
+ {
+ // The query returns a reference type; pass it straight through to
+ // the receiver.
+ stdexec::__set_value_invoke(std::move(__rcvr), __query(),
+ stdexec::get_env(__rcvr));
+ }
+ else
+ {
+ constexpr bool _Nothrow =
+ __nothrow_callable<__query, env_of_t<_Receiver>>;
+ auto __query_fn = [&]() noexcept(_Nothrow) -> __result&& {
+ __state.__result_.emplace(__conv{[&]() noexcept(_Nothrow) {
+ return __query()(stdexec::get_env(__rcvr));
+ }});
+ return std::move(*__state.__result_);
+ };
+ stdexec::__set_value_invoke(std::move(__rcvr), __query_fn);
+ }
+ };
+};
} // namespace __read
inline constexpr __read::__read_t read{};
+template <>
+struct __sexpr_impl<__read::__read_t> : __read::__read_impl
+{};
+
namespace __queries
{
inline auto get_scheduler_t::operator()() const noexcept
@@ -8233,7 +6586,7 @@
{
struct __no_scheduler_in_environment
{
- using is_sender = void;
+ using sender_concept = sender_t;
using completion_signatures = //
__mexception<_CANNOT_RESTORE_EXECUTION_CONTEXT_AFTER_ON_<>,
_WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
@@ -8259,7 +6612,7 @@
template <class _Ty>
__always(_Ty) -> __always<_Ty>;
-struct on_t : __with_default_get_env<on_t>, __no_scheduler_in_environment
+struct on_t : __no_scheduler_in_environment
{
template <scheduler _Scheduler, sender _Sender>
auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const
@@ -8314,9 +6667,7 @@
__continue_on_data(_Scheduler, _Closure)
-> __continue_on_data<_Scheduler, _Closure>;
-struct continue_on_t :
- __with_default_get_env<continue_on_t>,
- __no_scheduler_in_environment
+struct continue_on_t : __no_scheduler_in_environment
{
template <sender _Sender, scheduler _Scheduler,
__sender_adaptor_closure_for<_Sender> _Closure>
@@ -8419,7 +6770,7 @@
{
struct __t
{
- using is_receiver = void;
+ using receiver_concept = receiver_t;
using __id = __receiver;
__state<_Values...>* __state_;
run_loop* __loop_;
@@ -8687,7 +7038,7 @@
//////////////////////////////////////////////////////////////////////////////////////////////////
struct __ignore_sender
{
- using is_sender = void;
+ using sender_concept = sender_t;
template <sender _Sender>
constexpr __ignore_sender(_Sender&&) noexcept
diff --git a/include/sdbusplus/async/stdexec/sequence_senders.hpp b/include/sdbusplus/async/stdexec/sequence_senders.hpp
index 88412e6..2f7b7e0 100644
--- a/include/sdbusplus/async/stdexec/sequence_senders.hpp
+++ b/include/sdbusplus/async/stdexec/sequence_senders.hpp
@@ -20,9 +20,12 @@
namespace exec
{
-struct sequence_tag
+struct sequence_sender_t : stdexec::sender_t
{};
+using sequence_tag [[deprecated("Renamed to exec::sequence_sender_t")]] =
+ exec::sequence_sender_t;
+
namespace __sequence_sndr
{
using namespace stdexec;
@@ -90,7 +93,7 @@
{
struct __t
{
- using is_receiver = void;
+ using receiver_concept = stdexec::receiver_t;
using __id = __stopped_means_break;
using _Receiver = stdexec::__t<_ReceiverId>;
using _Token = stop_token_of_t<env_of_t<_Receiver>>;
@@ -145,9 +148,9 @@
} // namespace __sequence_sndr
template <class _Sender>
-concept __enable_sequence_sender = //
- requires { typename _Sender::is_sender; } && //
- stdexec::same_as<typename _Sender::is_sender, sequence_tag>;
+concept __enable_sequence_sender = //
+ requires { typename _Sender::sender_concept; } && //
+ stdexec::same_as<typename _Sender::sender_concept, sequence_sender_t>;
template <class _Sender>
inline constexpr bool enable_sequence_sender =