stdexec: update to latest commit
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I1fa908582820eb1d8d64dcb4568dd52f80936ec1
diff --git a/include/sdbusplus/async/stdexec/__detail/__config.hpp b/include/sdbusplus/async/stdexec/__detail/__config.hpp
index 5be8786..0b3bc2d 100644
--- a/include/sdbusplus/async/stdexec/__detail/__config.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__config.hpp
@@ -21,28 +21,28 @@
#include <cassert>
-#define STDEXEC_CAT_(X, ...) X##__VA_ARGS__
-#define STDEXEC_CAT(X, ...) STDEXEC_CAT_(X, __VA_ARGS__)
+#define STDEXEC_CAT_(_Xp, ...) _Xp##__VA_ARGS__
+#define STDEXEC_CAT(_Xp, ...) STDEXEC_CAT_(_Xp, __VA_ARGS__)
#define STDEXEC_EXPAND(...) __VA_ARGS__
-#define STDEXEC_EVAL(M, ...) M(__VA_ARGS__)
+#define STDEXEC_EVAL(_M, ...) _M(__VA_ARGS__)
-#define STDEXEC_NOT(X) STDEXEC_CAT(STDEXEC_NOT_, X)
+#define STDEXEC_NOT(_Xp) STDEXEC_CAT(STDEXEC_NOT_, _Xp)
#define STDEXEC_NOT_0 1
#define STDEXEC_NOT_1 0
-#define STDEXEC_IIF_0(Y, ...) __VA_ARGS__
-#define STDEXEC_IIF_1(Y, ...) Y
-#define STDEXEC_IIF(X, Y, ...) \
- STDEXEC_EVAL(STDEXEC_CAT(STDEXEC_IIF_, X), Y, __VA_ARGS__)
+#define STDEXEC_IIF_0(_Yp, ...) __VA_ARGS__
+#define STDEXEC_IIF_1(_Yp, ...) _Yp
+#define STDEXEC_IIF(_Xp, _Yp, ...) \
+ STDEXEC_EVAL(STDEXEC_CAT(STDEXEC_IIF_, _Xp), _Yp, __VA_ARGS__)
#define STDEXEC_COUNT(...) \
STDEXEC_EXPAND(STDEXEC_COUNT_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
-#define STDEXEC_COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _N, ...) _N
+#define STDEXEC_COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _Np, ...) _Np
#define STDEXEC_CHECK(...) STDEXEC_EXPAND(STDEXEC_CHECK_N(__VA_ARGS__, 0, ))
-#define STDEXEC_CHECK_N(x, n, ...) n
-#define STDEXEC_PROBE(x) x, 1,
+#define STDEXEC_CHECK_N(_Xp, _Np, ...) _Np
+#define STDEXEC_PROBE(_Xp) _Xp, 1,
#if defined(__NVCOMPILER)
#define STDEXEC_NVHPC() 1
@@ -67,6 +67,24 @@
#define STDEXEC_MSVC() 0
#endif
+#if STDEXEC_CLANG()
+#define STDEXEC_STRINGIZE(__arg) #__arg
+#define STDEXEC_PRAGMA_PUSH() _Pragma("GCC diagnostic push")
+#define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop")
+#define STDEXEC_PRAGMA_IGNORE(__arg) \
+ _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __arg))
+#else
+#define STDEXEC_PRAGMA_PUSH()
+#define STDEXEC_PRAGMA_POP()
+#define STDEXEC_PRAGMA_IGNORE(__arg)
+#endif
+
+#ifdef __has_builtin
+#define STDEXEC_HAS_BUILTIN __has_builtin
+#else
+#define STDEXEC_HAS_BUILTIN(...) 0
+#endif
+
#if STDEXEC_CLANG() && defined(__CUDACC__)
#define STDEXEC_DETAIL_CUDACC_HOST_DEVICE __host__ __device__
#else
@@ -78,11 +96,11 @@
"Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead."
#endif
-#define STDEXEC_ASSERT(_X) \
+#define STDEXEC_ASSERT(_Xp) \
do \
{ \
- static_assert(noexcept(_X)); \
- STDEXEC_ASSERT_FN(_X); \
+ static_assert(noexcept(_Xp)); \
+ STDEXEC_ASSERT_FN(_Xp); \
} while (false)
#ifndef STDEXEC_ASSERT_FN
diff --git a/include/sdbusplus/async/stdexec/__detail/__intrusive_ptr.hpp b/include/sdbusplus/async/stdexec/__detail/__intrusive_ptr.hpp
index a79a353..3c163f0 100644
--- a/include/sdbusplus/async/stdexec/__detail/__intrusive_ptr.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__intrusive_ptr.hpp
@@ -48,6 +48,7 @@
// __intrusive_from_this() (which increments the atomic):
::new ((void*)__value_) _Ty{(_Us &&) __us...};
}
+
~__control_block()
{
__value().~_Ty();
@@ -156,6 +157,7 @@
}
bool operator==(const __intrusive_ptr&) const = default;
+
bool operator==(std::nullptr_t) const noexcept
{
return __data_ == nullptr;
diff --git a/include/sdbusplus/async/stdexec/__detail/__meta.hpp b/include/sdbusplus/async/stdexec/__detail/__meta.hpp
index 3d0cd50..5e2adde 100644
--- a/include/sdbusplus/async/stdexec/__detail/__meta.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__meta.hpp
@@ -31,14 +31,15 @@
struct __ignore
{
__ignore() = default;
+
constexpr __ignore(auto&&...) noexcept {}
};
// Before gcc-12, gcc really didn't like tuples or variants of immovable types
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 12)
-#define STDEXEC_IMMOVABLE(_X) _X(_X&&)
+#define STDEXEC_IMMOVABLE(_Xp) _Xp(_Xp&&)
#else
-#define STDEXEC_IMMOVABLE(_X) _X(_X&&) = delete
+#define STDEXEC_IMMOVABLE(_Xp) _Xp(_Xp&&) = delete
#endif
// BUG (gcc PR93711): copy elision fails when initializing a
@@ -53,9 +54,6 @@
struct __none_such
{};
-template <class...>
-concept __typename = true;
-
struct __immovable
{
__immovable() = default;
@@ -64,11 +62,22 @@
STDEXEC_IMMOVABLE(__immovable);
};
-template <class _T>
-using __t = typename _T::__t;
+struct __move_only
+{
+ __move_only() = default;
-template <bool _B>
-using __bool = std::bool_constant<_B>;
+ __move_only(__move_only&&) noexcept = default;
+ __move_only& operator=(__move_only&&) noexcept = default;
+
+ __move_only(const __move_only&) = delete;
+ __move_only& operator=(const __move_only&) = delete;
+};
+
+template <class _Tp>
+using __t = typename _Tp::__t;
+
+template <bool _Bp>
+using __mbool = std::bool_constant<_Bp>;
template <class _Ty>
struct __mtype
@@ -80,26 +89,29 @@
template <class...>
struct __types;
-template <class _T>
-using __midentity = _T;
+template <class... _Ts>
+concept __typename = requires { typename __types<_Ts...>; };
-template <std::size_t _N>
-using __msize_t = char[_N + 1];
+template <class _Tp>
+using __midentity = _Tp;
-template <class _T>
-inline constexpr auto __v = _T::value;
+template <std::size_t _Np>
+using __msize_t = char[_Np + 1];
-template <class _T, class _U>
-inline constexpr bool __v<std::is_same<_T, _U>> = false;
+template <class _Tp>
+inline constexpr auto __v = _Tp::value;
-template <class _T>
-inline constexpr bool __v<std::is_same<_T, _T>> = true;
+template <class _Tp, class _Up>
+inline constexpr bool __v<std::is_same<_Tp, _Up>> = false;
-template <class _T, _T _I>
-inline constexpr _T __v<std::integral_constant<_T, _I>> = _I;
+template <class _Tp>
+inline constexpr bool __v<std::is_same<_Tp, _Tp>> = true;
-template <std::size_t _I>
-inline constexpr std::size_t __v<char[_I]> = _I - 1;
+template <class _Tp, _Tp _Ip>
+inline constexpr _Tp __v<std::integral_constant<_Tp, _Ip>> = _Ip;
+
+template <std::size_t _Ip>
+inline constexpr std::size_t __v<char[_Ip]> = _Ip - 1;
template <bool>
struct __i
@@ -148,8 +160,8 @@
template <class _Fn, class... _Back>
using __mbind_back = __mbind_back_q<_Fn::template __f, _Back...>;
-template <template <class...> class _T, class... _Args>
-concept __valid = requires { typename __meval<_T, _Args...>; };
+template <template <class...> class _Tp, class... _Args>
+concept __valid = requires { typename __meval<_Tp, _Args...>; };
template <class _Fn, class... _Args>
concept __minvocable = __valid<_Fn::template __f, _Args...>;
@@ -165,12 +177,14 @@
template <class _Fn, class... _Args>
struct __mdefer_
{};
+
template <class _Fn, class... _Args>
requires __minvocable<_Fn, _Args...>
struct __mdefer_<_Fn, _Args...>
{
using __t = __minvoke<_Fn, _Args...>;
};
+
template <class _Fn, class... _Args>
struct __mdefer : __mdefer_<_Fn, _Args...>
{};
@@ -181,6 +195,7 @@
template <class _True, class...>
using __f = _True;
};
+
template <>
struct __if_<false>
{
@@ -200,11 +215,11 @@
requires(sizeof...(_False) <= 1)
using __if_c = __minvoke<__if_<_Pred>, _True, _False...>;
-template <class _T>
+template <class _Tp>
struct __mconst
{
template <class...>
- using __f = _T;
+ using __f = _Tp;
};
template <class _Fn, class _Default>
@@ -230,6 +245,7 @@
using __f = __minvoke<__mfold_right_<sizeof...(_Tail) == 0>, _Fn,
__minvoke<_Fn, _State, _Head>, _Tail...>;
};
+
template <>
struct __mfold_right_<true>
{ // empty pack
@@ -248,39 +264,58 @@
template <class _Continuation, class...>
struct __mconcat_
{};
+
template <class _Continuation, class... _As>
requires(sizeof...(_As) == 0) && __minvocable<_Continuation, _As...>
struct __mconcat_<_Continuation, _As...>
{
using __t = __minvoke<_Continuation, _As...>;
};
-template <class _Continuation, template <class...> class _A, class... _As>
+
+template <class _Continuation, template <class...> class _Ap, class... _As>
requires __minvocable<_Continuation, _As...>
-struct __mconcat_<_Continuation, _A<_As...>>
+struct __mconcat_<_Continuation, _Ap<_As...>>
{
using __t = __minvoke<_Continuation, _As...>;
};
-template <class _Continuation, template <class...> class _A, class... _As,
- template <class...> class _B, class... _Bs>
+
+template < //
+ class _Continuation, //
+ template <class...> class _Ap,
+ class... _As, //
+ template <class...> class _Bp, class... _Bs>
requires __minvocable<_Continuation, _As..., _Bs...>
-struct __mconcat_<_Continuation, _A<_As...>, _B<_Bs...>>
+struct __mconcat_<_Continuation, _Ap<_As...>, _Bp<_Bs...>>
{
using __t = __minvoke<_Continuation, _As..., _Bs...>;
};
-template <class _Continuation, template <class...> class _A, class... _As,
- template <class...> class _B, class... _Bs,
- template <class...> class _C, class... _Cs>
+
+template < //
+ class _Continuation, //
+ template <class...> class _Ap,
+ class... _As, //
+ template <class...> class _Bp,
+ class... _Bs, //
+ template <class...> class _Cp, class... _Cs>
requires __minvocable<_Continuation, _As..., _Bs..., _Cs...>
-struct __mconcat_<_Continuation, _A<_As...>, _B<_Bs...>, _C<_Cs...>>
+struct __mconcat_<_Continuation, _Ap<_As...>, _Bp<_Bs...>, _Cp<_Cs...>>
{
using __t = __minvoke<_Continuation, _As..., _Bs..., _Cs...>;
};
-template <class _Continuation, template <class...> class _A, class... _As,
- template <class...> class _B, class... _Bs,
- template <class...> class _C, class... _Cs,
- template <class...> class _D, class... _Ds, class... _Tail>
-struct __mconcat_<_Continuation, _A<_As...>, _B<_Bs...>, _C<_Cs...>, _D<_Ds...>,
- _Tail...> :
+
+template < //
+ class _Continuation, //
+ template <class...> class _Ap,
+ class... _As, //
+ template <class...> class _Bp,
+ class... _Bs, //
+ template <class...> class _Cp,
+ class... _Cs, //
+ template <class...> class _Dp,
+ class... _Ds, //
+ class... _Tail>
+struct __mconcat_<_Continuation, _Ap<_As...>, _Bp<_Bs...>, _Cp<_Cs...>,
+ _Dp<_Ds...>, _Tail...> :
__mconcat_<_Continuation, __types<_As..., _Bs..., _Cs..., _Ds...>, _Tail...>
{};
@@ -298,19 +333,21 @@
using __f = __minvoke<_Fn, _Ts...>;
};
-template <class _Fn, class _T>
+template <class _Fn, class _Tp>
struct __uncurry_;
-template <class _Fn, template <class...> class _A, class... _As>
+
+template <class _Fn, template <class...> class _Ap, class... _As>
requires __minvocable<_Fn, _As...>
-struct __uncurry_<_Fn, _A<_As...>>
+struct __uncurry_<_Fn, _Ap<_As...>>
{
using __t = __minvoke<_Fn, _As...>;
};
+
template <class _Fn>
struct __uncurry
{
- template <class _T>
- using __f = __t<__uncurry_<_Fn, _T>>;
+ template <class _Tp>
+ using __f = __t<__uncurry_<_Fn, _Tp>>;
};
template <class _Fn, class _List>
using __mapply = __minvoke<__uncurry<_Fn>, _List>;
@@ -335,11 +372,11 @@
using __f = __msize_t<(bool(__v<__minvoke<_Fn, _Ts>>) + ... + 0)>;
};
-template <class _T>
+template <class _Tp>
struct __contains
{
template <class... _Args>
- using __f = __bool<(__v<std::is_same<_T, _Args>> || ...)>;
+ using __f = __mbool<(__v<std::is_same<_Tp, _Args>> || ...)>;
};
template <class _Continuation = __q<__types>>
@@ -353,9 +390,10 @@
struct __push_back_unique
{
template <class _List, class _Item>
- using __f = __mapply<__if<__mapply<__contains<_Item>, _List>, _Continuation,
- __mbind_back<_Continuation, _Item>>,
- _List>;
+ using __f = //
+ __mapply<__if<__mapply<__contains<_Item>, _List>, _Continuation,
+ __mbind_back<_Continuation, _Item>>,
+ _List>;
};
template <class _Continuation = __q<__types>>
@@ -403,11 +441,20 @@
struct __remove
{
template <class... _Args>
- using __f =
+ using __f = //
__minvoke<__mconcat<_Continuation>, __if<std::is_same<_Args, _Old>,
__types<>, __types<_Args>>...>;
};
+template <class _Pred, class _Continuation = __q<__types>>
+struct __remove_if
+{
+ template <class... _Args>
+ using __f = //
+ __minvoke<__mconcat<_Continuation>,
+ __if<__minvoke<_Pred, _Args>, __types<>, __types<_Args>>...>;
+};
+
template <class _Return>
struct __qf
{
@@ -416,55 +463,60 @@
};
// A very simple std::declval replacement that doesn't handle void
-template <class _T>
-_T&& __declval() noexcept;
+template <class _Tp>
+_Tp&& __declval() noexcept;
// For copying cvref from one type to another:
struct __cp
{
- template <class _T>
- using __f = _T;
+ template <class _Tp>
+ using __f = _Tp;
};
+
struct __cpc
{
- template <class _T>
- using __f = const _T;
+ template <class _Tp>
+ using __f = const _Tp;
};
+
struct __cplr
{
- template <class _T>
- using __f = _T&;
+ template <class _Tp>
+ using __f = _Tp&;
};
+
struct __cprr
{
- template <class _T>
- using __f = _T&&;
+ template <class _Tp>
+ using __f = _Tp&&;
};
+
struct __cpclr
{
- template <class _T>
- using __f = const _T&;
+ template <class _Tp>
+ using __f = const _Tp&;
};
+
struct __cpcrr
{
- template <class _T>
- using __f = const _T&&;
+ template <class _Tp>
+ using __f = const _Tp&&;
};
template <class>
extern __cp __cpcvr;
-template <class _T>
-extern __cpc __cpcvr<const _T>;
-template <class _T>
-extern __cplr __cpcvr<_T&>;
-template <class _T>
-extern __cprr __cpcvr<_T&&>;
-template <class _T>
-extern __cpclr __cpcvr<const _T&>;
-template <class _T>
-extern __cpcrr __cpcvr<const _T&&>;
-template <class _T>
-using __copy_cvref_fn = decltype(__cpcvr<_T>);
+template <class _Tp>
+extern __cpc __cpcvr<const _Tp>;
+template <class _Tp>
+extern __cplr __cpcvr<_Tp&>;
+template <class _Tp>
+extern __cprr __cpcvr<_Tp&&>;
+template <class _Tp>
+extern __cpclr __cpcvr<const _Tp&>;
+template <class _Tp>
+extern __cpcrr __cpcvr<const _Tp&&>;
+template <class _Tp>
+using __copy_cvref_fn = decltype(__cpcvr<_Tp>);
template <class _From, class _To>
using __copy_cvref_t = __minvoke<__copy_cvref_fn<_From>, _To>;
@@ -488,21 +540,21 @@
// For hiding a template type parameter from ADL
template <class _Ty>
-struct _X
+struct _Xp
{
- using __t = struct _T
+ using __t = struct _Up
{
using __t = _Ty;
};
};
template <class _Ty>
-using __x = __t<_X<_Ty>>;
+using __x = __t<_Xp<_Ty>>;
template <class _Ty>
concept __has_id = requires { typename _Ty::__id; };
template <class _Ty>
-struct _Y
+struct _Yp
{
using __t = _Ty;
@@ -513,17 +565,19 @@
// a type that is setup to use ADL isolation.
// static_assert(!__has_id<std::remove_cvref_t<_Ty>>);
};
+
template <bool = true>
struct __id_
{
template <class _Ty>
using __f = typename _Ty::__id;
};
+
template <>
struct __id_<false>
{
template <class _Ty>
- using __f = _Y<_Ty>;
+ using __f = _Yp<_Ty>;
};
template <class _Ty>
using __id = __minvoke<__id_<__has_id<_Ty>>, _Ty>;
@@ -535,16 +589,18 @@
using __cvref_id = __copy_cvref_t<_From, __id<_To>>;
template <class _Fun, class... _As>
-concept __callable = requires(_Fun&& __fun, _As&&... __as) {
- ((_Fun &&) __fun)((_As &&) __as...);
- };
+concept __callable = //
+ requires(_Fun&& __fun, _As&&... __as) { //
+ ((_Fun &&) __fun)((_As &&) __as...); //
+ };
template <class _Fun, class... _As>
-concept __nothrow_callable = __callable<_Fun, _As...> &&
- requires(_Fun&& __fun, _As&&... __as) {
- {
- ((_Fun &&) __fun)((_As &&) __as...)
- } noexcept;
- };
+concept __nothrow_callable = //
+ __callable<_Fun, _As...> && //
+ requires(_Fun&& __fun, _As&&... __as) {
+ {
+ ((_Fun &&) __fun)((_As &&) __as...)
+ } noexcept;
+ };
#if STDEXEC_NVHPC()
// nvc++ doesn't cache the results of alias template specializations.
@@ -567,7 +623,7 @@
using __f = __call_result_t<_Fun, _As...>;
};
template <bool _Enable, class _Fun, class... _As>
-using __call_result_if_t = typename __if<__bool<_Enable>, __qcall_result,
+using __call_result_if_t = typename __if<__mbool<_Enable>, __qcall_result,
__>::template __f<_Fun, _As...>;
// For emplacing non-movable types into optionals:
@@ -577,10 +633,12 @@
{
_Fn __fn_;
using __t = __call_result_t<_Fn>;
+
operator __t() && noexcept(__nothrow_callable<_Fn>)
{
return ((_Fn &&) __fn_)();
}
+
__t operator()() && noexcept(__nothrow_callable<_Fn>)
{
return ((_Fn &&) __fn_)();
@@ -589,17 +647,29 @@
template <class _Fn>
__conv(_Fn) -> __conv<_Fn>;
-template <class _T>
-using __cref_t = const std::remove_reference_t<_T>&;
+// Implemented as a class instead of a free function
+// because of a bizarre nvc++ compiler bug:
+struct __cref_fn
+{
+ template <class _Ty>
+ const _Ty& operator()(const _Ty&);
+};
+template <class _Ty>
+using __cref_t = decltype(__cref_fn{}(__declval<_Ty>()));
template <class, class, class, class>
struct __mzip_with2_;
-template <class _Fn, class _Continuation, template <class...> class _C,
- class... _Cs, template <class...> class _D, class... _Ds>
+
+template < //
+ class _Fn, //
+ class _Continuation, //
+ template <class...> class _Cp,
+ class... _Cs, //
+ template <class...> class _Dp, class... _Ds>
requires requires {
typename __minvoke<_Continuation, __minvoke<_Fn, _Cs, _Ds>...>;
}
-struct __mzip_with2_<_Fn, _Continuation, _C<_Cs...>, _D<_Ds...>>
+struct __mzip_with2_<_Fn, _Continuation, _Cp<_Cs...>, _Dp<_Ds...>>
{
using __t = __minvoke<_Continuation, __minvoke<_Fn, _Cs, _Ds>...>;
};
@@ -607,8 +677,8 @@
template <class _Fn, class _Continuation = __q<__types>>
struct __mzip_with2
{
- template <class _C, class _D>
- using __f = __t<__mzip_with2_<_Fn, _Continuation, _C, _D>>;
+ template <class _Cp, class _Dp>
+ using __f = __t<__mzip_with2_<_Fn, _Continuation, _Cp, _Dp>>;
};
#if STDEXEC_GCC() && (__GNUC__ < 12)
@@ -617,16 +687,16 @@
template <std::size_t... _Indices>
extern __types<__msize_t<_Indices>...>
__mconvert_indices<std::index_sequence<_Indices...>>;
-template <std::size_t _N>
+template <std::size_t _Np>
using __mmake_index_sequence =
- decltype(stdexec::__mconvert_indices<std::make_index_sequence<_N>>);
+ decltype(stdexec::__mconvert_indices<std::make_index_sequence<_Np>>);
#else
template <std::size_t... _Indices>
__types<__msize_t<_Indices>...>
__mconvert_indices(std::index_sequence<_Indices...>*);
-template <std::size_t _N>
+template <std::size_t _Np>
using __mmake_index_sequence = decltype(stdexec::__mconvert_indices(
- (std::make_index_sequence<_N>*)nullptr));
+ (std::make_index_sequence<_Np>*)nullptr));
#endif
template <class... _Ts>
@@ -636,12 +706,14 @@
struct __mfind_if_
{
template <class _Fn, class _Continuation, class _Head, class... _Tail>
- using __f = __minvoke<
- __if_c<__v<__minvoke<_Fn, _Head>>, __mbind_front<_Continuation, _Head>,
- __mbind_front<__mfind_if_<(sizeof...(_Tail) != 0)>, _Fn,
- _Continuation>>,
- _Tail...>;
+ using __f = //
+ __minvoke<__if_c<__v<__minvoke<_Fn, _Head>>,
+ __mbind_front<_Continuation, _Head>,
+ __mbind_front<__mfind_if_<(sizeof...(_Tail) != 0)>,
+ _Fn, _Continuation>>,
+ _Tail...>;
};
+
template <>
struct __mfind_if_<false>
{
@@ -666,11 +738,11 @@
};
template <class... _Booleans>
-using __mand = __bool<(__v<_Booleans> && ...)>;
+using __mand = __mbool<(__v<_Booleans> && ...)>;
template <class... _Booleans>
-using __mor = __bool<(__v<_Booleans> || ...)>;
+using __mor = __mbool<(__v<_Booleans> || ...)>;
template <class _Boolean>
-using __mnot = __bool<!__v<_Boolean>>;
+using __mnot = __mbool<!__v<_Boolean>>;
template <class _Fn>
struct __mall_of
@@ -678,12 +750,14 @@
template <class... _Args>
using __f = __mand<__minvoke<_Fn, _Args>...>;
};
+
template <class _Fn>
struct __mnone_of
{
template <class... _Args>
using __f = __mand<__mnot<__minvoke<_Fn, _Args>>...>;
};
+
template <class _Fn>
struct __many_of
{
@@ -692,8 +766,8 @@
};
#if __has_builtin(__type_pack_element)
-template <std::size_t _N, class... _Ts>
-using __m_at = __type_pack_element<_N, _Ts...>;
+template <std::size_t _Np, class... _Ts>
+using __m_at = __type_pack_element<_Np, _Ts...>;
#else
template <std::size_t>
using __void_ptr = void*;
@@ -707,27 +781,27 @@
template <std::size_t... _Is>
struct __m_at_<std::index_sequence<_Is...>>
{
- template <class _U, class... _Us>
- static _U __f_(__void_ptr<_Is>..., _U*, _Us*...);
+ template <class _Up, class... _Us>
+ static _Up __f_(__void_ptr<_Is>..., _Up*, _Us*...);
template <class... _Ts>
using __f = __t<decltype(__m_at_::__f_(__mtype_ptr<_Ts>()...))>;
};
-template <std::size_t _N, class... _Ts>
-using __m_at = __minvoke<__m_at_<std::make_index_sequence<_N>>, _Ts...>;
+template <std::size_t _Np, class... _Ts>
+using __m_at = __minvoke<__m_at_<std::make_index_sequence<_Np>>, _Ts...>;
#endif
-template <std::size_t _N>
+template <std::size_t _Np>
struct __placeholder_;
-template <std::size_t _N>
-using __placeholder = __placeholder_<_N>*;
+template <std::size_t _Np>
+using __placeholder = __placeholder_<_Np>*;
using __0 = __placeholder<0>;
using __1 = __placeholder<1>;
using __2 = __placeholder<2>;
using __3 = __placeholder<3>;
-template <class _Ty, class _Noexcept = __bool<true>>
+template <class _Ty, class _Noexcept = __mbool<true>>
struct __mconstruct
{
template <class... _As>
@@ -739,8 +813,8 @@
}
};
-template <template <class...> class _C, class _Noexcept = __bool<true>>
-using __mconstructor_for = __mcompose<__q<__mconstruct>, __q<_C>>;
+template <template <class...> class _Cp, class _Noexcept = __mbool<true>>
+using __mconstructor_for = __mcompose<__q<__mconstruct>, __q<_Cp>>;
template <std::size_t>
using __ignore_t = __ignore;
@@ -750,7 +824,8 @@
{
return (_Ty &&) __t;
}
-template <std::size_t _N, class... _Ts>
+
+template <std::size_t _Np, class... _Ts>
constexpr decltype(auto) __nth_pack_element(_Ts&&... __ts) noexcept
{
return [&]<std::size_t... _Is>(std::index_sequence<_Is...>*) noexcept
@@ -758,7 +833,7 @@
{
return stdexec::__nth_pack_element_<_Is...>((_Ts &&) __ts...);
}
- ((std::make_index_sequence<_N>*)nullptr);
+ ((std::make_index_sequence<_Np>*)nullptr);
}
template <class _Ty>
@@ -770,42 +845,47 @@
return _Ty{};
}
};
-template <std::size_t _N>
-struct __mdispatch_<__placeholder<_N>>
+
+template <std::size_t _Np>
+struct __mdispatch_<__placeholder<_Np>>
{
template <class... _Ts>
decltype(auto) operator()(_Ts&&... __ts) const noexcept
{
- return stdexec::__nth_pack_element<_N>((_Ts &&) __ts...);
+ return stdexec::__nth_pack_element<_Np>((_Ts &&) __ts...);
}
};
-template <std::size_t _N>
-struct __mdispatch_<__placeholder<_N>&>
+
+template <std::size_t _Np>
+struct __mdispatch_<__placeholder<_Np>&>
{
template <class... _Ts>
decltype(auto) operator()(_Ts&&... __ts) const noexcept
{
- return stdexec::__nth_pack_element<_N>(__ts...);
+ return stdexec::__nth_pack_element<_Np>(__ts...);
}
};
-template <std::size_t _N>
-struct __mdispatch_<__placeholder<_N>&&>
+
+template <std::size_t _Np>
+struct __mdispatch_<__placeholder<_Np>&&>
{
template <class... _Ts>
decltype(auto) operator()(_Ts&&... __ts) const noexcept
{
- return std::move(stdexec::__nth_pack_element<_N>(__ts...));
+ return std::move(stdexec::__nth_pack_element<_Np>(__ts...));
}
};
-template <std::size_t _N>
-struct __mdispatch_<const __placeholder<_N>&>
+
+template <std::size_t _Np>
+struct __mdispatch_<const __placeholder<_Np>&>
{
template <class... _Ts>
decltype(auto) operator()(_Ts&&... __ts) const noexcept
{
- return std::as_const(stdexec::__nth_pack_element<_N>(__ts...));
+ return std::as_const(stdexec::__nth_pack_element<_Np>(__ts...));
}
};
+
template <class _Ret, class... _Args>
struct __mdispatch_<_Ret (*)(_Args...)>
{
@@ -826,6 +906,7 @@
template <class _Ty>
struct __mdispatch
{};
+
template <class _Ret, class... _Args>
struct __mdispatch<_Ret(_Args...)>
{
@@ -852,23 +933,27 @@
using __dispatch_result_t = __call_result_t<__mdispatch<_Ty>, _Ts...>;
template <class _Signature, class... _Args>
-using __try_dispatch_ = __bool<__dispatchable<_Signature, _Args...>>;
+using __try_dispatch_ = __mbool<__dispatchable<_Signature, _Args...>>;
+
template <class _Signatures, class _Continuation = __q<__mfront>>
struct __which
{};
-template <template <class...> class _C, class... _Signatures,
+
+template <template <class...> class _Cp, class... _Signatures,
class _Continuation>
-struct __which<_C<_Signatures...>, _Continuation>
+struct __which<_Cp<_Signatures...>, _Continuation>
{
template <class... _Args>
- using __f = __minvoke<
- __mfind_if<__mbind_back_q<__try_dispatch_, _Args...>, _Continuation>,
- _Signatures...>;
+ using __f = //
+ __minvoke<__mfind_if<__mbind_back_q<__try_dispatch_, _Args...>,
+ _Continuation>,
+ _Signatures...>;
};
template <class _Signatures, class _DefaultFn, class... _Args>
-using __make_dispatcher = __minvoke<
- __if_c<__minvocable<__which<_Signatures>, _Args...>,
- __mcompose<__q<__mdispatch>, __which<_Signatures>>, _DefaultFn>,
- _Args...>;
+using __make_dispatcher = //
+ __minvoke<
+ __if_c<__minvocable<__which<_Signatures>, _Args...>,
+ __mcompose<__q<__mdispatch>, __which<_Signatures>>, _DefaultFn>,
+ _Args...>;
} // namespace stdexec
diff --git a/include/sdbusplus/async/stdexec/__detail/__p2300.hpp b/include/sdbusplus/async/stdexec/__detail/__p2300.hpp
index b76f2ba..d76e65b 100644
--- a/include/sdbusplus/async/stdexec/__detail/__p2300.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__p2300.hpp
@@ -22,7 +22,9 @@
#else
#define STDEXEC_STD_DEPRECATED \
[[deprecated( \
- "Please access this entity in the ::stdexec:: namespace. Define STDEXEC_DISABLE_STD_DEPRECATIONS to silence this warning.")]]
+ "Please access this entity in the ::stdexec:: namespace. Define " \
+ "STDEXEC_DISABLE_STD_DEPRECATIONS to silence this " \
+ "warning.")]]
#endif
namespace std
@@ -161,7 +163,7 @@
// [exec.snd], senders
template <class _Sender, class _Env = stdexec::no_env>
-concept sender /*STDEXEC_STD_DEPRECATED*/ = stdexec::sender<_Sender, _Env>;
+concept sender /*STDEXEC_STD_DEPRECATED*/ = stdexec::sender_in<_Sender, _Env>;
template <class _Sender, class _Receiver>
concept sender_to /*STDEXEC_STD_DEPRECATED*/ =
@@ -186,14 +188,18 @@
using dependent_completion_signatures STDEXEC_STD_DEPRECATED =
stdexec::dependent_completion_signatures<_Env>;
-template <class _Sender, class _Env = stdexec::no_env,
- template <class...> class _Tuple = stdexec::__decayed_tuple,
- template <class...> class _Variant = stdexec::__variant>
+template < //
+ class _Sender, //
+ class _Env = stdexec::no_env, //
+ template <class...> class _Tuple = stdexec::__decayed_tuple, //
+ template <class...> class _Variant = stdexec::__variant>
using value_types_of_t STDEXEC_STD_DEPRECATED =
stdexec::value_types_of_t<_Sender, _Env, _Tuple, _Variant>;
-template <class _Sender, class _Env = stdexec::no_env,
- template <class...> class _Variant = stdexec::__variant>
+template < //
+ class _Sender, //
+ class _Env = stdexec::no_env, //
+ template <class...> class _Variant = stdexec::__variant>
using error_types_of_t STDEXEC_STD_DEPRECATED =
stdexec::error_types_of_t<_Sender, _Env, _Variant>;
@@ -329,14 +335,16 @@
stdexec::completion_signatures<_Sigs...>;
// [exec.utils.mkcmplsigs]
-template <class _Sender, class _Env = stdexec::no_env,
- class _Sigs = stdexec::completion_signatures<>,
- template <class...>
- class _SetValue = stdexec::__compl_sigs::__default_set_value,
- template <class>
- class _SetError = stdexec::__compl_sigs::__default_set_error,
- class _SetStopped =
- stdexec::completion_signatures<stdexec::set_stopped_t()>>
+template < //
+ class _Sender, //
+ class _Env = stdexec::no_env,
+ class _Sigs = stdexec::completion_signatures<>, //
+ template <class...>
+ class _SetValue = stdexec::__compl_sigs::__default_set_value, //
+ template <class>
+ class _SetError = stdexec::__compl_sigs::__default_set_error, //
+ class _SetStopped =
+ stdexec::completion_signatures<stdexec::set_stopped_t()>>
using make_completion_signatures STDEXEC_STD_DEPRECATED =
stdexec::make_completion_signatures<_Sender, _Env, _Sigs, _SetValue,
_SetError, _SetStopped>;
@@ -349,7 +357,7 @@
STDEXEC_STD_DEPRECATED
inline constexpr auto execute = stdexec::execute;
-#if !_STD_NO_COROUTINES_
+#if !STDEXEC_STD_NO_COROUTINES_
// [exec.as_awaitable]
using as_awaitable_t STDEXEC_STD_DEPRECATED = stdexec::as_awaitable_t;
STDEXEC_STD_DEPRECATED
@@ -359,7 +367,7 @@
template <class _Promise>
using with_awaitable_senders STDEXEC_STD_DEPRECATED =
stdexec::with_awaitable_senders<_Promise>;
-#endif // !_STD_NO_COROUTINES_
+#endif // !STDEXEC_STD_NO_COROUTINES_
} // namespace execution
namespace this_thread
diff --git a/include/sdbusplus/async/stdexec/__detail/__scope.hpp b/include/sdbusplus/async/stdexec/__detail/__scope.hpp
new file mode 100644
index 0000000..6f0f685
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/__detail/__scope.hpp
@@ -0,0 +1,113 @@
+/*
+ * 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 "__meta.hpp"
+
+namespace stdexec
+{
+template <class _Fn, class... _Ts>
+ requires __nothrow_callable<_Fn, _Ts...>
+struct __scope_guard;
+
+template <class _Fn>
+struct __scope_guard<_Fn>
+{
+ [[no_unique_address]] _Fn __fn_;
+ [[no_unique_address]] __immovable __hidden_{};
+ bool __dismissed_{false};
+
+ ~__scope_guard()
+ {
+ if (!__dismissed_)
+ ((_Fn &&) __fn_)();
+ }
+
+ void __dismiss() noexcept
+ {
+ __dismissed_ = true;
+ }
+};
+
+template <class _Fn, class _T0>
+struct __scope_guard<_Fn, _T0>
+{
+ [[no_unique_address]] _Fn __fn_;
+ [[no_unique_address]] _T0 __t0_;
+ [[no_unique_address]] __immovable __hidden_{};
+
+ bool __dismissed_{false};
+
+ void __dismiss() noexcept
+ {
+ __dismissed_ = true;
+ }
+
+ ~__scope_guard()
+ {
+ if (!__dismissed_)
+ ((_Fn &&) __fn_)((_T0 &&) __t0_);
+ }
+};
+
+template <class _Fn, class _T0, class _T1>
+struct __scope_guard<_Fn, _T0, _T1>
+{
+ [[no_unique_address]] _Fn __fn_;
+ [[no_unique_address]] _T0 __t0_;
+ [[no_unique_address]] _T1 __t1_;
+ [[no_unique_address]] __immovable __hidden_{};
+
+ bool __dismissed_{false};
+
+ void __dismiss() noexcept
+ {
+ __dismissed_ = true;
+ }
+
+ ~__scope_guard()
+ {
+ if (!__dismissed_)
+ ((_Fn &&) __fn_)((_T0 &&) __t0_, (_T1 &&) __t1_);
+ }
+};
+
+template <class _Fn, class _T0, class _T1, class _T2>
+struct __scope_guard<_Fn, _T0, _T1, _T2>
+{
+ [[no_unique_address]] _Fn __fn_;
+ [[no_unique_address]] _T0 __t0_;
+ [[no_unique_address]] _T1 __t1_;
+ [[no_unique_address]] _T2 __t2_;
+ [[no_unique_address]] __immovable __hidden_{};
+
+ bool __dismissed_{false};
+
+ void __dismiss() noexcept
+ {
+ __dismissed_ = true;
+ }
+
+ ~__scope_guard()
+ {
+ if (!__dismissed_)
+ ((_Fn &&) __fn_)((_T0 &&) __t0_, (_T1 &&) __t1_, (_T2 &&) __t2_);
+ }
+};
+
+template <class _Fn, class... _Ts>
+__scope_guard(_Fn, _Ts...) -> __scope_guard<_Fn, _Ts...>;
+} // namespace stdexec
diff --git a/include/sdbusplus/async/stdexec/any_sender_of.hpp b/include/sdbusplus/async/stdexec/any_sender_of.hpp
new file mode 100644
index 0000000..19e1b9e
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/any_sender_of.hpp
@@ -0,0 +1,1104 @@
+/* Copyright (c) 2023 Maikel Nadolski
+ * 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 <sdbusplus/async/stdexec/execution.hpp>
+
+#include <cstddef>
+
+namespace exec
+{
+namespace __any
+{
+using namespace stdexec;
+
+struct __create_vtable_t
+{
+ template <class _VTable, class _Tp>
+ requires __tag_invocable_r<const _VTable*, __create_vtable_t,
+ __mtype<_VTable>, __mtype<_Tp>>
+ constexpr const _VTable* operator()(__mtype<_VTable>,
+ __mtype<_Tp>) const noexcept
+ {
+ return tag_invoke(__create_vtable_t{}, __mtype<_VTable>{},
+ __mtype<_Tp>{});
+ }
+};
+
+inline constexpr __create_vtable_t __create_vtable{};
+
+template <class _Sig>
+struct __query_vfun;
+
+template <class _Tag, class _Ret, class... _As>
+struct __query_vfun<_Tag (*const)(_Ret (*)(_As...))>
+{
+ _Ret (*__fn_)(void*, _As...);
+
+ _Ret operator()(_Tag, void* __rcvr, _As&&... __as) const
+ {
+ return __fn_(__rcvr, (_As &&) __as...);
+ }
+};
+
+template <class _Tag, class _Ret, class... _As>
+struct __query_vfun<_Tag (*)(_Ret (*)(_As...))>
+{
+ _Ret (*__fn_)(void*, _As...);
+
+ _Ret operator()(_Tag, void* __rcvr, _As&&... __as) const
+ {
+ return __fn_(__rcvr, (_As &&) __as...);
+ }
+};
+
+template <class _Tag, class _Ret, class... _As>
+struct __query_vfun<_Tag (*const)(_Ret (*)(_As...) noexcept)>
+{
+ _Ret (*__fn_)(void*, _As...) noexcept;
+
+ _Ret operator()(_Tag, void* __rcvr, _As&&... __as) const noexcept
+ {
+ return __fn_(__rcvr, (_As &&) __as...);
+ }
+};
+
+template <class _Tag, class _Ret, class... _As>
+struct __query_vfun<_Tag (*)(_Ret (*)(_As...) noexcept)>
+{
+ _Ret (*__fn_)(void*, _As...) noexcept;
+
+ _Ret operator()(_Tag, void* __rcvr, _As&&... __as) const noexcept
+ {
+ return __fn_(__rcvr, (_As &&) __as...);
+ }
+};
+
+template <class>
+struct __query_vfun_fn;
+
+template <class _EnvProvider>
+ requires __callable<get_env_t, const _EnvProvider&>
+struct __query_vfun_fn<_EnvProvider>
+{
+ template <class _Tag, class _Ret, class... _As>
+ requires __callable<_Tag, env_of_t<const _EnvProvider&>, _As...>
+ constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...)))
+ const noexcept)(void*, _As...)
+ {
+ return +[](void* __env_provider, _As... __as) -> _Ret {
+ return _Tag{}(get_env(*(const _EnvProvider*)__env_provider),
+ (_As &&) __as...);
+ };
+ }
+
+ template <class _Tag, class _Ret, class... _As>
+ requires __callable<_Tag, env_of_t<const _EnvProvider&>, _As...>
+ constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...) noexcept))
+ const noexcept)(void*, _As...) noexcept
+ {
+ return +[](void* __env_provider, _As... __as) noexcept -> _Ret {
+ static_assert(
+ __nothrow_callable<_Tag, const env_of_t<_EnvProvider>&,
+ _As...>);
+ return _Tag{}(get_env(*(const _EnvProvider*)__env_provider),
+ (_As &&) __as...);
+ };
+ }
+};
+
+template <class _Queryable>
+ requires(!__callable<get_env_t, const _Queryable&>)
+struct __query_vfun_fn<_Queryable>
+{
+ template <class _Tag, class _Ret, class... _As>
+ requires __callable<_Tag, const _Queryable&, _As...>
+ constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...)))
+ const noexcept)(void*, _As...)
+ {
+ return +[](void* __queryable, _As... __as) -> _Ret {
+ return _Tag{}(*(const _Queryable*)__queryable, (_As &&) __as...);
+ };
+ }
+
+ template <class _Tag, class _Ret, class... _As>
+ requires __callable<_Tag, const _Queryable&, _As...>
+ constexpr _Ret (*operator()(_Tag (*)(_Ret (*)(_As...) noexcept))
+ const noexcept)(void*, _As...) noexcept
+ {
+ return +[](void* __env_provider, _As... __as) noexcept -> _Ret {
+ static_assert(__nothrow_callable<_Tag, const _Queryable&, _As...>);
+ return _Tag{}(*(const _Queryable*)__env_provider, (_As &&) __as...);
+ };
+ }
+};
+
+template <class _Sig>
+struct __storage_vfun;
+
+template <class _Tag, class... _As>
+struct __storage_vfun<_Tag(void (*)(_As...))>
+{
+ void (*__fn_)(void*, _As...) = [](void*, _As...) {};
+
+ void operator()(_Tag, void* __storage, _As&&... __as) const
+ {
+ return __fn_(__storage, (_As &&) __as...);
+ }
+};
+
+template <class _Tag, class... _As>
+struct __storage_vfun<_Tag(void (*)(_As...) noexcept)>
+{
+ void (*__fn_)(void*, _As...) noexcept = [](void*, _As...) noexcept {};
+
+ void operator()(_Tag, void* __storage, _As&&... __as) const noexcept
+ {
+ return __fn_(__storage, (_As &&) __as...);
+ }
+};
+
+template <class _Storage, class _Tp>
+struct __storage_vfun_fn
+{
+ template <class _Tag, class... _As>
+ requires __callable<_Tag, __mtype<_Tp>, _Storage&, _As...>
+ constexpr void (*operator()(_Tag (*)(void (*)(_As...)))
+ const noexcept)(void*, _As...)
+ {
+ return +[](void* __storage, _As... __as) -> void {
+ return _Tag{}(__mtype<_Tp>{}, *(_Storage*)__storage,
+ (_As &&) __as...);
+ };
+ }
+
+ template <class _Tag, class... _As>
+ requires __callable<_Tag, __mtype<_Tp>, _Storage&, _As...>
+ constexpr void (*operator()(_Tag (*)(void (*)(_As...) noexcept))
+ const noexcept)(void*, _As...) noexcept
+ {
+ return +[](void* __storage, _As... __as) noexcept -> void {
+ static_assert(
+ __nothrow_callable<_Tag, __mtype<_Tp>, _Storage&, _As...>);
+ return _Tag{}(__mtype<_Tp>{}, *(_Storage*)__storage,
+ (_As &&) __as...);
+ };
+ }
+};
+
+struct __delete_t
+{
+ template <class _Storage, class _Tp>
+ requires tag_invocable<__delete_t, __mtype<_Tp>, _Storage&>
+ void operator()(__mtype<_Tp>, _Storage& __storage) noexcept
+ {
+ static_assert(
+ nothrow_tag_invocable<__delete_t, __mtype<_Tp>, _Storage&>);
+ tag_invoke(__delete_t{}, __mtype<_Tp>{}, __storage);
+ }
+};
+
+inline constexpr __delete_t __delete{};
+
+struct __copy_construct_t
+{
+ template <class _Storage, class _Tp>
+ requires tag_invocable<__copy_construct_t, __mtype<_Tp>, _Storage&,
+ const _Storage&>
+ void operator()(
+ __mtype<_Tp>, _Storage& __self,
+ const _Storage&
+ __from) noexcept(nothrow_tag_invocable<__copy_construct_t,
+ __mtype<_Tp>, _Storage&,
+ const _Storage&>)
+ {
+ tag_invoke(__copy_construct_t{}, __mtype<_Tp>{}, __self, __from);
+ }
+};
+
+inline constexpr __copy_construct_t __copy_construct{};
+
+struct __move_construct_t
+{
+ template <class _Storage, class _Tp>
+ requires tag_invocable<__move_construct_t, __mtype<_Tp>, _Storage&,
+ _Storage&&>
+ void operator()(__mtype<_Tp>, _Storage& __self,
+ __midentity<_Storage&&> __from) noexcept
+ {
+ static_assert(nothrow_tag_invocable<__move_construct_t, __mtype<_Tp>,
+ _Storage&, _Storage&&>);
+ tag_invoke(__move_construct_t{}, __mtype<_Tp>{}, __self,
+ (_Storage &&) __from);
+ }
+};
+
+inline constexpr __move_construct_t __move_construct{};
+
+template <class _ParentVTable, class... _StorageCPOs>
+struct __storage_vtable;
+
+template <class _ParentVTable, class... _StorageCPOs>
+ requires requires { _ParentVTable::operator(); }
+struct __storage_vtable<_ParentVTable, _StorageCPOs...> :
+ _ParentVTable,
+ __storage_vfun<_StorageCPOs>...
+{
+ using _ParentVTable::operator();
+ using __storage_vfun<_StorageCPOs>::operator()...;
+};
+
+template <class _ParentVTable, class... _StorageCPOs>
+ requires(!requires { _ParentVTable::operator(); })
+struct __storage_vtable<_ParentVTable, _StorageCPOs...> :
+ _ParentVTable,
+ __storage_vfun<_StorageCPOs>...
+{
+ using __storage_vfun<_StorageCPOs>::operator()...;
+};
+
+template <class _ParentVTable, class... _StorageCPOs>
+inline constexpr __storage_vtable<_ParentVTable, _StorageCPOs...>
+ __null_storage_vtbl{};
+
+template <class _ParentVTable, class... _StorageCPOs>
+constexpr const __storage_vtable<_ParentVTable, _StorageCPOs...>*
+ __default_storage_vtable(
+ __storage_vtable<_ParentVTable, _StorageCPOs...>*) noexcept
+{
+ return &__null_storage_vtbl<_ParentVTable, _StorageCPOs...>;
+}
+
+template <class _Storage, class _Tp, class _ParentVTable, class... _StorageCPOs>
+static const __storage_vtable<_ParentVTable, _StorageCPOs...> __storage_vtbl{
+ {*__create_vtable(__mtype<_ParentVTable>{}, __mtype<_Tp>{})},
+ {__storage_vfun_fn<_Storage, _Tp>{}((_StorageCPOs*)nullptr)}...};
+
+template <class _Vtable, class _Allocator, bool _Copyable = false,
+ std::size_t _Alignment = alignof(std::max_align_t),
+ std::size_t _InlineSize = 3 * sizeof(void*)>
+struct __storage
+{
+ class __t;
+};
+
+template <class _Vtable, class _Allocator, bool _Copyable,
+ std::size_t _Alignment, std::size_t _InlineSize>
+class __storage<_Vtable, _Allocator, _Copyable, _Alignment, _InlineSize>::__t :
+ __if_c<_Copyable, __, __move_only>
+{
+ static_assert(
+ std::is_convertible_v<
+ typename std::allocator_traits<_Allocator>::void_pointer, void*>);
+
+ static constexpr std::size_t __buffer_size = std::max(_InlineSize,
+ sizeof(void*));
+ static constexpr std::size_t __alignment = std::max(_Alignment,
+ alignof(void*));
+ using __with_copy = __copy_construct_t(void(const __t&));
+ using __with_move = __move_construct_t(void(__t&&) noexcept);
+ using __with_delete = __delete_t(void() noexcept);
+
+ template <class _Tp>
+ static constexpr bool __is_small =
+ sizeof(_Tp) <= __buffer_size && alignof(_Tp) <= __alignment &&
+ std::is_nothrow_move_constructible_v<_Tp>;
+
+ using __vtable_t = __if_c<
+ _Copyable,
+ __storage_vtable<_Vtable, __with_delete, __with_move, __with_copy>,
+ __storage_vtable<_Vtable, __with_delete, __with_move>>;
+
+ template <class _Tp>
+ static constexpr const __vtable_t* __get_vtable_of_type() noexcept
+ {
+ if constexpr (_Copyable)
+ {
+ return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete,
+ __with_move, __with_copy>;
+ }
+ else
+ {
+ return &__storage_vtbl<__t, __decay_t<_Tp>, _Vtable, __with_delete,
+ __with_move>;
+ }
+ }
+
+ public:
+ using __id = __storage;
+
+ __t() = default;
+
+ template <__not_decays_to<__t> _Tp>
+ requires __callable<__create_vtable_t, __mtype<_Vtable>,
+ __mtype<__decay_t<_Tp>>>
+ __t(_Tp&& __object) : __vtable_{__get_vtable_of_type<_Tp>()}
+ {
+ using _Dp = __decay_t<_Tp>;
+ if constexpr (__is_small<_Dp>)
+ {
+ __construct_small<_Dp>((_Tp &&) __object);
+ }
+ else
+ {
+ __construct_large<_Dp>((_Tp &&) __object);
+ }
+ }
+
+ template <class _Tp, class... _Args>
+ requires __callable<__create_vtable_t, __mtype<_Vtable>, __mtype<_Tp>>
+ __t(std::in_place_type_t<_Tp>, _Args&&... __args) :
+ __vtable_{__get_vtable_of_type<_Tp>()}
+ {
+ if constexpr (__is_small<_Tp>)
+ {
+ __construct_small<_Tp>((_Args &&) __args...);
+ }
+ else
+ {
+ __construct_large<_Tp>((_Args &&) __args...);
+ }
+ }
+
+ __t(const __t& __other)
+ requires(_Copyable)
+ {
+ (*__other.__vtable_)(__copy_construct, this, __other);
+ }
+
+ __t& operator=(const __t& __other)
+ requires(_Copyable)
+ {
+ __t tmp(__other);
+ return *this = std::move(tmp);
+ }
+
+ __t(__t&& __other) noexcept
+ {
+ (*__other.__vtable_)(__move_construct, this, (__t &&) __other);
+ }
+
+ __t& operator=(__t&& __other) noexcept
+ {
+ __reset();
+ (*__other.__vtable_)(__move_construct, this, (__t &&) __other);
+ return *this;
+ }
+
+ ~__t()
+ {
+ __reset();
+ }
+
+ void __reset() noexcept
+ {
+ (*__vtable_)(__delete, this);
+ __object_pointer_ = nullptr;
+ __vtable_ = __default_storage_vtable((__vtable_t*)nullptr);
+ }
+
+ const _Vtable* __get_vtable() const noexcept
+ {
+ return __vtable_;
+ }
+
+ void* __get_object_pointer() const noexcept
+ {
+ return __object_pointer_;
+ }
+
+ private:
+ template <class _Tp, class... _As>
+ void __construct_small(_As&&... __args)
+ {
+ static_assert(sizeof(_Tp) <= __buffer_size &&
+ alignof(_Tp) <= __alignment);
+ _Tp* __pointer = static_cast<_Tp*>(static_cast<void*>(&__buffer_[0]));
+ using _Alloc = typename std::allocator_traits<
+ _Allocator>::template rebind_alloc<_Tp>;
+ _Alloc __alloc{__allocator_};
+ std::allocator_traits<_Alloc>::construct(__alloc, __pointer,
+ (_As &&) __args...);
+ __object_pointer_ = __pointer;
+ }
+
+ template <class _Tp, class... _As>
+ void __construct_large(_As&&... __args)
+ {
+ using _Alloc = typename std::allocator_traits<
+ _Allocator>::template rebind_alloc<_Tp>;
+ _Alloc __alloc{__allocator_};
+ _Tp* __pointer = std::allocator_traits<_Alloc>::allocate(__alloc, 1);
+ try
+ {
+ std::allocator_traits<_Alloc>::construct(__alloc, __pointer,
+ (_As &&) __args...);
+ }
+ catch (...)
+ {
+ std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
+ throw;
+ }
+ __object_pointer_ = __pointer;
+ }
+
+ template <class _Tp>
+ friend void tag_invoke(__delete_t, __mtype<_Tp>, __t& __self) noexcept
+ {
+ if (!__self.__object_pointer_)
+ {
+ return;
+ }
+ using _Alloc = typename std::allocator_traits<
+ _Allocator>::template rebind_alloc<_Tp>;
+ _Alloc __alloc{__self.__allocator_};
+ _Tp* __pointer =
+ static_cast<_Tp*>(std::exchange(__self.__object_pointer_, nullptr));
+ std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
+ if constexpr (!__is_small<_Tp>)
+ {
+ std::allocator_traits<_Alloc>::deallocate(__alloc, __pointer, 1);
+ }
+ }
+
+ template <class _Tp>
+ friend void tag_invoke(__move_construct_t, __mtype<_Tp>, __t& __self,
+ __t&& __other) noexcept
+ {
+ if (!__other.__object_pointer_)
+ {
+ return;
+ }
+ _Tp* __pointer = static_cast<_Tp*>(
+ std::exchange(__other.__object_pointer_, nullptr));
+ if constexpr (__is_small<_Tp>)
+ {
+ _Tp& __other_object = *__pointer;
+ __self.template __construct_small<_Tp>((_Tp &&) __other_object);
+ using _Alloc = typename std::allocator_traits<
+ _Allocator>::template rebind_alloc<_Tp>;
+ _Alloc __alloc{__self.__allocator_};
+ std::allocator_traits<_Alloc>::destroy(__alloc, __pointer);
+ }
+ else
+ {
+ __self.__object_pointer_ = __pointer;
+ }
+ __self.__vtable_ = std::exchange(
+ __other.__vtable_, __default_storage_vtable((__vtable_t*)nullptr));
+ }
+
+ template <class _Tp>
+ requires _Copyable
+ friend void tag_invoke(__copy_construct_t, __mtype<_Tp>, __t& __self,
+ const __t& __other)
+ {
+ if (!__other.__object_pointer_)
+ {
+ return;
+ }
+ const _Tp& __other_object =
+ *static_cast<const _Tp*>(__other.__object_pointer_);
+ if constexpr (__is_small<_Tp>)
+ {
+ __self.template __construct_small<_Tp>(__other_object);
+ }
+ else
+ {
+ __self.template __construct_large<_Tp>(__other_object);
+ }
+ __self.__vtable_ = __other.__vtable_;
+ }
+
+ const __vtable_t* __vtable_{__default_storage_vtable((__vtable_t*)nullptr)};
+ void* __object_pointer_{nullptr};
+ alignas(__alignment) std::byte __buffer_[__buffer_size]{};
+ [[no_unique_address]] _Allocator __allocator_{};
+};
+
+template <class _VTable, class _Allocator = std::allocator<std::byte>>
+using __unique_storage_t = __t<__storage<_VTable, _Allocator>>;
+
+template <class _VTable, class _Allocator = std::allocator<std::byte>>
+using __copyable_storage_t = __t<__storage<_VTable, _Allocator, true>>;
+
+namespace __rec
+{
+template <class _Sig>
+struct __rcvr_vfun;
+
+template <class _Sigs, class... _Queries>
+struct __vtable
+{
+ class __t;
+};
+
+template <class _Sigs, class... _Queries>
+struct __ref;
+
+template <class _Tag, class... _As>
+struct __rcvr_vfun<_Tag(_As...)>
+{
+ void (*__fn_)(void*, _As...) noexcept;
+};
+
+template <class _Rcvr>
+struct __rcvr_vfun_fn
+{
+ template <class _Tag, class... _As>
+ constexpr void (*operator()(_Tag (*)(_As...))
+ const noexcept)(void*, _As...) noexcept
+ {
+ return +[](void* __rcvr, _As... __as) noexcept -> void {
+ _Tag{}((_Rcvr &&) * (_Rcvr*)__rcvr, (_As &&) __as...);
+ };
+ }
+};
+
+template <class... _Sigs, class... _Queries>
+struct __vtable<completion_signatures<_Sigs...>, _Queries...>
+{
+ class __t : public __rcvr_vfun<_Sigs>..., public __query_vfun<_Queries>...
+ {
+ public:
+ using __query_vfun<_Queries>::operator()...;
+
+ private:
+ template <class _Rcvr>
+ requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
+ (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
+ friend const __t* tag_invoke(__create_vtable_t, __mtype<__t>,
+ __mtype<_Rcvr>) noexcept
+ {
+ static const __t __vtable_{
+ {__rcvr_vfun_fn<_Rcvr>{}((_Sigs*)nullptr)}...,
+ {__query_vfun_fn<_Rcvr>{}((_Queries) nullptr)}...};
+ return &__vtable_;
+ }
+ };
+};
+
+template <class... _Sigs, class... _Queries>
+struct __ref<completion_signatures<_Sigs...>, _Queries...>
+{
+ private:
+ using __vtable_t =
+ __t<__vtable<completion_signatures<_Sigs...>, _Queries...>>;
+
+ struct __env_t
+ {
+ const __vtable_t* __vtable_;
+ void* __rcvr_;
+
+ template <class _Tag, class... _As>
+ requires __callable<const __vtable_t&, _Tag, void*, _As...>
+ friend auto
+ tag_invoke(_Tag, const __env_t& __self, _As&&... __as) noexcept(
+ __nothrow_callable<const __vtable_t&, _Tag, void*, _As...>)
+ -> __call_result_t<const __vtable_t&, _Tag, void*, _As...>
+ {
+ return (*__self.__vtable_)(_Tag{}, __self.__rcvr_,
+ (_As &&) __as...);
+ }
+ } __env_;
+
+ public:
+ template <__none_of<__ref, const __ref, __env_t, const __env_t> _Rcvr>
+ requires receiver_of<_Rcvr, completion_signatures<_Sigs...>> &&
+ (__callable<__query_vfun_fn<_Rcvr>, _Queries> && ...)
+ __ref(_Rcvr& __rcvr) noexcept :
+ __env_{__create_vtable(__mtype<__vtable_t>{}, __mtype<_Rcvr>{}),
+ &__rcvr}
+ {}
+
+ template <__one_of<set_value_t, set_error_t, set_stopped_t> _Tag,
+ __decays_to<__ref> _Self, class... _As>
+ requires __one_of<_Tag(_As...), _Sigs...>
+ friend void tag_invoke(_Tag, _Self&& __self, _As&&... __as) noexcept
+ {
+ (*static_cast<const __rcvr_vfun<_Tag(_As...)>*>(__self.__env_.__vtable_)
+ ->__fn_)(((_Self &&) __self).__env_.__rcvr_, (_As &&) __as...);
+ }
+
+ template <std::same_as<__ref> Self>
+ friend const __env_t& tag_invoke(get_env_t, const Self& __self) noexcept
+ {
+ return __self.__env_;
+ }
+};
+} // namespace __rec
+
+class __operation_vtable
+{
+ public:
+ void (*__start_)(void*) noexcept;
+
+ private:
+ template <class _Op>
+ friend const __operation_vtable* tag_invoke(__create_vtable_t,
+ __mtype<__operation_vtable>,
+ __mtype<_Op>) noexcept
+ {
+ static __operation_vtable __vtable{
+ [](void* __object_pointer) noexcept -> void {
+ STDEXEC_ASSERT(__object_pointer);
+ _Op& __op = *static_cast<_Op*>(__object_pointer);
+ static_assert(operation_state<_Op>);
+ start(__op);
+ }};
+ return &__vtable;
+ }
+};
+
+using __unique_operation_storage = __unique_storage_t<__operation_vtable>;
+
+template <class _Sigs, class _Queries>
+using __receiver_ref =
+ __mapply<__mbind_front<__q<__rec::__ref>, _Sigs>, _Queries>;
+
+template <class _Receiver, class _Sigs, class _Queries>
+struct __operation_base
+{
+ [[no_unique_address]] _Receiver __receiver_;
+};
+
+template <class _Sender, class _Receiver, class _Queries>
+struct __operation
+{
+ using _Sigs = completion_signatures_of_t<_Sender>;
+ using __receiver_ref_t = __receiver_ref<_Sigs, _Queries>;
+
+ struct __rec
+ {
+ __operation_base<_Receiver, _Sigs, _Queries>* __op_;
+
+ template <__one_of<set_value_t, set_error_t, set_stopped_t> _CPO,
+ __decays_to<__rec> _Self, class... _Args>
+ requires __callable<_CPO, _Receiver&&, _Args...>
+ friend void tag_invoke(_CPO, _Self&& __self, _Args&&... __args) noexcept
+ {
+ _CPO{}((_Receiver &&) __self.__op_->__receiver_,
+ (_Args &&) __args...);
+ }
+
+ friend env_of_t<_Receiver> tag_invoke(get_env_t,
+ const __rec& __self) noexcept
+ {
+ return get_env(__self.__op_->__receiver_);
+ }
+ };
+
+ class __t : __immovable, __operation_base<_Receiver, _Sigs, _Queries>
+ {
+ public:
+ using __id = __operation;
+
+ __t(_Sender&& __sender, _Receiver&& __receiver) :
+ __operation_base<_Receiver, _Sigs, _Queries>{(_Receiver &&)
+ __receiver},
+ __storage_{__sender.__connect(__receiver_ref_t{__rec_})}
+ {}
+
+ private:
+ __rec __rec_{
+ static_cast<__operation_base<_Receiver, _Sigs, _Queries>*>(this)};
+ __unique_operation_storage __storage_{};
+
+ friend void tag_invoke(start_t, __t& __self) noexcept
+ {
+ STDEXEC_ASSERT(__self.__storage_.__get_vtable()->__start_);
+ __self.__storage_.__get_vtable()->__start_(
+ __self.__storage_.__get_object_pointer());
+ }
+ };
+};
+
+template <class _Queries>
+class __query_vtable;
+
+template <template <class...> class _L, typename... _Queries>
+class __query_vtable<_L<_Queries...>> : public __query_vfun<_Queries>...
+{
+ public:
+ using __query_vfun<_Queries>::operator()...;
+
+ private:
+ template <class _EnvProvider>
+ requires(__callable<__query_vfun_fn<_EnvProvider>, _Queries> && ...)
+ friend const __query_vtable* tag_invoke(__create_vtable_t,
+ __mtype<__query_vtable>,
+ __mtype<_EnvProvider>) noexcept
+ {
+ static const __query_vtable __vtable{
+ {__query_vfun_fn<_EnvProvider>{}((_Queries) nullptr)}...};
+ return &__vtable;
+ }
+};
+
+template <class _Sigs, class _SenderQueries = __types<>,
+ class _ReceiverQueries = __types<>>
+struct __sender
+{
+ using __receiver_ref_t = __receiver_ref<_Sigs, _ReceiverQueries>;
+
+ class __vtable : public __query_vtable<_SenderQueries>
+ {
+ public:
+ using __id = __vtable;
+
+ const __query_vtable<_SenderQueries>& __queries() const noexcept
+ {
+ return *this;
+ }
+
+ __unique_operation_storage (*__connect_)(void*, __receiver_ref_t);
+
+ private:
+ template <sender_to<__receiver_ref_t> _Sender>
+ friend const __vtable* tag_invoke(__create_vtable_t, __mtype<__vtable>,
+ __mtype<_Sender>) noexcept
+ {
+ static const __vtable __vtable_{
+ {*__create_vtable(__mtype<__query_vtable<_SenderQueries>>{},
+ __mtype<_Sender>{})},
+ [](void* __object_pointer,
+ __receiver_ref_t __receiver) -> __unique_operation_storage {
+ _Sender& __sender =
+ *static_cast<_Sender*>(__object_pointer);
+ using __op_state_t =
+ connect_result_t<_Sender, __receiver_ref_t>;
+ return __unique_operation_storage{
+ std::in_place_type<__op_state_t>, __conv{[&] {
+ return connect((_Sender &&) __sender,
+ (__receiver_ref_t &&) __receiver);
+ }}};
+ }};
+ return &__vtable_;
+ }
+ };
+
+ class __env_t
+ {
+ public:
+ __env_t(const __vtable* __vtable, void* __sender) noexcept :
+ __vtable_{__vtable}, __sender_{__sender}
+ {}
+
+ private:
+ const __vtable* __vtable_;
+ void* __sender_;
+
+ template <class _Tag, class... _As>
+ requires __callable<const __query_vtable<_SenderQueries>&, _Tag,
+ void*, _As...>
+ friend auto
+ tag_invoke(_Tag, const __env_t& __self, _As&&... __as) noexcept(
+ __nothrow_callable<const __query_vtable<_SenderQueries>&, _Tag,
+ void*, _As...>)
+ -> __call_result_t<const __query_vtable<_SenderQueries>&, _Tag,
+ void*, _As...>
+ {
+ return __self.__vtable_->__queries()(_Tag{}, __self.__sender_,
+ (_As &&) __as...);
+ }
+ };
+
+ class __t
+ {
+ public:
+ using __id = __sender;
+ using completion_signatures = _Sigs;
+ using is_sender = void;
+
+ __t(const __t&) = delete;
+ __t& operator=(const __t&) = delete;
+
+ __t(__t&&) = default;
+ __t& operator=(__t&&) = default;
+
+ template <__not_decays_to<__t> _Sender>
+ requires sender_to<_Sender, __receiver_ref<_Sigs, _ReceiverQueries>>
+ __t(_Sender&& __sndr) : __storage_{(_Sender &&) __sndr}
+ {}
+
+ __unique_operation_storage __connect(__receiver_ref_t __receiver)
+ {
+ return __storage_.__get_vtable()->__connect_(
+ __storage_.__get_object_pointer(),
+ (__receiver_ref_t &&) __receiver);
+ }
+
+ explicit operator bool() const noexcept
+ {
+ return __get_object_pointer(__storage_) != nullptr;
+ }
+
+ private:
+ __unique_storage_t<__vtable> __storage_;
+
+ template <receiver_of<_Sigs> _Rcvr>
+ friend stdexec::__t<
+ __operation<__t, __decay_t<_Rcvr>, _ReceiverQueries>>
+ tag_invoke(connect_t, __t&& __self, _Rcvr&& __rcvr)
+ {
+ return {(__t &&) __self, (_Rcvr &&) __rcvr};
+ }
+
+ friend __env_t tag_invoke(get_env_t, const __t& __self) noexcept
+ {
+ return {__self.__storage_.__get_vtable(),
+ __self.__storage_.__get_object_pointer()};
+ }
+ };
+};
+
+template <class _ScheduleSender, class _SchedulerQueries = __types<>>
+class __scheduler
+{
+ public:
+ template <class _Scheduler>
+ requires(!__decays_to<_Scheduler, __scheduler>) && scheduler<_Scheduler>
+ __scheduler(_Scheduler&& __scheduler) :
+ __storage_{(_Scheduler &&) __scheduler}
+ {}
+
+ using __sender_t = _ScheduleSender;
+
+ private:
+ class __vtable : public __query_vtable<_SchedulerQueries>
+ {
+ public:
+ __sender_t (*__schedule_)(void*) noexcept;
+ bool (*__equal_to_)(const void*, const void* other) noexcept;
+
+ const __query_vtable<_SchedulerQueries>& __queries() const noexcept
+ {
+ return *this;
+ }
+
+ private:
+ template <scheduler _Scheduler>
+ friend const __vtable* tag_invoke(__create_vtable_t, __mtype<__vtable>,
+ __mtype<_Scheduler>) noexcept
+ {
+ static const __vtable __vtable_{
+ {*__create_vtable(__mtype<__query_vtable<_SchedulerQueries>>{},
+ __mtype<_Scheduler>{})},
+ [](void* __object_pointer) noexcept -> __sender_t {
+ const _Scheduler& __scheduler =
+ *static_cast<const _Scheduler*>(__object_pointer);
+ return __sender_t{schedule(__scheduler)};
+ },
+ [](const void* __self, const void* __other) noexcept -> bool {
+ static_assert(noexcept(std::declval<const _Scheduler&>() ==
+ std::declval<const _Scheduler&>()));
+ STDEXEC_ASSERT(__self && __other);
+ const _Scheduler& __self_scheduler =
+ *static_cast<const _Scheduler*>(__self);
+ const _Scheduler& __other_scheduler =
+ *static_cast<const _Scheduler*>(__other);
+ return __self_scheduler == __other_scheduler;
+ }};
+ return &__vtable_;
+ }
+ };
+
+ template <same_as<__scheduler> _Self>
+ friend __sender_t tag_invoke(schedule_t, const _Self& __self) noexcept
+ {
+ STDEXEC_ASSERT(__self.__storage_.__get_vtable()->__schedule_);
+ return __self.__storage_.__get_vtable()->__schedule_(
+ __self.__storage_.__get_object_pointer());
+ }
+
+ template <class _Tag, same_as<__scheduler> _Self, class... _As>
+ requires __callable<const __query_vtable<_SchedulerQueries>&, _Tag,
+ void*, _As...>
+ friend auto tag_invoke(_Tag, const _Self& __self, _As&&... __as) noexcept(
+ __nothrow_callable<const __query_vtable<_SchedulerQueries>&, _Tag,
+ void*, _As...>)
+ -> __call_result_t<const __query_vtable<_SchedulerQueries>&, _Tag,
+ void*, _As...>
+ {
+ return __self.__storage_.__get_vtable()->__queries()(
+ _Tag{}, __self.__storage_.__get_object_pointer(), (_As &&) __as...);
+ }
+
+ friend bool operator==(const __scheduler& __self,
+ const __scheduler& __other) noexcept
+ {
+ if (__self.__storage_.__get_vtable() !=
+ __other.__storage_.__get_vtable())
+ {
+ return false;
+ }
+ void* __p = __self.__storage_.__get_object_pointer();
+ void* __o = __other.__storage_.__get_object_pointer();
+ // if both object pointers are not null, use the virtual equal_to
+ // function
+ return (__p && __o &&
+ __self.__storage_.__get_vtable()->__equal_to_(__p, __o))
+ // if both object pointers are nullptrs, they are equal
+ || (!__p && !__o);
+ }
+
+ friend bool operator!=(const __scheduler& __self,
+ const __scheduler& __other) noexcept
+ {
+ return !(__self == __other);
+ }
+
+ __copyable_storage_t<__vtable> __storage_{};
+};
+} // namespace __any
+
+template <auto... _Sigs>
+using queries = stdexec::__types<decltype(_Sigs)...>;
+
+template <class _Completions, auto... _ReceiverQueries>
+class any_receiver_ref
+{
+ using __receiver_base =
+ __any::__rec::__ref<_Completions, decltype(_ReceiverQueries)...>;
+ using __env_t = stdexec::env_of_t<__receiver_base>;
+ __receiver_base __receiver_;
+
+ template <class _Tag, stdexec::__decays_to<any_receiver_ref> Self,
+ class... _As>
+ requires stdexec::tag_invocable<
+ _Tag, stdexec::__copy_cvref_t<Self, __receiver_base>, _As...>
+ friend auto tag_invoke(_Tag, Self&& __self, _As&&... __as) noexcept(
+ std::is_nothrow_invocable_v<
+ _Tag, stdexec::__copy_cvref_t<Self, __receiver_base>, _As...>)
+ {
+ return tag_invoke(_Tag{}, ((Self &&) __self).__receiver_,
+ (_As &&) __as...);
+ }
+
+ public:
+ using is_receiver = void;
+
+ template <stdexec::__none_of<any_receiver_ref, const any_receiver_ref,
+ __env_t, const __env_t>
+ _Receiver>
+ requires stdexec::receiver_of<_Receiver, _Completions>
+ any_receiver_ref(_Receiver& __receiver) noexcept(
+ stdexec::__nothrow_constructible_from<__receiver_base, _Receiver>) :
+ __receiver_(__receiver)
+ {}
+
+ template <auto... _SenderQueries>
+ class any_sender
+ {
+ using __sender_base = stdexec::__t<
+ __any::__sender<_Completions, queries<_SenderQueries...>,
+ queries<_ReceiverQueries...>>>;
+ __sender_base __sender_;
+
+ template <class _Tag, stdexec::__decays_to<any_sender> Self,
+ class... _As>
+ requires stdexec::tag_invocable<
+ _Tag, stdexec::__copy_cvref_t<Self, __sender_base>, _As...>
+ friend auto tag_invoke(_Tag, Self&& __self, _As&&... __as) noexcept(
+ std::is_nothrow_invocable_v<
+ _Tag, stdexec::__copy_cvref_t<Self, __sender_base>, _As...>)
+ {
+ return tag_invoke(_Tag{}, ((Self &&) __self).__sender_,
+ (_As &&) __as...);
+ }
+
+ public:
+ using is_sender = void;
+ using completion_signatures =
+ typename __sender_base::completion_signatures;
+
+ template <class _Sender>
+ requires(!stdexec::__decays_to<_Sender, any_sender>) &&
+ stdexec::sender<_Sender>
+ any_sender(_Sender&& __sender) noexcept(
+ stdexec::__nothrow_constructible_from<__sender_base, _Sender>) :
+ __sender_((_Sender &&) __sender)
+ {}
+
+ template <auto... _SchedulerQueries>
+ class any_scheduler
+ {
+ using __schedule_completions =
+ stdexec::__concat_completion_signatures_t<
+ _Completions,
+ stdexec::completion_signatures<stdexec::set_value_t()>>;
+ using __schedule_receiver =
+ any_receiver_ref<__schedule_completions, _ReceiverQueries...>;
+
+ template <typename _Tag, typename _Sig>
+ static _Tag __ret_fn(_Tag (*const)(_Sig));
+
+ template <class _Tag>
+ struct __ret_equals_to
+ {
+ template <class _Sig>
+ using __f =
+ std::is_same<_Tag, decltype(__ret_fn((_Sig) nullptr))>;
+ };
+
+ using schedule_sender_queries = stdexec::__minvoke<
+ stdexec::__remove_if<__ret_equals_to<
+ stdexec::get_completion_scheduler_t<stdexec::set_value_t>>>,
+ decltype(_SenderQueries)...>;
+
+ template <class... _Queries>
+ using __schedule_sender_fn = typename __schedule_receiver::template any_sender<
+ stdexec::get_completion_scheduler<stdexec::set_value_t>.template signature<any_scheduler() noexcept>>;
+ using __schedule_sender =
+ stdexec::__mapply<stdexec::__q<__schedule_sender_fn>,
+ schedule_sender_queries>;
+
+ using __scheduler_base =
+ __any::__scheduler<__schedule_sender,
+ queries<_SchedulerQueries...>>;
+
+ __scheduler_base __scheduler_;
+
+ public:
+ template <class _Scheduler>
+ requires(!stdexec::__decays_to<_Scheduler, any_scheduler> &&
+ stdexec::scheduler<_Scheduler>)
+ any_scheduler(_Scheduler&& __scheduler) :
+ __scheduler_{(_Scheduler &&) __scheduler}
+ {}
+
+ private:
+ template <class _Tag, stdexec::__decays_to<any_scheduler> Self,
+ class... _As>
+ requires stdexec::tag_invocable<
+ _Tag, stdexec::__copy_cvref_t<Self, __scheduler_base>,
+ _As...>
+ friend auto tag_invoke(_Tag, Self&& __self, _As&&... __as) noexcept(
+ std::is_nothrow_invocable_v<
+ _Tag, stdexec::__copy_cvref_t<Self, __scheduler_base>,
+ _As...>)
+ {
+ return tag_invoke(_Tag{}, ((Self &&) __self).__scheduler_,
+ (_As &&) __as...);
+ }
+
+ friend bool
+ operator==(const any_scheduler& __self,
+ const any_scheduler& __other) noexcept = default;
+ };
+ };
+};
+} // namespace exec
diff --git a/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp b/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp
new file mode 100644
index 0000000..4db9d6a
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/at_coroutine_exit.hpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ * 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
+
+// The original idea is taken from libunifex and adapted to stdexec.
+
+#include "../stdexec/execution.hpp"
+#include "any_sender_of.hpp"
+#include "inline_scheduler.hpp"
+
+#include <exception>
+#include <type_traits>
+
+namespace exec
+{
+namespace __at_coro_exit
+{
+using namespace stdexec;
+
+using __any_scheduler = //
+ any_receiver_ref< //
+ completion_signatures<set_error_t(std::exception_ptr),
+ set_stopped_t()>> //
+ ::any_sender<>::any_scheduler<>;
+
+struct __die_on_stop_t
+{
+ template <class _Receiver>
+ struct __receiver_id
+ {
+ struct __t
+ {
+ using __id = __receiver_id;
+ _Receiver __receiver_;
+
+ template <__decays_to<__t> _Self, class... _Args>
+ requires __callable<set_value_t, _Receiver, _Args...>
+ friend void tag_invoke(set_value_t, _Self&& __self,
+ _Args&&... __args) noexcept
+ {
+ set_value((_Receiver &&) __self.__receiver_,
+ (_Args &&) __args...);
+ }
+
+ template <__decays_to<__t> _Self, class _Error>
+ requires __callable<set_error_t, _Receiver, _Error>
+ friend void tag_invoke(set_error_t, _Self&& __self,
+ _Error&& __error) noexcept
+ {
+ set_error((_Receiver &&) __self.__receiver_,
+ (_Error &&) __error);
+ }
+
+ [[noreturn]] friend void tag_invoke(set_stopped_t, __t&&) noexcept
+ {
+ std::terminate();
+ }
+
+ friend env_of_t<_Receiver> tag_invoke(get_env_t,
+ const __t& __self) noexcept
+ {
+ return get_env(__self.__receiver_);
+ }
+ };
+ };
+ template <class _Rec>
+ using __receiver = __t<__receiver_id<_Rec>>;
+
+ template <class _Sender>
+ struct __sender_id
+ {
+ template <class _Env>
+ using __completion_signatures = //
+ __mapply<__remove<set_stopped_t(), __q<completion_signatures>>,
+ completion_signatures_of_t<_Sender, _Env>>;
+
+ struct __t
+ {
+ using __id = __sender_id;
+ using is_sender = void;
+
+ _Sender __sender_;
+
+ template <receiver _Receiver>
+ requires sender_to<_Sender, __receiver<_Receiver>>
+ friend connect_result_t<_Sender, __receiver<_Receiver>>
+ tag_invoke(connect_t, __t&& __self, _Receiver&& __rcvr) noexcept
+ {
+ return connect((_Sender &&) __self.__sender_,
+ __receiver<_Receiver>{(_Receiver &&) __rcvr});
+ }
+
+ template <__decays_to<__t> _Self, class _Env>
+ friend auto tag_invoke(get_completion_signatures_t, _Self&&, _Env)
+ -> dependent_completion_signatures<_Env>;
+ template <__decays_to<__t> _Self, class _Env>
+ friend auto tag_invoke(get_completion_signatures_t, _Self&&, _Env)
+ -> __completion_signatures<_Env>
+ requires true;
+
+ friend env_of_t<_Sender> tag_invoke(get_env_t,
+ const __t& __self) noexcept
+ {
+ return get_env(__self.__sender_);
+ }
+ };
+ };
+ template <class _Sender>
+ using __sender = __t<__sender_id<__decay_t<_Sender>>>;
+
+ template <sender _Sender>
+ __sender<_Sender> operator()(_Sender&& __sndr) const
+ noexcept(__nothrow_decay_copyable<_Sender>)
+ {
+ return __sender<_Sender>{(_Sender &&) __sndr};
+ }
+
+ template <class _Value>
+ _Value&& operator()(_Value&& __value) const noexcept
+ {
+ return (_Value &&) __value;
+ }
+};
+
+inline constexpr __die_on_stop_t __die_on_stop;
+
+template <class _Promise>
+concept __has_continuation = //
+ requires(_Promise& __promise, __continuation_handle<> __c) {
+ {
+ __promise.continuation()
+ } -> convertible_to<__continuation_handle<>>;
+ {
+ __promise.set_continuation(__c)
+ };
+ };
+
+template <class... _Ts>
+class [[nodiscard]] __task
+{
+ struct __promise;
+
+ public:
+ using promise_type = __promise;
+
+ explicit __task(__coro::coroutine_handle<__promise> __coro) noexcept :
+ __coro_(__coro)
+ {}
+
+ __task(__task&& __that) noexcept :
+ __coro_(std::exchange(__that.__coro_, {}))
+ {}
+
+ bool await_ready() const noexcept
+ {
+ return false;
+ }
+
+ template <__has_continuation _Promise>
+ bool await_suspend(__coro::coroutine_handle<_Promise> __parent) noexcept
+ {
+ __coro_.promise().__scheduler_ =
+ get_scheduler(get_env(__parent.promise()));
+ __coro_.promise().set_continuation(__parent.promise().continuation());
+ __parent.promise().set_continuation(__coro_);
+ return false;
+ }
+
+ std::tuple<_Ts&...> await_resume() noexcept
+ {
+ return std::exchange(__coro_, {}).promise().__args_;
+ }
+
+ private:
+ struct __final_awaitable
+ {
+ static constexpr bool await_ready() noexcept
+ {
+ return false;
+ }
+
+ static __coro::coroutine_handle<>
+ await_suspend(__coro::coroutine_handle<__promise> __h) noexcept
+ {
+ __promise& __p = __h.promise();
+ auto __coro = __p.__is_unhandled_stopped_
+ ? __p.continuation().unhandled_stopped()
+ : __p.continuation().handle();
+ __h.destroy();
+ return __coro;
+ }
+
+ void await_resume() const noexcept {}
+ };
+
+ struct __env
+ {
+ const __promise& __promise_;
+
+ friend __any_scheduler tag_invoke(get_scheduler_t,
+ __env __self) noexcept
+ {
+ return __self.__promise_.__scheduler_;
+ }
+ };
+
+ struct __promise : with_awaitable_senders<__promise>
+ {
+ template <class _Action>
+ explicit __promise(_Action&&, _Ts&... __ts) noexcept : __args_{__ts...}
+ {}
+
+ __coro::suspend_always initial_suspend() noexcept
+ {
+ return {};
+ }
+
+ __final_awaitable final_suspend() noexcept
+ {
+ return {};
+ }
+
+ void return_void() noexcept {}
+
+ [[noreturn]] void unhandled_exception() noexcept
+ {
+ std::terminate();
+ }
+
+ __coro::coroutine_handle<__promise> unhandled_stopped() noexcept
+ {
+ __is_unhandled_stopped_ = true;
+ return __coro::coroutine_handle<__promise>::from_promise(*this);
+ }
+
+ __task get_return_object() noexcept
+ {
+ return __task(
+ __coro::coroutine_handle<__promise>::from_promise(*this));
+ }
+
+ template <class _Awaitable>
+ decltype(auto) await_transform(_Awaitable&& __awaitable) noexcept
+ {
+ return as_awaitable(__die_on_stop((_Awaitable &&) __awaitable),
+ *this);
+ }
+
+ friend __env tag_invoke(get_env_t, const __promise& __self) noexcept
+ {
+ return {__self};
+ }
+
+ bool __is_unhandled_stopped_{false};
+ std::tuple<_Ts&...> __args_{};
+ __any_scheduler __scheduler_{inline_scheduler{}};
+ };
+
+ __coro::coroutine_handle<__promise> __coro_;
+};
+
+struct __at_coro_exit_t
+{
+ private:
+ template <class _Action, class... _Ts>
+ static __task<_Ts...> __impl(_Action __action, _Ts... __ts)
+ {
+ co_await ((_Action &&) __action)((_Ts &&) __ts...);
+ }
+
+ public:
+ template <class _Action, class... _Ts>
+ requires __callable<__decay_t<_Action>, __decay_t<_Ts>...>
+ __task<_Ts...> operator()(_Action&& __action, _Ts&&... __ts) const
+ {
+ return __impl((_Action &&) __action, (_Ts &&) __ts...);
+ }
+};
+} // namespace __at_coro_exit
+
+inline constexpr __at_coro_exit::__at_coro_exit_t at_coroutine_exit{};
+} // namespace exec
diff --git a/include/sdbusplus/async/stdexec/commit.info b/include/sdbusplus/async/stdexec/commit.info
index a7276cd..0cebda7 100644
--- a/include/sdbusplus/async/stdexec/commit.info
+++ b/include/sdbusplus/async/stdexec/commit.info
@@ -1 +1 @@
-268b9d858c0a0e63af4806c3065dc096319375d6
+3bd568c7df8fcf725421254a27700f9ed1f64ff1
diff --git a/include/sdbusplus/async/stdexec/concepts.hpp b/include/sdbusplus/async/stdexec/concepts.hpp
index d95c44c..0e5cfb2 100644
--- a/include/sdbusplus/async/stdexec/concepts.hpp
+++ b/include/sdbusplus/async/stdexec/concepts.hpp
@@ -34,24 +34,26 @@
#include <type_traits>
#endif
+#include "__detail/__meta.hpp"
+
namespace stdexec::__std_concepts
{
#if defined(__clang__)
-template <class _A, class _B>
-concept __same_as = __is_same(_A, _B);
+template <class _Ap, class _Bp>
+concept __same_as = __is_same(_Ap, _Bp);
#elif defined(__GNUC__)
-template <class _A, class _B>
-concept __same_as = __is_same_as(_A, _B);
+template <class _Ap, class _Bp>
+concept __same_as = __is_same_as(_Ap, _Bp);
#else
-template <class _A, class _B>
+template <class _Ap, class _Bp>
inline constexpr bool __same_as = false;
-template <class _A>
-inline constexpr bool __same_as<_A, _A> = true;
+template <class _Ap>
+inline constexpr bool __same_as<_Ap, _Ap> = true;
#endif
// Make sure we're using a same_as concept that doesn't instantiate std::is_same
-template <class _A, class _B>
-concept same_as = __same_as<_A, _B> && __same_as<_B, _A>;
+template <class _Ap, class _Bp>
+concept same_as = __same_as<_Ap, _Bp> && __same_as<_Bp, _Ap>;
#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
@@ -65,74 +67,162 @@
template <class T>
concept integral = std::is_integral_v<T>;
-template <class _A, class _B>
-concept derived_from =
- std::is_base_of_v<_B, _A> &&
- std::is_convertible_v<const volatile _A*, const volatile _B*>;
+template <class _Ap, class _Bp>
+concept derived_from = //
+ std::is_base_of_v<_Bp, _Ap> && //
+ std::is_convertible_v<const volatile _Ap*, const volatile _Bp*>;
template <class _From, class _To>
-concept convertible_to =
- std::is_convertible_v<_From, _To> &&
+concept convertible_to = //
+ std::is_convertible_v<_From, _To> && //
requires(_From (&__fun)()) { static_cast<_To>(__fun()); };
-template <class _T>
-concept equality_comparable = requires(const std::remove_reference_t<_T>& __t) {
- {
- __t == __t
- } -> convertible_to<bool>;
- {
- __t != __t
- } -> convertible_to<bool>;
- };
+template <class _Ty>
+concept equality_comparable = //
+ requires(__cref_t<_Ty> __t) {
+ {
+ __t == __t
+ } -> convertible_to<bool>;
+ {
+ __t != __t
+ } -> convertible_to<bool>;
+ };
#endif
} // namespace stdexec::__std_concepts
namespace stdexec
{
using namespace __std_concepts;
-using std::decay_t;
-// // TODO: this makes nvc++ sad. Find out why.
-// template <class _Ty>
-// _Ty __decay__(const _Ty&);
-// template <class _Ty>
-// _Ty* __decay__(_Ty*);
+#if __has_builtin(__decay)
+template <class _Ty>
+using __decay_t = __decay(_Ty);
+#elif STDEXEC_NVHPC()
+template <class _Ty>
+using __decay_t = std::decay_t<_Ty>;
+#else
+namespace __tt
+{
+struct __decay_object
+{
+ template <class _Ty>
+ static _Ty __g(const _Ty&);
+ template <class _Ty>
+ using __f = decltype(__g(__declval<_Ty>()));
+};
-// template <class _Ty>
-// auto __decay_(_Ty&&(*__fn)()) -> decltype((__decay__)(__fn()));
-// template <class>
-// void __decay_(...);
+struct __decay_default
+{
+ template <class _Ty>
+ static _Ty __g(_Ty);
+ template <class _Ty>
+ using __f = decltype(__g(__declval<_Ty>()));
+};
-// template <class _Ty>
-// using decay_t = decltype((__decay_<_Ty>)(0));
+struct __decay_abominable
+{
+ template <class _Ty>
+ using __f = _Ty;
+};
+
+struct __decay_void
+{
+ template <class _Ty>
+ using __f = void;
+};
+
+template <class _Ty>
+extern __decay_object __mdecay;
+
+template <class _Ty, class... Us>
+extern __decay_default __mdecay<_Ty(Us...)>;
+
+template <class _Ty, class... Us>
+extern __decay_default __mdecay<_Ty(Us...) noexcept>;
+
+template <class _Ty, class... Us>
+extern __decay_default __mdecay<_Ty (&)(Us...)>;
+
+template <class _Ty, class... Us>
+extern __decay_default __mdecay<_Ty (&)(Us...) noexcept>;
+
+template <class _Ty, class... Us>
+extern __decay_abominable __mdecay<_Ty(Us...) const>;
+
+template <class _Ty, class... Us>
+extern __decay_abominable __mdecay<_Ty(Us...) const noexcept>;
+
+template <class _Ty, class... Us>
+extern __decay_abominable __mdecay<_Ty(Us...) const&>;
+
+template <class _Ty, class... Us>
+extern __decay_abominable __mdecay<_Ty(Us...) const & noexcept>;
+
+template <class _Ty, class... Us>
+extern __decay_abominable __mdecay<_Ty(Us...) const&&>;
+
+template <class _Ty, class... Us>
+extern __decay_abominable __mdecay<_Ty(Us...) const && noexcept>;
+
+template <class _Ty>
+extern __decay_default __mdecay<_Ty[]>;
+
+template <class _Ty, std::size_t N>
+extern __decay_default __mdecay<_Ty[N]>;
+
+template <class _Ty, std::size_t N>
+extern __decay_default __mdecay<_Ty (&)[N]>;
+
+template <>
+inline __decay_void __mdecay<void>;
+
+template <>
+inline __decay_void __mdecay<const void>;
+} // namespace __tt
+
+template <class _Ty>
+using __decay_t = typename decltype(__tt::__mdecay<_Ty>)::template __f<_Ty>;
+#endif
// C++20 concepts
-template <class _T, class _U>
-concept __decays_to = __same_as<decay_t<_T>, _U>;
+template <class _Ty, class _Up>
+concept __decays_to = __same_as<__decay_t<_Ty>, _Up>;
+
+template <class _Ty, class _Up>
+concept __not_decays_to = !
+__decays_to<_Ty, _Up>;
+
+template <bool _TrueOrFalse>
+concept __satisfies = _TrueOrFalse;
template <class...>
concept __true = true;
-template <class _C>
-concept __class = __true<int _C::*> && (!__same_as<const _C, _C>);
+template <class _Cp>
+concept __class = __true<int _Cp::*> && (!__same_as<const _Cp, _Cp>);
-template <class _T, class... _As>
-concept __one_of = (__same_as<_T, _As> || ...);
+template <class _Ty, class... _As>
+concept __one_of = (__same_as<_Ty, _As> || ...);
-template <class _T, class... _Us>
-concept __all_of = (__same_as<_T, _Us> && ...);
+template <class _Ty, class... _Us>
+concept __all_of = (__same_as<_Ty, _Us> && ...);
-template <class _T, class... _Us>
-concept __none_of = ((!__same_as<_T, _Us>) && ...);
+template <class _Ty, class... _Us>
+concept __none_of = ((!__same_as<_Ty, _Us>) && ...);
// Not exactly right, but close.
-template <class _T>
-concept __boolean_testable_ = convertible_to<_T, bool>;
+template <class _Ty>
+concept __boolean_testable_ = convertible_to<_Ty, bool>;
+
+template <class _Ty>
+inline constexpr bool __is_lvalue_reference_ = false;
+template <class _Ty>
+inline constexpr bool __is_lvalue_reference_<_Ty&> = true;
// Avoid using libstdc++'s object concepts because they instantiate a
// lot of templates.
template <class _Ty>
-inline constexpr bool __destructible_ =
+inline constexpr bool __destructible_ = //
requires {
{
((_Ty && (*)() noexcept) nullptr)().~_Ty()
@@ -142,60 +232,169 @@
inline constexpr bool __destructible_<_Ty&> = true;
template <class _Ty>
inline constexpr bool __destructible_<_Ty&&> = true;
-template <class _Ty, std::size_t _N>
-inline constexpr bool __destructible_<_Ty[_N]> = __destructible_<_Ty>;
+template <class _Ty, std::size_t _Np>
+inline constexpr bool __destructible_<_Ty[_Np]> = __destructible_<_Ty>;
template <class T>
concept destructible = __destructible_<T>;
#if __has_builtin(__is_constructible)
-template <class _T, class... _As>
-concept constructible_from = destructible<_T> && __is_constructible(_T, _As...);
+template <class _Ty, class... _As>
+concept constructible_from = //
+ destructible<_Ty> && //
+ __is_constructible(_Ty, _As...);
#else
-template <class _T, class... _As>
-concept constructible_from = destructible<_T> && is_constructible_v<_T, _As...>;
+template <class _Ty, class... _As>
+concept constructible_from = //
+ destructible<_Ty> && //
+ is_constructible_v<_Ty, _As...>;
#endif
-template <class _T>
-concept move_constructible = constructible_from<_T, _T>;
+template <class _Ty>
+concept default_initializable = //
+ constructible_from<_Ty> && //
+ requires { _Ty{}; } && //
+ requires { ::new _Ty; };
-template <class _T>
-concept copy_constructible = move_constructible<_T> &&
- constructible_from<_T, _T const&>;
+template <class _Ty>
+concept move_constructible = //
+ constructible_from<_Ty, _Ty>;
-template <class _T>
-concept __movable_value = move_constructible<decay_t<_T>> &&
- constructible_from<decay_t<_T>, _T>;
+template <class _Ty>
+concept copy_constructible = //
+ move_constructible<_Ty> //
+ && constructible_from<_Ty, const _Ty&>;
+
+template <class _LHS, class _RHS>
+concept assignable_from = //
+ __is_lvalue_reference_<_LHS> && //
+ // std::common_reference_with<
+ // const std::remove_reference_t<_LHS>&,
+ // const std::remove_reference_t<_RHS>&> &&
+ requires(_LHS __lhs, _RHS&& __rhs) {
+ {
+ __lhs = ((_RHS &&) __rhs)
+ } -> same_as<_LHS>;
+ };
+
+namespace __swap
+{
+using std::swap;
+
+template <class _Ty, class _Uy>
+concept swappable_with = //
+ requires(_Ty&& __t, _Uy&& __u) { swap((_Ty &&) __t, (_Uy &&) __u); };
+
+inline constexpr const auto __fn = //
+ []<class _Ty, swappable_with<_Ty> _Uy>(_Ty&& __t, _Uy&& __u) noexcept(
+ noexcept(swap((_Ty &&) __t, (_Uy &&) __u))) {
+ swap((_Ty &&) __t, (_Uy &&) __u);
+ };
+} // namespace __swap
+
+using __swap::swappable_with;
+inline constexpr const auto& swap = __swap::__fn;
+
+template <class _Ty>
+concept swappable = //
+ swappable_with<_Ty, _Ty>;
+
+template <class _Ty>
+concept movable = //
+ std::is_object_v<_Ty> && //
+ move_constructible<_Ty> && //
+ assignable_from<_Ty&, _Ty> && //
+ swappable<_Ty>;
+
+template <class _Ty>
+concept copyable = //
+ copy_constructible<_Ty> && //
+ movable<_Ty> && //
+ assignable_from<_Ty&, _Ty&> && //
+ assignable_from<_Ty&, const _Ty&> && //
+ assignable_from<_Ty&, const _Ty>;
+
+template <class _Ty>
+concept semiregular = //
+ copyable<_Ty> && //
+ default_initializable<_Ty>;
+
+template <class _Ty>
+concept regular = //
+ semiregular<_Ty> && //
+ equality_comparable<_Ty>;
+
+template <class T, class U>
+concept __partially_ordered_with = //
+ requires(__cref_t<T> t, __cref_t<U> u) {
+ {
+ t < u
+ } -> __boolean_testable_;
+ {
+ t > u
+ } -> __boolean_testable_;
+ {
+ t <= u
+ } -> __boolean_testable_;
+ {
+ t >= u
+ } -> __boolean_testable_;
+ {
+ u < t
+ } -> __boolean_testable_;
+ {
+ u > t
+ } -> __boolean_testable_;
+ {
+ u <= t
+ } -> __boolean_testable_;
+ {
+ u >= t
+ } -> __boolean_testable_;
+ };
+
+template <class _Ty>
+concept totally_ordered = //
+ equality_comparable<_Ty> && //
+ __partially_ordered_with<_Ty, _Ty>;
+
+template <class _Ty>
+concept __movable_value = //
+ move_constructible<__decay_t<_Ty>> && //
+ constructible_from<__decay_t<_Ty>, _Ty>;
template <class _Trait>
concept __is_true = _Trait::value;
template <class, template <class...> class>
constexpr bool __is_instance_of_ = false;
-template <class... _As, template <class...> class _T>
-constexpr bool __is_instance_of_<_T<_As...>, _T> = true;
+template <class... _As, template <class...> class _Ty>
+constexpr bool __is_instance_of_<_Ty<_As...>, _Ty> = true;
-template <class _Ty, template <class...> class _T>
-concept __is_instance_of = __is_instance_of_<_Ty, _T>;
+template <class _Ay, template <class...> class _Ty>
+concept __is_instance_of = __is_instance_of_<_Ay, _Ty>;
-template <class _Ty, template <class...> class _T>
+template <class _Ay, template <class...> class _Ty>
concept __is_not_instance_of = !
-__is_instance_of<_Ty, _T>;
+__is_instance_of<_Ay, _Ty>;
#if __has_builtin(__is_nothrow_constructible)
-template <class _T, class... _As>
-concept __nothrow_constructible_from = constructible_from<_T, _As...> &&
- __is_nothrow_constructible(_T, _As...);
+template <class _Ty, class... _As>
+concept __nothrow_constructible_from = constructible_from<_Ty, _As...> &&
+ __is_nothrow_constructible(_Ty, _As...);
#else
-template <class _T, class... _As>
+template <class _Ty, class... _As>
concept __nothrow_constructible_from =
- constructible_from<_T, _As...> &&
- std::is_nothrow_constructible_v<_T, _As...>;
+ constructible_from<_Ty, _As...> &&
+ std::is_nothrow_constructible_v<_Ty, _As...>;
#endif
template <class _Ty>
+concept __decay_copyable = constructible_from<__decay_t<_Ty>, _Ty>;
+
+template <class _Ty>
concept __nothrow_decay_copyable =
- __nothrow_constructible_from<decay_t<_Ty>, _Ty>;
+ __nothrow_constructible_from<__decay_t<_Ty>, _Ty>;
} // namespace stdexec
#if !STDEXEC_HAS_STD_CONCEPTS_HEADER()
diff --git a/include/sdbusplus/async/stdexec/coroutine.hpp b/include/sdbusplus/async/stdexec/coroutine.hpp
index 597355a..ee0b6fd 100644
--- a/include/sdbusplus/async/stdexec/coroutine.hpp
+++ b/include/sdbusplus/async/stdexec/coroutine.hpp
@@ -25,20 +25,21 @@
#include <experimental/coroutine>
namespace __coro = std::experimental;
#else
-#define _STD_NO_COROUTINES_ 1
+#define STDEXEC_STD_NO_COROUTINES_ 1
#endif
namespace stdexec
{
-#if !_STD_NO_COROUTINES_
+#if !STDEXEC_STD_NO_COROUTINES_
// Define some concepts and utilities for working with awaitables
-template <class _T>
-concept __await_suspend_result = __one_of<_T, void, bool> ||
- __is_instance_of<_T, __coro::coroutine_handle>;
+template <class _Tp>
+concept __await_suspend_result =
+ __one_of<_Tp, void, bool> ||
+ __is_instance_of<_Tp, __coro::coroutine_handle>;
template <class _Awaiter, class _Promise>
concept __with_await_suspend =
- same_as<_Promise, void> ||
+ same_as<_Promise, void> || //
requires(_Awaiter& __await, __coro::coroutine_handle<_Promise> __h) {
{
__await.await_suspend(__h)
@@ -46,10 +47,12 @@
};
template <class _Awaiter, class _Promise = void>
-concept __awaiter = requires(_Awaiter& __await) {
- __await.await_ready() ? 1 : 0;
- __await.await_resume();
- } && __with_await_suspend<_Awaiter, _Promise>;
+concept __awaiter = //
+ requires(_Awaiter& __await) {
+ __await.await_ready() ? 1 : 0;
+ __await.await_resume();
+ } && //
+ __with_await_suspend<_Awaiter, _Promise>;
template <class _Awaitable>
decltype(auto) __get_awaiter(_Awaitable&& __await, void*)
@@ -97,15 +100,15 @@
}
template <class _Awaitable, class _Promise = void>
-concept __awaitable =
+concept __awaitable = //
requires(_Awaitable&& __await, _Promise* __promise) {
{
stdexec::__get_awaiter((_Awaitable &&) __await, __promise)
} -> __awaiter<_Promise>;
};
-template <class _T>
-_T& __as_lvalue(_T&&);
+template <class _Tp>
+_Tp& __as_lvalue(_Tp&&);
template <class _Awaitable, class _Promise = void>
requires __awaitable<_Awaitable, _Promise>
diff --git a/include/sdbusplus/async/stdexec/execution.hpp b/include/sdbusplus/async/stdexec/execution.hpp
index be0acf3..d0f0bb1 100644
--- a/include/sdbusplus/async/stdexec/execution.hpp
+++ b/include/sdbusplus/async/stdexec/execution.hpp
@@ -17,6 +17,7 @@
#include "__detail/__intrusive_ptr.hpp"
#include "__detail/__meta.hpp"
+#include "__detail/__scope.hpp"
#include "concepts.hpp"
#include "coroutine.hpp"
#include "functional.hpp"
@@ -35,22 +36,6 @@
#include <type_traits>
#include <variant>
-#if STDEXEC_CLANG()
-#define STDEXEC_STRINGIZE(__arg) #__arg
-#define STDEXEC_PRAGMA_PUSH() _Pragma("GCC diagnostic push")
-#define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop")
-#define STDEXEC_PRAGMA_IGNORE(__arg) \
- _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __arg))
-#else
-#define STDEXEC_PRAGMA_PUSH()
-#define STDEXEC_PRAGMA_POP()
-#define STDEXEC_PRAGMA_IGNORE(__arg)
-#endif
-
-#if STDEXEC_NVHPC() || STDEXEC_GCC()
-#define STDEXEC_NON_LEXICAL_FRIENDSHIP 1
-#endif
-
#ifdef __EDG__
#pragma diagnostic push
#pragma diag_suppress 1302
@@ -58,35 +43,42 @@
#endif
#ifdef STDEXEC_ENABLE_R5_DEPRECATIONS
-#define R5_SENDER_DEPR_WARNING \
- [[deprecated( \
- "Deprecated sender type detected. Please update the type to satisfy the boolean stdexec::enable_sender<S> trait. Defining a member type alias named 'is_sender' is one way to do this.")]]
-#define R5_RECEIVER_DEPR_WARNING \
- [[deprecated( \
- "Deprecated receiver type detected. Please update the type for to satisfy the boolean stdexec::enable_receiver<R> trait. Defining a member type alias named 'is_receiver' is one way to do this.")]]
+#define STDEXEC_R5_SENDER_DEPR_WARNING \
+ [[deprecated( \
+ "Deprecated sender type detected. Please update the type to satisfy the boolean " \
+ "stdexec::enable_sender<S> trait. " \
+ "Defining a member type alias named 'is_sender' is one way to do this.")]]
+#define STDEXEC_R5_RECEIVER_DEPR_WARNING \
+ [[deprecated( \
+ "Deprecated receiver type detected. Please update the type for to satisfy the boolean " \
+ "stdexec::enable_receiver<R> trait. Defining a member type alias named 'is_receiver' is one " \
+ "way to do this.")]]
#else
-#define R5_SENDER_DEPR_WARNING
-#define R5_RECEIVER_DEPR_WARNING
+#define STDEXEC_R5_SENDER_DEPR_WARNING
+#define STDEXEC_R5_RECEIVER_DEPR_WARNING
#endif
+#define STDEXEC_LEGACY_R5_CONCEPTS() 1
+
STDEXEC_PRAGMA_PUSH()
STDEXEC_PRAGMA_IGNORE("-Wundefined-inline")
STDEXEC_PRAGMA_IGNORE("-Wundefined-internal")
namespace stdexec
{
-// BUGBUG
-namespace execution = stdexec;
-namespace this_thread = stdexec;
-
-using std::remove_cvref_t;
-
// [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.fwd_env]
-namespace __forwarding_query
+namespace __fwding_query
{
struct forwarding_query_t
{
@@ -107,9 +99,13 @@
}
}
};
-} // namespace __forwarding_query
-inline constexpr __forwarding_query::forwarding_query_t forwarding_query{};
-using __forwarding_query::forwarding_query_t;
+} // namespace __fwding_query
+
+inline constexpr __fwding_query::forwarding_query_t forwarding_query{};
+using __fwding_query::forwarding_query_t;
+
+template <class _Tag>
+concept __forwarding_query = forwarding_query(_Tag{});
/////////////////////////////////////////////////////////////////////////////
// [execution.receivers]
@@ -136,6 +132,7 @@
using __id = empty_env;
};
} // namespace __env
+
using __env::empty_env;
using __empty_env
[[deprecated("Please use stdexec::empty_env now.")]] = empty_env;
@@ -143,8 +140,8 @@
/////////////////////////////////////////////////////////////////////////////
// [execution.senders]
template <class _Sender>
-concept __enable_sender =
- requires { typename _Sender::is_sender; } ||
+concept __enable_sender = //
+ requires { typename _Sender::is_sender; } || //
__awaitable<_Sender, __compl_sigs::__env_promise<empty_env>>;
template <class _Sender>
@@ -153,30 +150,27 @@
// [execution.schedulers.queries], scheduler queries
namespace __scheduler_queries
{
-template <class _Ty>
-const _Ty& __cref_fn(const _Ty&);
-template <class _Ty>
-using __cref_t = decltype(__scheduler_queries::__cref_fn(__declval<_Ty>()));
-
-struct execute_may_block_caller_t
+struct execute_may_block_caller_t : __query<execute_may_block_caller_t>
{
- template <class _T>
- requires tag_invocable<execute_may_block_caller_t, __cref_t<_T>>
- constexpr bool operator()(_T&& __t) const noexcept
+ 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<_T>>>);
+ __cref_t<_Tp>>>);
static_assert(
- nothrow_tag_invocable<execute_may_block_caller_t, __cref_t<_T>>);
+ 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;
}
};
} // namespace __scheduler_queries
+
using __scheduler_queries::execute_may_block_caller_t;
inline constexpr execute_may_block_caller_t execute_may_block_caller{};
@@ -191,6 +185,7 @@
{
struct get_completion_signatures_t;
}
+
using __get_completion_signatures::get_completion_signatures_t;
/////////////////////////////////////////////////////////////////////////////
@@ -212,6 +207,7 @@
using __tag_t = _Tag;
using __value_t = _Value;
_Value __value_;
+
struct __t
{
using __id = __with;
@@ -221,32 +217,34 @@
__t(__with&& __w) : __value_(((__with &&) __w).__value_) {}
- template <same_as<_Tag> _T, class... _Ts>
- friend __val_or_ref_t
- tag_invoke(_T, const __t& __self, _Ts&&...) noexcept(
- std::is_nothrow_copy_constructible_v<__val_or_ref_t>)
+ template <same_as<_Tag> _Tp, class... _Ts>
+ friend __val_or_ref_t tag_invoke(_Tp, const __t& __self, _Ts&&...) //
+ noexcept(std::is_nothrow_copy_constructible_v<__val_or_ref_t>)
{
return __self.__value_;
}
};
};
+
template <class _Tag>
struct __with<_Tag, __none_such>
{
using __tag_t = _Tag;
using __value_t = __none_such;
+
struct __t
{
using __id = __with;
+
__t(__with) {}
- template <same_as<_Tag> _T, class... _Ts>
- friend void tag_invoke(_T, const __t&, _Ts&&...) = delete;
+ template <same_as<_Tag> _Tp, class... _Ts>
+ friend void tag_invoke(_Tp, const __t&, _Ts&&...) = delete;
};
};
template <__class _Tag, class _Value>
-__with<_Tag, decay_t<_Value>> __with_(_Tag, _Value&& __val)
+__with<_Tag, __decay_t<_Value>> __with_(_Tag, _Value&& __val)
{
return {(_Value &&) __val};
}
@@ -272,14 +270,13 @@
[[no_unique_address]] _BaseEnv __base_env_{};
// Forward the receiver queries:
- template <
- __none_of<__tag_of<_WithIds>..., get_completion_signatures_t> _Tag,
- same_as<__t> _Self, class... _As>
- requires __callable<_Tag, const __base_env_of<_Self>&, _As...>
- friend auto tag_invoke(_Tag __tag, const _Self& __self,
- _As&&... __as) noexcept
- -> __call_result_if_t<same_as<_Self, __t>, _Tag,
- const __base_env_of<_Self>&, _As...>
+ template <__forwarding_query _Tag, same_as<__t> _Self, class... _As>
+ requires __none_of<_Tag, __tag_of<_WithIds>...> &&
+ __callable<_Tag, const __base_env_of<_Self>&, _As...>
+ friend auto tag_invoke(_Tag __tag, const _Self& __self,
+ _As&&... __as) noexcept
+ -> __call_result_if_t<same_as<_Self, __t>, _Tag,
+ const __base_env_of<_Self>&, _As...>
{
return ((_Tag &&) __tag)(__self.__base_env_, (_As &&) __as...);
}
@@ -306,7 +303,7 @@
template <__none_of<no_env> _BaseEnv, class... _Tags, class... _Values>
requires __is_not_instance_of<_BaseEnv, __with>
auto operator()(_BaseEnv&& __base_env, __with<_Tags, _Values>... __ws) const
- -> __env_t<decay_t<_BaseEnv>, __with<_Tags, _Values>...>
+ -> __env_t<__decay_t<_BaseEnv>, __with<_Tags, _Values>...>
{
return {{std::move(__ws)}..., (_BaseEnv &&) __base_env};
}
@@ -352,6 +349,7 @@
}
};
} // namespace __env
+
using __env::__with;
using __env::__with_;
@@ -368,11 +366,17 @@
using env_of_t = __call_result_t<get_env_t, _EnvProvider>;
template <class _EnvProvider>
-concept environment_provider = requires(_EnvProvider& __ep) {
- {
- get_env(std::as_const(__ep))
- } -> __none_of<no_env, void>;
- };
+concept environment_provider = //
+ requires(_EnvProvider& __ep) {
+ {
+ get_env(std::as_const(__ep))
+ } -> queryable;
+ // NOT TO SPEC: Remove the following line when we deprecate all
+ // R5 entities.
+ {
+ get_env(std::as_const(__ep))
+ } -> __none_of<no_env, void>;
+ };
/////////////////////////////////////////////////////////////////////////////
// [execution.receivers]
@@ -430,6 +434,7 @@
}
};
} // namespace __receivers
+
using __receivers::set_error_t;
using __receivers::set_stopped_t;
using __receivers::set_value_t;
@@ -470,6 +475,7 @@
{
struct as_awaitable_t;
}
+
using __as_awaitable::as_awaitable_t;
extern const as_awaitable_t as_awaitable;
@@ -508,6 +514,8 @@
__types<__minvoke<_Ty>> __test(_Tag (*)());
template <class, class = void>
__types<> __test(...);
+template <class _Tag, class _Ty = void, class... _Args>
+void __test(_Tag (*)(_Args...) noexcept) = delete;
#endif
// To be kept in sync with the promise type used in __connect_awaitable
@@ -522,9 +530,9 @@
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&>
+ 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);
}
@@ -536,9 +544,10 @@
// BUGBUG not to spec!
struct __dependent
{
-#if !_STD_NO_COROUTINES_
+#if !STDEXEC_STD_NO_COROUTINES_
bool await_ready();
- void await_suspend(const __coro::coroutine_handle<__env_promise<no_env>>&);
+ template <class _Env>
+ void await_suspend(__coro::coroutine_handle<__env_promise<_Env>>);
__dependent await_resume();
#endif
};
@@ -560,6 +569,7 @@
decltype(__compl_sigs::__test<_Tag, _Ty>((_Sig*)nullptr));
#endif
} // namespace __compl_sigs
+
using __compl_sigs::__completion_signature;
using __compl_sigs::__env_promise;
using no_env_promise = __env_promise<no_env>;
@@ -634,6 +644,7 @@
// [execution.receivers]
template <class _Sig>
struct _MISSING_COMPLETION_SIGNAL_;
+
template <class _Tag, class... _Args>
struct _MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>
{
@@ -657,8 +668,8 @@
};
template <class _Receiver, class _Tag, class... _Args>
-using __missing_completion_signal_t =
- __if<__bool<nothrow_tag_invocable<_Tag, _Receiver, _Args...>>,
+using __missing_completion_signal_t = //
+ __if<__mbool<nothrow_tag_invocable<_Tag, _Receiver, _Args...>>,
__found_completion_signature,
_MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>>;
@@ -671,37 +682,47 @@
-> decltype((__has_completion<_Receiver>((_Sigs*)0), ...));
template <class _Completion, class _Receiver>
-concept __is_valid_completion = _Completion::template
+concept __is_valid_completion = //
+ _Completion::template
_WITH_RECEIVER_<_Receiver>::value;
} // namespace __receiver_concepts
+using __receiver_concepts::__has_completions;
+using __receiver_concepts::__is_valid_completion;
+
/////////////////////////////////////////////////////////////////////////////
// [execution.receivers]
+// NOT TO SPEC:
+// As we upgrade the receiver related entities from R5 to R7,
+// we allow types that do not yet satisfy enable_receiver to
+// still satisfy the receiver concept if the type provides an
+// explicit get_env. All R5 receivers provided an explicit get_env,
+// so this is backwards compatible.
+template <class _Receiver>
+concept __receiver_r5_or_r7 = //
+ enable_receiver<_Receiver> //
+ || tag_invocable<get_env_t, __cref_t<_Receiver>>;
template <class _Receiver>
-concept receiver =
- // NOT TO SPEC:
- // As we upgrade the receiver related entities from R5 to R7,
- // we allow types that do not yet satisfy enable_receiver to
- // still satisfy the receiver concept if the type provides an
- // explicit get_env. All R5 receivers provided an explicit get_env,
- // so this is backwards compatible.
- // NOTE: Double-negation here is to make the constraint atomic
- !!(enable_receiver<_Receiver> ||
- tag_invocable<get_env_t, __cref_t<_Receiver>>) &&
- environment_provider<__cref_t<_Receiver>> &&
- move_constructible<remove_cvref_t<_Receiver>> &&
- constructible_from<remove_cvref_t<_Receiver>, _Receiver>;
+concept __receiver = //
+ // Nested requirement here is to make this an atomic
+ // constraint
+ requires { requires __receiver_r5_or_r7<_Receiver>; };
+
+template <class _Receiver>
+concept receiver = __receiver<_Receiver> && //
+ environment_provider<__cref_t<_Receiver>> && //
+ move_constructible<__decay_t<_Receiver>> && //
+ constructible_from<__decay_t<_Receiver>, _Receiver>;
template <class _Receiver, class _Completions>
-concept receiver_of =
- receiver<_Receiver> &&
+concept receiver_of = //
+ receiver<_Receiver> && //
requires(_Completions* __required_completions) {
{
- __receiver_concepts::__has_completions<remove_cvref_t<_Receiver>>(
- __required_completions)
- } -> __receiver_concepts::__is_valid_completion<
- remove_cvref_t<_Receiver>>;
+ __has_completions<__decay_t<_Receiver>>(__required_completions)
+ } //
+ ->__is_valid_completion<__decay_t<_Receiver>>;
};
/////////////////////////////////////////////////////////////////////////////
@@ -713,8 +734,7 @@
__valid<tag_invoke_result_t, get_completion_signatures_t, _Sender, _Env>;
template <class _Sender, class...>
-using __member_alias_t =
- typename remove_cvref_t<_Sender>::completion_signatures;
+using __member_alias_t = typename __decay_t<_Sender>::completion_signatures;
template <class _Sender>
concept __with_member_alias = __valid<__member_alias_t, _Sender>;
@@ -753,15 +773,26 @@
set_error_t(std::exception_ptr)>>{};
}
}
+#if STDEXEC_LEGACY_R5_CONCEPTS()
+ else if constexpr (same_as<_Env, no_env> &&
+ enable_sender<__decay_t<_Sender>>)
+ {
+ return __mconst<dependent_completion_signatures<no_env>>{};
+ }
+#endif
}
template <class _Sender, class _Env>
using __impl_fn = decltype(__impl<_Sender, _Env>());
template <class _Sender, class _Env = no_env>
- requires(__with_tag_invoke<_Sender, _Env> ||
- __with_member_alias<_Sender> ||
- __awaitable<_Sender, __env_promise<_Env>>)
+ requires(__with_tag_invoke<_Sender, _Env> //
+ || __with_member_alias<_Sender> //
+ || __awaitable<_Sender, __env_promise<_Env>>
+#if STDEXEC_LEGACY_R5_CONCEPTS()
+ || (same_as<_Env, no_env> && enable_sender<__decay_t<_Sender>>)
+#endif
+ )
constexpr auto operator()(_Sender&&, const _Env& = {}) const noexcept
-> __minvoke<__impl_fn<_Sender, _Env>, _Sender, _Env>
{
@@ -788,31 +819,56 @@
__valid_completion_signatures<__completion_signatures_of_t<_Sender, _Env>,
_Env>;
+#if !STDEXEC_LEGACY_R5_CONCEPTS()
+// Here is the R7 sender concepts, not yet enabled.
+template <class _Sender>
+concept sender = //
+ enable_sender<__decay_t<_Sender>> && //
+ environment_provider<__cref_t<_Sender>> && //
+ move_constructible<__decay_t<_Sender>> && //
+ constructible_from<__decay_t<_Sender>, _Sender>;
+
+template <class _Sender, class _Env = empty_env>
+concept sender_in = //
+ sender<_Sender> && //
+ __with_completion_signatures<_Sender, _Env>;
+
+#else
+template <class _Sender, class _Env>
+concept __sender_r7 = same_as<_Env, no_env> &&
+ enable_sender<__decay_t<_Sender>>;
+
+// Here are the sender concepts that provide backward compatibility
+// with R5-style senders.
+template <class _Sender, class _Env = no_env>
+concept __sender_r5_or_r7 = //
+ __satisfies<__sender_r7<_Sender, _Env>> //
+ || __with_completion_signatures<_Sender, _Env>;
+
template <class _Sender, class _Env = no_env>
concept __sender =
- // Double-negation here is to make this an atomic constraint
- !!((same_as<_Env, no_env> && enable_sender<remove_cvref_t<_Sender>>) ||
- __with_completion_signatures<_Sender, _Env>);
+ // Nested requirement here is to make this an atomic constraint
+ requires { requires __sender_r5_or_r7<_Sender, _Env>; };
-/////////////////////////////////////////////////////////////////////////////
-// [execution.senders]
template <class _Sender, class _Env = no_env>
concept sender =
// NOT TO SPEC
// The sender related concepts are temporarily "in flight" being
// upgraded from P2300R5 to the get_env / enable_sender aware version
// in P2300R7.
- __sender<_Sender> && __sender<_Sender, _Env> &&
- environment_provider<__cref_t<_Sender>> &&
- move_constructible<remove_cvref_t<_Sender>> &&
- constructible_from<remove_cvref_t<_Sender>, _Sender>;
+ __sender<_Sender> && //
+ __sender<_Sender, _Env> && //
+ environment_provider<__cref_t<_Sender>> && //
+ move_constructible<__decay_t<_Sender>> && //
+ constructible_from<__decay_t<_Sender>, _Sender>;
-template <class _Sender, class _Env>
+template <class _Sender, class _Env = empty_env>
concept sender_in = sender<_Sender, _Env>;
+#endif
// __checked_completion_signatures is for catching logic bugs in a typed
-// sender's metadata. If sender<S> and sender<S, Ctx> are both true, then they
-// had better report the same metadata. This completion signatures wrapper
+// sender's metadata. If sender<S> and sender_in<S, Ctx> are both true, then
+// they had better report the same metadata. This completion signatures wrapper
// enforces that at compile time.
template <class _Sender, class _Env>
struct __checked_completion_signatures
@@ -828,7 +884,7 @@
};
template <class _Sender, class _Env = no_env>
- requires sender<_Sender, _Env>
+ requires sender_in<_Sender, _Env>
using completion_signatures_of_t =
__t<__checked_completion_signatures<_Sender, _Env>>;
@@ -837,9 +893,9 @@
__not_a_variant() = delete;
};
template <class... _Ts>
-using __variant =
+using __variant = //
__minvoke<__if_c<sizeof...(_Ts) != 0,
- __transform<__q<decay_t>, __munique<__q<std::variant>>>,
+ __transform<__q<__decay_t>, __munique<__q<std::variant>>>,
__mconst<__not_a_variant>>,
_Ts...>;
@@ -847,7 +903,7 @@
__munique<__mbind_front_q<std::variant, std::monostate>>;
template <class... _Ts>
-using __decayed_tuple = std::tuple<decay_t<_Ts>...>;
+using __decayed_tuple = std::tuple<__decay_t<_Ts>...>;
template <class _Tag, class _Tuple>
struct __select_completions_for
@@ -856,47 +912,67 @@
using __f = __minvoke<_Tag2, _Tuple, _Args...>;
};
+template <class _Tuple>
+struct __invoke_completions
+{
+ template <class _Tag, class... _Args>
+ using __f = __minvoke<_Tag, _Tuple, _Args...>;
+};
+
template <class _Tag, class _Tuple>
using __select_completions_for_or =
__with_default<__select_completions_for<_Tag, _Tuple>, __>;
+template <class _Tag, class... _Args>
+using __set_tag_type = _Tag(_Args...);
+
+template <class _Tag, class _Completions>
+using __only_gather_signal = __compl_sigs::__for_all_sigs<
+ _Completions,
+ __select_completions_for_or<_Tag, __mbind_front_q<__set_tag_type, _Tag>>,
+ __remove<__, __q<completion_signatures>>>;
+
template <class _Tag, class _Completions, class _Tuple, class _Variant>
using __gather_signal =
- __compl_sigs::__for_all_sigs<_Completions,
- __select_completions_for_or<_Tag, _Tuple>,
- __remove<__, _Variant>>;
+ __compl_sigs::__for_all_sigs<__only_gather_signal<_Tag, _Completions>,
+ __invoke_completions<_Tuple>, _Variant>;
template <class _Tag, class _Sender, class _Env, class _Tuple, class _Variant>
- requires sender<_Sender, _Env>
+ requires sender_in<_Sender, _Env>
using __gather_completions_for =
__gather_signal<_Tag, completion_signatures_of_t<_Sender, _Env>, _Tuple,
_Variant>;
-template <class _Sender, class _Env = no_env,
- class _Tuple = __q<__decayed_tuple>, class _Variant = __q<__variant>>
- requires sender<_Sender, _Env>
+template < //
+ class _Sender, //
+ class _Env = no_env, //
+ class _Tuple = __q<__decayed_tuple>, //
+ class _Variant = __q<__variant>>
+ requires sender_in<_Sender, _Env>
using __value_types_of_t =
__gather_completions_for<set_value_t, _Sender, _Env, _Tuple, _Variant>;
template <class _Sender, class _Env = no_env, class _Variant = __q<__variant>>
- requires sender<_Sender, _Env>
+ requires sender_in<_Sender, _Env>
using __error_types_of_t = __gather_completions_for<set_error_t, _Sender, _Env,
__q<__midentity>, _Variant>;
-template <class _Sender, class _Env = no_env,
- template <class...> class _Tuple = __decayed_tuple,
- template <class...> class _Variant = __variant>
- requires sender<_Sender, _Env>
+template < //
+ class _Sender, //
+ class _Env = no_env, //
+ template <class...> class _Tuple = __decayed_tuple, //
+ template <class...> class _Variant = __variant>
+ requires sender_in<_Sender, _Env>
using value_types_of_t =
__value_types_of_t<_Sender, _Env, __q<_Tuple>, __q<_Variant>>;
template <class _Sender, class _Env = no_env,
template <class...> class _Variant = __variant>
- requires sender<_Sender, _Env>
+ requires sender_in<_Sender, _Env>
using error_types_of_t = __error_types_of_t<_Sender, _Env, __q<_Variant>>;
template <class _Tag, class _Sender, class _Env = no_env>
- requires sender<_Sender, _Env>
+ requires sender_in<_Sender, _Env>
using __count_of =
__compl_sigs::__for_all_sigs<completion_signatures_of_t<_Sender, _Env>,
__q<__mfront>, __mcount<_Tag>>;
@@ -918,19 +994,19 @@
value_types_of_t<_Sender, _Env, __types, __msingle>;
template <class _Sender, class _Env = no_env>
-concept __single_typed_sender = sender<_Sender, _Env> &&
+concept __single_typed_sender = sender_in<_Sender, _Env> &&
__valid<__single_sender_value_t, _Sender, _Env>;
template <class _Sender, class _Env = no_env>
concept __single_value_variant_sender =
- sender<_Sender, _Env> &&
+ sender_in<_Sender, _Env> &&
__valid<__single_value_variant_sender_t, _Sender, _Env>;
template <class... Errs>
-using __nofail = __bool<sizeof...(Errs) == 0>;
+using __nofail = __mbool<sizeof...(Errs) == 0>;
template <class _Sender, class _Env = no_env>
-concept __nofail_sender = sender<_Sender, _Env> &&
+concept __nofail_sender = sender_in<_Sender, _Env> &&
(__v<error_types_of_t<_Sender, _Env, __nofail>>);
/////////////////////////////////////////////////////////////////////////////
@@ -946,29 +1022,44 @@
using __ensure_concat =
__minvoke<__mconcat<__q<completion_signatures>>, _Sigs...>;
-template <class _Sender, class _Env, class _Sigs, class _SetValue,
- class _SetError, class _SetStopped>
-using __compl_sigs_t = __concat_completion_signatures_t<
- _Sigs, __value_types_of_t<_Sender, _Env, _SetValue, __q<__ensure_concat>>,
- __error_types_of_t<_Sender, _Env,
- __transform<_SetError, __q<__ensure_concat>>>,
- __if_c<sends_stopped<_Sender, _Env>, _SetStopped, completion_signatures<>>>;
+template < //
+ class _Sender, //
+ class _Env, //
+ class _Sigs, //
+ class _SetValue, //
+ class _SetError, //
+ class _SetStopped>
+using __compl_sigs_t = //
+ __concat_completion_signatures_t<
+ _Sigs,
+ __value_types_of_t<_Sender, _Env, _SetValue, __q<__ensure_concat>>,
+ __error_types_of_t<_Sender, _Env,
+ __transform<_SetError, __q<__ensure_concat>>>,
+ __if_c<sends_stopped<_Sender, _Env>, _SetStopped,
+ completion_signatures<>>>;
-template <class _Sender, class _Env, class _Sigs, class _SetValue,
- class _SetError, class _SetStopped>
+template < //
+ class _Sender, //
+ class _Env, //
+ class _Sigs, //
+ class _SetValue, //
+ class _SetError, //
+ class _SetStopped>
auto __make(int)
-> __compl_sigs_t<_Sender, _Env, _Sigs, _SetValue, _SetError, _SetStopped>;
template <class, class _Env, class, class, class, class>
auto __make(long) -> dependent_completion_signatures<_Env>;
-template <class _Sender, class _Env = no_env,
- __valid_completion_signatures<_Env> _Sigs = completion_signatures<>,
- class _SetValue = __q<__default_set_value>,
- class _SetError = __q<__default_set_error>,
- __valid_completion_signatures<_Env> _SetStopped =
- completion_signatures<set_stopped_t()>>
- requires sender<_Sender, _Env>
+template < //
+ class _Sender, //
+ class _Env = no_env, //
+ __valid_completion_signatures<_Env> _Sigs = completion_signatures<>, //
+ class _SetValue = __q<__default_set_value>, //
+ class _SetError = __q<__default_set_error>, //
+ __valid_completion_signatures<_Env> _SetStopped =
+ completion_signatures<set_stopped_t()>>
+ requires sender_in<_Sender, _Env>
using __make_completion_signatures =
decltype(__make<_Sender, _Env, _Sigs, _SetValue, _SetError, _SetStopped>(
0));
@@ -1000,7 +1091,7 @@
// template <class...> class SetValue = __default_set_value,
// template <class> class SetError = __default_set_error,
// class SetStopped = completion_signatures<set_stopped_t()>>
-// requires sender<Sndr, Env>
+// requires sender_in<Sndr, Env>
// using make_completion_signatures =
// completion_signatures< ... >;
// ```
@@ -1041,14 +1132,15 @@
// If any of the above type computations are ill-formed,
// `make_completion_signatures<Sndr, Env, AddlSigs, SetValue, SetError,
// SendsStopped>` is an alias for an empty struct
-template <class _Sender, class _Env = no_env,
- __valid_completion_signatures<_Env> _Sigs = completion_signatures<>,
- template <class...>
- class _SetValue = __compl_sigs::__default_set_value,
- template <class> class _SetError = __compl_sigs::__default_set_error,
- __valid_completion_signatures<_Env> _SetStopped =
- completion_signatures<set_stopped_t()>>
- requires sender<_Sender, _Env>
+template < //
+ class _Sender, //
+ class _Env = no_env, //
+ __valid_completion_signatures<_Env> _Sigs = completion_signatures<>, //
+ template <class...> class _SetValue = __compl_sigs::__default_set_value, //
+ template <class> class _SetError = __compl_sigs::__default_set_error, //
+ __valid_completion_signatures<_Env> _SetStopped =
+ completion_signatures<set_stopped_t()>>
+ requires sender_in<_Sender, _Env>
using make_completion_signatures =
__make_completion_signatures<_Sender, _Env, _Sigs, __q<_SetValue>,
__q<_SetError>, _SetStopped>;
@@ -1077,6 +1169,7 @@
}
};
} // namespace __scheduler_queries
+
using __scheduler_queries::forwarding_scheduler_query_t;
inline constexpr forwarding_scheduler_query_t forwarding_scheduler_query{};
@@ -1103,37 +1196,36 @@
}
};
} // namespace __schedule
+
using __schedule::schedule_t;
inline constexpr schedule_t schedule{};
// NOT TO SPEC
template <class _Tag, const auto& _Predicate>
-concept tag_category = requires {
- typename __bool<bool{_Predicate(_Tag{})}>;
- requires bool {
- _Predicate(_Tag{})
- };
- };
+concept tag_category = //
+ requires {
+ typename __mbool<bool{_Predicate(_Tag{})}>;
+ requires bool {
+ _Predicate(_Tag{})
+ };
+ };
// [execution.schedulers.queries], scheduler queries
namespace __scheduler_queries
{
-template <class _Ty>
-const _Ty& __cref_fn(const _Ty&);
-template <class _Ty>
-using __cref_t = decltype(__scheduler_queries::__cref_fn(__declval<_Ty>()));
-
-struct get_forward_progress_guarantee_t
+struct get_forward_progress_guarantee_t :
+ __query<get_forward_progress_guarantee_t>
{
- template <class _T>
- requires tag_invocable<get_forward_progress_guarantee_t, __cref_t<_T>>
- constexpr auto operator()(_T&& __t) const noexcept(
- nothrow_tag_invocable<get_forward_progress_guarantee_t, __cref_t<_T>>)
- -> tag_invoke_result_t<get_forward_progress_guarantee_t, __cref_t<_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
{
@@ -1141,29 +1233,33 @@
}
};
-struct __has_algorithm_customizations_t
+struct __has_algorithm_customizations_t :
+ __query<__has_algorithm_customizations_t>
{
- template <class _T>
+ template <class _Tp>
using __result_t =
- tag_invoke_result_t<__has_algorithm_customizations_t, __cref_t<_T>>;
- template <class _T>
- requires tag_invocable<__has_algorithm_customizations_t, __cref_t<_T>>
- constexpr __result_t<_T> operator()(_T&& __t) const
- noexcept(noexcept(__result_t<_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&& __t) const
+ noexcept(noexcept(__result_t<_Tp>{}))
{
- using _Boolean =
- tag_invoke_result_t<__has_algorithm_customizations_t, __cref_t<_T>>;
+ 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 {};
}
};
} // namespace __scheduler_queries
+
using __scheduler_queries::__has_algorithm_customizations_t;
inline constexpr __has_algorithm_customizations_t
__has_algorithm_customizations{};
@@ -1177,16 +1273,18 @@
template <__one_of<set_value_t, set_error_t, set_stopped_t> _CPO>
struct get_completion_scheduler_t;
}
+
using __sender_queries::get_completion_scheduler_t;
/////////////////////////////////////////////////////////////////////////////
// [execution.schedulers]
template <class _Scheduler>
-concept __has_schedule = requires(_Scheduler&& __sched) {
- {
- schedule((_Scheduler &&) __sched)
- } -> sender;
- };
+concept __has_schedule = //
+ requires(_Scheduler&& __sched) {
+ {
+ schedule((_Scheduler &&) __sched)
+ } -> sender;
+ };
template <class _Scheduler>
concept __sender_has_completion_scheduler =
@@ -1195,14 +1293,15 @@
{
tag_invoke(std::move(__tag),
get_env(schedule((_Scheduler &&) __sched)))
- } -> same_as<remove_cvref_t<_Scheduler>>;
+ } -> same_as<__decay_t<_Scheduler>>;
};
template <class _Scheduler>
-concept scheduler = __has_schedule<_Scheduler> &&
- __sender_has_completion_scheduler<_Scheduler> &&
- equality_comparable<remove_cvref_t<_Scheduler>> &&
- copy_constructible<remove_cvref_t<_Scheduler>>;
+concept scheduler = //
+ __has_schedule<_Scheduler> && //
+ __sender_has_completion_scheduler<_Scheduler> && //
+ equality_comparable<__decay_t<_Scheduler>> && //
+ copy_constructible<__decay_t<_Scheduler>>;
// NOT TO SPEC
template <scheduler _Scheduler>
@@ -1216,13 +1315,14 @@
template <class _T0>
concept __allocator = true;
-struct get_scheduler_t
+struct get_scheduler_t : __query<get_scheduler_t>
{
friend constexpr bool tag_invoke(forwarding_query_t,
const get_scheduler_t&) noexcept
{
return true;
}
+
template <__none_of<no_env> _Env>
requires tag_invocable<get_scheduler_t, const _Env&> &&
scheduler<tag_invoke_result_t<get_scheduler_t, const _Env&>>
@@ -1232,39 +1332,43 @@
static_assert(nothrow_tag_invocable<get_scheduler_t, const _Env&>);
return tag_invoke(get_scheduler_t{}, __env);
}
+
auto operator()() const noexcept;
};
-struct get_delegatee_scheduler_t
+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 _T>
+
+ template <class _Tp>
requires nothrow_tag_invocable<get_delegatee_scheduler_t,
- __cref_t<_T>> &&
+ __cref_t<_Tp>> &&
scheduler<tag_invoke_result_t<get_delegatee_scheduler_t,
- __cref_t<_T>>>
- auto operator()(_T&& __t) const
+ __cref_t<_Tp>>>
+ auto operator()(_Tp&& __t) const
noexcept(nothrow_tag_invocable<get_delegatee_scheduler_t,
- __cref_t<_T>>)
+ __cref_t<_Tp>>)
-> tag_invoke_result_t<get_delegatee_scheduler_t,
- __cref_t<_T>>
+ __cref_t<_Tp>>
{
return tag_invoke(get_delegatee_scheduler_t{}, std::as_const(__t));
}
+
auto operator()() const noexcept;
};
-struct get_allocator_t
+struct get_allocator_t : __query<get_allocator_t>
{
friend constexpr bool tag_invoke(forwarding_query_t,
const get_allocator_t&) noexcept
{
return true;
}
+
template <__none_of<no_env> _Env>
requires nothrow_tag_invocable<get_allocator_t, const _Env&> &&
__allocator<tag_invoke_result_t<get_allocator_t, const _Env&>>
@@ -1274,21 +1378,24 @@
{
return tag_invoke(get_allocator_t{}, __env);
}
+
auto operator()() const noexcept;
};
-struct get_stop_token_t
+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 <__none_of<no_env> _Env>
never_stop_token operator()(const _Env&) const noexcept
{
return {};
}
+
template <__none_of<no_env> _Env>
requires tag_invocable<get_stop_token_t, const _Env&> &&
stoppable_token<
@@ -1299,9 +1406,11 @@
{
return tag_invoke(get_stop_token_t{}, __env);
}
+
auto operator()() const noexcept;
};
} // namespace __queries
+
using __queries::get_allocator_t;
using __queries::get_delegatee_scheduler_t;
using __queries::get_scheduler_t;
@@ -1311,20 +1420,20 @@
inline constexpr get_allocator_t get_allocator{};
inline constexpr get_stop_token_t get_stop_token{};
-template <class _T>
-using stop_token_of_t =
- remove_cvref_t<decltype(get_stop_token(__declval<_T>()))>;
+template <class _Tp>
+using stop_token_of_t = __decay_t<decltype(get_stop_token(__declval<_Tp>()))>;
template <receiver _Receiver>
using __current_scheduler_t =
__call_result_t<get_scheduler_t, env_of_t<_Receiver>>;
template <class _SchedulerProvider>
-concept __scheduler_provider = requires(const _SchedulerProvider& __sp) {
- {
- get_scheduler(__sp)
- } -> scheduler<>;
- };
+concept __scheduler_provider = //
+ requires(const _SchedulerProvider& __sp) {
+ {
+ get_scheduler(__sp)
+ } -> scheduler<>;
+ };
/////////////////////////////////////////////////////////////////////////////
// [execution.op_state]
@@ -1334,27 +1443,28 @@
{
template <class _Op>
requires tag_invocable<start_t, _Op&>
- void operator()(_Op& __op) const
- noexcept(nothrow_tag_invocable<start_t, _Op&>)
+ void operator()(_Op& __op) const noexcept
{
+ static_assert(nothrow_tag_invocable<start_t, _Op&>);
(void)tag_invoke(start_t{}, __op);
}
};
} // namespace __start
+
using __start::start_t;
inline constexpr start_t start{};
/////////////////////////////////////////////////////////////////////////////
// [execution.op_state]
-template <class _O>
-concept operation_state = destructible<_O> && std::is_object_v<_O> &&
- requires(_O& __o) {
- {
- start(__o)
- } noexcept;
- };
+template <class _Op>
+concept operation_state = //
+ destructible<_Op> && //
+ std::is_object_v<_Op> && //
+ requires(_Op& __op) { //
+ start(__op);
+ };
-#if !_STD_NO_COROUTINES_
+#if !STDEXEC_STD_NO_COROUTINES_
/////////////////////////////////////////////////////////////////////////////
// __connect_awaitable_
namespace __connect_awaitable_
@@ -1365,44 +1475,21 @@
{
return {};
}
+
[[noreturn]] __coro::suspend_always final_suspend() noexcept
{
std::terminate();
}
+
[[noreturn]] void unhandled_exception() noexcept
{
std::terminate();
}
+
[[noreturn]] void return_void() noexcept
{
std::terminate();
}
- template <class _Fun>
- auto yield_value(_Fun&& __fun) noexcept
- {
- struct awaiter
- {
- _Fun&& __fun_;
- bool await_ready() noexcept
- {
- return false;
- }
- void await_suspend(__coro::coroutine_handle<>) noexcept(
- __nothrow_callable<_Fun>)
- {
- // If this throws, the runtime catches the exception,
- // resumes the __connect_awaitable coroutine, and immediately
- // rethrows the exception. The end result is that an
- // exception_ptr to the exception gets passed to set_error.
- ((_Fun &&) __fun_)();
- }
- [[noreturn]] void await_resume() noexcept
- {
- std::terminate();
- }
- };
- return awaiter{(_Fun &&) __fun};
- }
};
struct __operation_base
@@ -1455,7 +1542,7 @@
__coro::coroutine_handle<> unhandled_stopped() noexcept
{
- set_stopped(std::move(__rcvr_));
+ set_stopped((_Receiver &&) __rcvr_);
// Returning noop_coroutine here causes the __connect_awaitable
// coroutine to never resume past the point where it co_await's
// the awaitable.
@@ -1476,9 +1563,9 @@
template <class _Awaitable>
requires tag_invocable<as_awaitable_t, _Awaitable, __t&>
- auto await_transform(_Awaitable&& __await) noexcept(
- nothrow_tag_invocable<as_awaitable_t, _Awaitable, __t&>)
- -> tag_invoke_result_t<as_awaitable_t, _Awaitable, __t&>
+ auto await_transform(_Awaitable&& __await) //
+ noexcept(nothrow_tag_invocable<as_awaitable_t, _Awaitable, __t&>)
+ -> tag_invoke_result_t<as_awaitable_t, _Awaitable, __t&>
{
return tag_invoke(as_awaitable, (_Awaitable &&) __await, *this);
}
@@ -1503,6 +1590,34 @@
struct __connect_awaitable_t
{
private:
+ template <class _Fun, class... _Ts>
+ static auto __co_call(_Fun __fun, _Ts&&... __as) noexcept
+ {
+ auto __fn = [&, __fun]() noexcept { __fun((_Ts &&) __as...); };
+
+ struct __awaiter
+ {
+ decltype(__fn) __fn_;
+
+ static constexpr bool await_ready() noexcept
+ {
+ return false;
+ }
+
+ void await_suspend(__coro::coroutine_handle<>) noexcept
+ {
+ __fn_();
+ }
+
+ [[noreturn]] void await_resume() noexcept
+ {
+ std::terminate();
+ }
+ };
+
+ return __awaiter{__fn};
+ }
+
template <class _Awaitable, class _Receiver>
static __operation_t<_Receiver> __co_impl(_Awaitable __await,
_Receiver __rcvr)
@@ -1511,40 +1626,28 @@
std::exception_ptr __eptr;
try
{
- // This is a bit mind bending control-flow wise.
- // We are first evaluating the co_await expression.
- // Then the result of that is passed into a lambda
- // that curries a reference to the result into another
- // lambda which is then returned to 'co_yield'.
- // The 'co_yield' expression then invokes this lambda
- // after the coroutine is suspended so that it is safe
- // for the receiver to destroy the coroutine.
- auto __fun = [&](auto&&... __as) noexcept {
- return [&]() noexcept -> void {
- set_value((_Receiver &&) __rcvr,
- (std::add_rvalue_reference_t<__result_t>)__as...);
- };
- };
- if constexpr (std::is_void_v<__result_t>)
- co_yield (co_await (_Awaitable &&) __await, __fun());
+ if constexpr (same_as<__result_t, void>)
+ co_await (co_await (_Awaitable &&) __await,
+ __co_call(set_value, (_Receiver &&) __rcvr));
else
- co_yield __fun(co_await (_Awaitable &&) __await);
+ co_await __co_call(set_value, (_Receiver &&) __rcvr,
+ co_await (_Awaitable &&) __await);
}
catch (...)
{
__eptr = std::current_exception();
}
- co_yield [&]() noexcept -> void {
- set_error((_Receiver &&) __rcvr, (std::exception_ptr &&) __eptr);
- };
+ co_await __co_call(set_error, (_Receiver &&) __rcvr,
+ (std::exception_ptr &&) __eptr);
}
template <receiver _Receiver, class _Awaitable>
- using __completions_t = completion_signatures<
- __minvoke< // set_value_t() or set_value_t(T)
- __remove<void, __qf<set_value_t>>,
- __await_result_t<_Awaitable, __promise_t<_Receiver>>>,
- set_error_t(std::exception_ptr), set_stopped_t()>;
+ using __completions_t = //
+ completion_signatures<
+ __minvoke< // set_value_t() or set_value_t(T)
+ __remove<void, __qf<set_value_t>>,
+ __await_result_t<_Awaitable, __promise_t<_Receiver>>>,
+ set_error_t(std::exception_ptr), set_stopped_t()>;
public:
template <class _Receiver, __awaitable<__promise_t<_Receiver>> _Awaitable>
@@ -1556,6 +1659,7 @@
}
};
} // namespace __connect_awaitable_
+
using __connect_awaitable_::__connect_awaitable_t;
#else
struct __connect_awaitable_t
@@ -1567,7 +1671,7 @@
// [exec.snd_queries]
namespace __sender_queries
{
-struct forwarding_sender_query_t
+struct forwarding_sender_query_t : __query<forwarding_sender_query_t>
{
template <class _Tag>
constexpr bool operator()(_Tag __tag) const noexcept
@@ -1585,6 +1689,7 @@
}
};
} // namespace __sender_queries
+
using __sender_queries::forwarding_sender_query_t;
inline constexpr forwarding_sender_query_t forwarding_sender_query{};
@@ -1592,6 +1697,11 @@
{
struct __is_debug_env_t
{
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const __is_debug_env_t&) noexcept
+ {
+ return true;
+ }
template <class _Env>
requires tag_invocable<__is_debug_env_t, _Env>
void operator()(_Env&&) const noexcept;
@@ -1659,20 +1769,23 @@
{
struct connect_t;
-template <class _T>
-R5_SENDER_DEPR_WARNING void
+template <class _Tp>
+STDEXEC_R5_SENDER_DEPR_WARNING //
+ void
__update_sender_type_to_p2300r7_by_adding_enable_sender_trait()
{}
-template <class _T>
-R5_RECEIVER_DEPR_WARNING void
+template <class _Tp>
+STDEXEC_R5_RECEIVER_DEPR_WARNING //
+ void
__update_receiver_type_to_p2300r7_by_adding_enable_receiver_trait()
{}
template <class _Sender, class _Receiver>
concept __connectable_with_tag_invoke =
- receiver<_Receiver> && sender<_Sender, env_of_t<_Receiver>> &&
- __receiver_from<_Receiver, _Sender> &&
+ receiver<_Receiver> && //
+ sender_in<_Sender, env_of_t<_Receiver>> && //
+ __receiver_from<_Receiver, _Sender> && //
tag_invocable<connect_t, _Sender, _Receiver>;
struct connect_t
@@ -1681,13 +1794,13 @@
static constexpr auto __select_impl() noexcept
{
// Report that 2300R5-style senders and receivers are deprecated:
- if constexpr (!enable_sender<remove_cvref_t<_Sender>>)
+ if constexpr (!enable_sender<__decay_t<_Sender>>)
__update_sender_type_to_p2300r7_by_adding_enable_sender_trait<
- remove_cvref_t<_Sender>>();
+ __decay_t<_Sender>>();
- if constexpr (!enable_receiver<remove_cvref_t<_Receiver>>)
+ if constexpr (!enable_receiver<__decay_t<_Receiver>>)
__update_receiver_type_to_p2300r7_by_adding_enable_receiver_trait<
- remove_cvref_t<_Receiver>>();
+ __decay_t<_Receiver>>();
if constexpr (__connectable_with_tag_invoke<_Sender, _Receiver>)
{
@@ -1712,7 +1825,7 @@
template <class _Sender, class _Receiver>
using __select_impl_t = decltype(__select_impl<_Sender, _Receiver>());
- template <class _Sender, class _Receiver>
+ template <sender _Sender, receiver _Receiver>
requires __connectable_with_tag_invoke<_Sender, _Receiver> ||
__callable<__connect_awaitable_t, _Sender, _Receiver> ||
tag_invocable<__is_debug_env_t, env_of_t<_Receiver>>
@@ -1840,9 +1953,9 @@
/////////////////////////////////////////////////////////////////////////////
// [exec.snd]
template <class _Sender, class _Receiver>
-concept sender_to = receiver<_Receiver> &&
- sender<_Sender, env_of_t<_Receiver>> &&
- __receiver_from<_Receiver, _Sender> &&
+concept sender_to = receiver<_Receiver> && //
+ sender_in<_Sender, env_of_t<_Receiver>> && //
+ __receiver_from<_Receiver, _Sender> && //
requires(_Sender&& __sndr, _Receiver&& __rcvr) {
connect((_Sender &&) __sndr, (_Receiver &&) __rcvr);
};
@@ -1854,7 +1967,7 @@
template <class _Sender, class _SetSig, class _Env = no_env>
concept sender_of =
- sender<_Sender, _Env> &&
+ sender_in<_Sender, _Env> &&
same_as<__types<_SetSig>, __gather_completions_for<
__tag_of_sig_t<_SetSig>, _Sender, _Env,
__qf<__tag_of_sig_t<_SetSig>>, __q<__types>>>;
@@ -1864,7 +1977,7 @@
namespace __sender_queries
{
template <__one_of<set_value_t, set_error_t, set_stopped_t> _CPO>
-struct get_completion_scheduler_t
+struct get_completion_scheduler_t : __query<get_completion_scheduler_t<_CPO>>
{
// NOT TO SPEC:
friend constexpr bool tag_invoke(forwarding_sender_query_t,
@@ -1872,6 +1985,7 @@
{
return true;
}
+
friend constexpr bool tag_invoke(forwarding_query_t,
const get_completion_scheduler_t&) noexcept
{
@@ -1894,6 +2008,7 @@
}
};
} // namespace __sender_queries
+
using __sender_queries::forwarding_sender_query_t;
using __sender_queries::get_completion_scheduler_t;
@@ -1916,7 +2031,7 @@
tag_invocable<_Fun, __completion_scheduler_for<_Sender, _CPO>, _Sender,
_As...>;
-#if !_STD_NO_COROUTINES_
+#if !STDEXEC_STD_NO_COROUTINES_
/////////////////////////////////////////////////////////////////////////////
// stdexec::as_awaitable [execution.coro_utils.as_awaitable]
namespace __as_awaitable
@@ -1939,14 +2054,16 @@
requires constructible_from<__value_or_void_t<_Value>, _Us...>
friend void tag_invoke(set_value_t, __receiver_base&& __self,
_Us&&... __us) noexcept
- try
{
- __self.__result_->template emplace<1>((_Us &&) __us...);
- __self.__continuation_.resume();
- }
- catch (...)
- {
- set_error((__receiver_base &&) __self, std::current_exception());
+ try
+ {
+ __self.__result_->template emplace<1>((_Us &&) __us...);
+ __self.__continuation_.resume();
+ }
+ catch (...)
+ {
+ set_error((__receiver_base &&) __self, std::current_exception());
+ }
}
template <class _Error>
@@ -1972,9 +2089,11 @@
struct __receiver
{
using _Promise = stdexec::__t<_PromiseId>;
+
struct __t : __receiver_base<_Value>
{
using __id = __receiver;
+
friend void tag_invoke(set_stopped_t, __t&& __self) noexcept
{
auto __continuation =
@@ -1988,17 +2107,10 @@
// Forward get_env query to the coroutine promise
friend __env_t<_Promise&> tag_invoke(get_env_t, const __t& __self)
{
- if constexpr (__callable<get_env_t, _Promise&>)
- {
- auto __continuation =
- __coro::coroutine_handle<_Promise>::from_address(
- __self.__continuation_.address());
- return get_env(__continuation.promise());
- }
- else
- {
- return empty_env{};
- }
+ auto __continuation =
+ __coro::coroutine_handle<_Promise>::from_address(
+ __self.__continuation_.address());
+ return get_env(__continuation.promise());
}
};
};
@@ -2046,11 +2158,11 @@
using _Promise = stdexec::__t<_PromiseId>;
using _Sender = stdexec::__t<_SenderId>;
using __value = __value_t<_Sender, _Promise>;
+
struct __t : __sender_awaitable_base<__value>
{
- __t(_Sender&& sndr,
- __coro::coroutine_handle<_Promise>
- __hcoro) noexcept(__nothrow_connectable<_Sender, __receiver>) :
+ __t(_Sender&& sndr, __coro::coroutine_handle<_Promise> __hcoro) //
+ noexcept(__nothrow_connectable<_Sender, __receiver>) :
__op_state_(connect((_Sender &&) sndr,
__receiver{{&this->__result_, __hcoro}}))
{}
@@ -2072,73 +2184,84 @@
template <class _Sender, class _Promise>
concept __awaitable_sender =
- __single_typed_sender<_Sender, __env_t<_Promise>> &&
- sender_to<_Sender, __receiver_t<_Sender, _Promise>> &&
+ __single_typed_sender<_Sender, __env_t<_Promise>> && //
+ sender_to<_Sender, __receiver_t<_Sender, _Promise>> && //
requires(_Promise& __promise) {
{
__promise.unhandled_stopped()
} -> convertible_to<__coro::coroutine_handle<>>;
};
+struct __unspecified
+{
+ __unspecified get_return_object() noexcept;
+ __unspecified initial_suspend() noexcept;
+ __unspecified final_suspend() noexcept;
+ void unhandled_exception() noexcept;
+ void return_void() noexcept;
+ __coro::coroutine_handle<> unhandled_stopped() noexcept;
+};
+
struct as_awaitable_t
{
- template <class _T, class _Promise>
+ template <class _Tp, class _Promise>
static constexpr auto __select_impl_() noexcept
{
- if constexpr (tag_invocable<as_awaitable_t, _T, _Promise&>)
+ if constexpr (tag_invocable<as_awaitable_t, _Tp, _Promise&>)
{
- using _Result = tag_invoke_result_t<as_awaitable_t, _T, _Promise&>;
+ using _Result = tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&>;
constexpr bool _Nothrow =
- nothrow_tag_invocable<as_awaitable_t, _T, _Promise&>;
+ nothrow_tag_invocable<as_awaitable_t, _Tp, _Promise&>;
return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
}
- else if constexpr (__awaitable<_T>)
- { // NOT __awaitable<_T, _Promise> !!
- return static_cast < _T && (*)() noexcept > (nullptr);
+ else if constexpr (__awaitable<_Tp, __unspecified>)
+ { // NOT __awaitable<_Tp, _Promise> !!
+ return static_cast < _Tp && (*)() noexcept > (nullptr);
}
- else if constexpr (__awaitable_sender<_T, _Promise>)
+ else if constexpr (__awaitable_sender<_Tp, _Promise>)
{
- using _Result = __sender_awaitable_t<_Promise, _T>;
+ using _Result = __sender_awaitable_t<_Promise, _Tp>;
constexpr bool _Nothrow = __nothrow_constructible_from<
- _Result, _T, __coro::coroutine_handle<_Promise>>;
+ _Result, _Tp, __coro::coroutine_handle<_Promise>>;
return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
}
else
{
- return static_cast < _T && (*)() noexcept > (nullptr);
+ return static_cast < _Tp && (*)() noexcept > (nullptr);
}
}
- template <class _T, class _Promise>
- using __select_impl_t = decltype(__select_impl_<_T, _Promise>());
+ template <class _Tp, class _Promise>
+ using __select_impl_t = decltype(__select_impl_<_Tp, _Promise>());
- template <class _T, class _Promise>
- auto operator()(_T&& __t, _Promise& __promise) const
- noexcept(__nothrow_callable<__select_impl_t<_T, _Promise>>)
- -> __call_result_t<__select_impl_t<_T, _Promise>>
+ template <class _Tp, class _Promise>
+ auto operator()(_Tp&& __t, _Promise& __promise) const
+ noexcept(__nothrow_callable<__select_impl_t<_Tp, _Promise>>)
+ -> __call_result_t<__select_impl_t<_Tp, _Promise>>
{
- if constexpr (tag_invocable<as_awaitable_t, _T, _Promise&>)
+ if constexpr (tag_invocable<as_awaitable_t, _Tp, _Promise&>)
{
- using _Result = tag_invoke_result_t<as_awaitable_t, _T, _Promise&>;
+ using _Result = tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&>;
static_assert(__awaitable<_Result, _Promise>);
- return tag_invoke(*this, (_T &&) __t, __promise);
+ return tag_invoke(*this, (_Tp &&) __t, __promise);
}
- else if constexpr (__awaitable<_T>)
- { // NOT __awaitable<_T, _Promise> !!
- return (_T &&) __t;
+ else if constexpr (__awaitable<_Tp, __unspecified>)
+ { // NOT __awaitable<_Tp, _Promise> !!
+ return (_Tp &&) __t;
}
- else if constexpr (__awaitable_sender<_T, _Promise>)
+ else if constexpr (__awaitable_sender<_Tp, _Promise>)
{
auto __hcoro =
__coro::coroutine_handle<_Promise>::from_promise(__promise);
- return __sender_awaitable_t<_Promise, _T>{(_T &&) __t, __hcoro};
+ return __sender_awaitable_t<_Promise, _Tp>{(_Tp &&) __t, __hcoro};
}
else
{
- return (_T &&) __t;
+ return (_Tp &&) __t;
}
}
};
} // namespace __as_awaitable
+
using __as_awaitable::as_awaitable_t;
inline constexpr as_awaitable_t as_awaitable;
@@ -2261,6 +2384,7 @@
}
};
} // namespace __with_awaitable_senders
+
using __with_awaitable_senders::__continuation_handle;
using __with_awaitable_senders::with_awaitable_senders;
#endif
@@ -2269,49 +2393,74 @@
// NOT TO SPEC: __submit
namespace __submit_
{
-template <class _SenderId, class _ReceiverId>
-struct __operation
-{
- using _Sender = stdexec::__t<_SenderId>;
- using _Receiver = stdexec::__t<_ReceiverId>;
- struct __t;
+template <class _ReceiverId>
+struct __operation_base;
- struct __receiver
+template <class _ReceiverId>
+struct __operation_base
+{
+ using _Receiver = __t<_ReceiverId>;
+ _Receiver __rcvr_;
+
+ using __delete_fn_t = void(__operation_base<_ReceiverId>*) noexcept;
+ __delete_fn_t* __delete_;
+};
+
+template <class _ReceiverId>
+struct __receiver
+{
+ using is_receiver = void;
+ using _Receiver = stdexec::__t<_ReceiverId>;
+
+ struct __t
{
- using __t = __receiver;
using __id = __receiver;
- __operation::__t* __op_state_;
+ __operation_base<_ReceiverId>* __op_state_;
+
// Forward all the receiver ops, and delete the operation state.
template <__one_of<set_value_t, set_error_t, set_stopped_t> _Tag,
class... _As>
requires __callable<_Tag, _Receiver, _As...>
friend void tag_invoke(
- _Tag __tag, __receiver&& __self,
+ _Tag __tag, __t&& __self,
_As&&... __as) noexcept(__nothrow_callable<_Tag, _Receiver, _As...>)
{
// Delete the state as cleanup:
- std::unique_ptr<__operation::__t> __g{__self.__op_state_};
+ auto __g = __scope_guard{__self.__op_state_->__delete_,
+ __self.__op_state_};
return __tag((_Receiver &&) __self.__op_state_->__rcvr_,
(_As &&) __as...);
}
+
// Forward all receiever queries.
- friend auto tag_invoke(get_env_t, const __receiver& __self)
+ friend auto tag_invoke(get_env_t, const __t& __self)
-> env_of_t<_Receiver>
{
return get_env((const _Receiver&)__self.__op_state_->__rcvr_);
}
};
+};
+template <class _ReceiverId>
+using __receiver_t = __t<__receiver<_ReceiverId>>;
- struct __t
- {
- using __id = __operation;
- _Receiver __rcvr_;
- connect_result_t<_Sender, __receiver> __op_state_;
- __t(_Sender&& __sndr, _Receiver&& __rcvr) :
- __rcvr_((_Receiver &&) __rcvr),
- __op_state_(connect((_Sender &&) __sndr, __receiver{this}))
- {}
- };
+template <class _SenderId, class _ReceiverId>
+struct __operation : __operation_base<_ReceiverId>
+{
+ using _Sender = stdexec::__t<_SenderId>;
+ using _Receiver = stdexec::__t<_ReceiverId>;
+
+ connect_result_t<_Sender, __receiver_t<_ReceiverId>> __op_state_;
+
+ template <__decays_to<_Receiver> _CvrefReceiver>
+ __operation(_Sender&& __sndr, _CvrefReceiver&& __rcvr) :
+ __operation_base<_ReceiverId>{
+ (_CvrefReceiver &&) __rcvr,
+ [](__operation_base<_ReceiverId>* __self) noexcept {
+ delete static_cast<__operation*>(__self);
+ }},
+ __op_state_(
+ connect((_Sender &&) __sndr, __receiver_t<_ReceiverId>{this}))
+ {}
};
struct __submit_t
@@ -2319,12 +2468,13 @@
template <receiver _Receiver, sender_to<_Receiver> _Sender>
void operator()(_Sender&& __sndr, _Receiver __rcvr) const noexcept(false)
{
- start((new __t<__operation<__id<_Sender>, __id<_Receiver>>>{
+ start((new __operation<__id<_Sender>, __id<_Receiver>>{
(_Sender &&) __sndr, (_Receiver &&) __rcvr})
->__op_state_);
}
};
} // namespace __submit_
+
using __submit_::__submit_t;
inline constexpr __submit_t __submit{};
@@ -2334,10 +2484,12 @@
{
using __t = __scheduler;
using __id = __scheduler;
+
template <class _Receiver>
struct __op : __immovable
{
_Receiver __recv_;
+
friend void tag_invoke(start_t, __op& __self) noexcept
{
set_value((_Receiver &&) __self.__recv_);
@@ -2348,6 +2500,7 @@
{
using __t = __sender;
using __id = __sender;
+ using is_sender = void;
using completion_signatures =
stdexec::completion_signatures<set_value_t()>;
@@ -2375,20 +2528,25 @@
struct __detached_receiver
{
using _Env = stdexec::__t<_EnvId>;
+
struct __t
{
using __id = __detached_receiver;
[[no_unique_address]] _Env __env_;
+
template <class... _As>
friend void tag_invoke(set_value_t, __t&&, _As&&...) noexcept
{}
+
template <class _Error>
[[noreturn]] friend void tag_invoke(set_error_t, __t&&,
_Error&&) noexcept
{
std::terminate();
}
+
friend void tag_invoke(set_stopped_t, __t&&) noexcept {}
+
friend const _Env& tag_invoke(get_env_t, const __t& __self) noexcept
{
// BUGBUG NOT TO SPEC
@@ -2397,8 +2555,7 @@
};
};
template <class _Env>
-using __detached_receiver_t =
- __t<__detached_receiver<__id<remove_cvref_t<_Env>>>>;
+using __detached_receiver_t = __t<__detached_receiver<__id<__decay_t<_Env>>>>;
struct start_detached_t;
@@ -2406,7 +2563,7 @@
// are the signatures to test against, in order:
using _Sender = __0;
using _Env = __1;
-using __cust_sigs =
+using __cust_sigs = //
__types<tag_invoke_t(start_detached_t, _Sender),
tag_invoke_t(start_detached_t, _Sender, _Env),
tag_invoke_t(start_detached_t, get_scheduler_t(_Env&), _Sender),
@@ -2447,6 +2604,7 @@
}
};
} // namespace __start_detached
+
using __start_detached::start_detached_t;
inline constexpr start_detached_t start_detached{};
@@ -2461,6 +2619,7 @@
struct __operation
{
using _Receiver = stdexec::__t<_ReceiverId>;
+
struct __t : __immovable
{
using __id = __operation;
@@ -2488,26 +2647,24 @@
struct __t
{
using __id = __basic_sender;
- using completion_signatures = __completion_signatures_<_Tag, _Ts...>;
using is_sender = void;
+ using completion_signatures = __completion_signatures_<_Tag, _Ts...>;
std::tuple<_Ts...> __vals_;
template <receiver_of<completion_signatures> _Receiver>
requires(copy_constructible<_Ts> && ...)
- friend auto tag_invoke(
- connect_t, const __t& __sndr,
- _Receiver
- __rcvr) noexcept((std::is_nothrow_copy_constructible_v<_Ts> &&
- ...)) -> __operation_t<_Receiver>
+ friend auto tag_invoke(connect_t, const __t& __sndr,
+ _Receiver __rcvr) //
+ noexcept((std::is_nothrow_copy_constructible_v<_Ts> && ...))
+ -> __operation_t<_Receiver>
{
return {{}, __sndr.__vals_, (_Receiver &&) __rcvr};
}
template <receiver_of<completion_signatures> _Receiver>
- friend auto
- tag_invoke(connect_t, __t&& __sndr, _Receiver __rcvr) noexcept(
- (std::is_nothrow_move_constructible_v<_Ts> && ...))
+ friend auto tag_invoke(connect_t, __t&& __sndr, _Receiver __rcvr) //
+ noexcept((std::is_nothrow_move_constructible_v<_Ts> && ...))
-> __operation_t<_Receiver>
{
return {{}, ((__t &&) __sndr).__vals_, (_Receiver &&) __rcvr};
@@ -2524,6 +2681,7 @@
struct __sender
{
using __base = stdexec::__t<__basic_sender<set_value_t, _Values...>>;
+
struct __t : __base
{
using __id = __sender;
@@ -2534,6 +2692,7 @@
struct __error_sender
{
using __base = stdexec::__t<__basic_sender<set_error_t, _Error>>;
+
struct __t : __base
{
using __id = __error_sender;
@@ -2550,9 +2709,9 @@
{
template <__movable_value... _Ts>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
- __t<__sender<decay_t<_Ts>...>>
+ __t<__sender<__decay_t<_Ts>...>>
operator()(_Ts&&... __ts) const
- noexcept((std::is_nothrow_constructible_v<decay_t<_Ts>, _Ts> && ...))
+ noexcept((__nothrow_constructible_from<__decay_t<_Ts>, _Ts> && ...))
{
return {{{(_Ts &&) __ts...}}};
}
@@ -2562,9 +2721,9 @@
{
template <__movable_value _Error>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
- __t<__error_sender<decay_t<_Error>>>
+ __t<__error_sender<__decay_t<_Error>>>
operator()(_Error&& __err) const
- noexcept(std::is_nothrow_constructible_v<decay_t<_Error>, _Error>)
+ noexcept(__nothrow_constructible_from<__decay_t<_Error>, _Error>)
{
return {{{(_Error &&) __err}}};
}
@@ -2580,6 +2739,7 @@
}
} just_stopped{};
} // namespace __just
+
using __just::just;
using __just::just_error;
using __just::just_stopped;
@@ -2592,21 +2752,27 @@
struct __as_receiver
{
_Fun __fun_;
+
friend void tag_invoke(set_value_t, __as_receiver&& __rcvr) noexcept
- try
{
- __rcvr.__fun_();
+ try
+ {
+ __rcvr.__fun_();
+ }
+ catch (...)
+ {
+ set_error((__as_receiver &&) __rcvr, std::exception_ptr());
+ }
}
- catch (...)
- {
- set_error((__as_receiver &&) __rcvr, std::exception_ptr());
- }
+
[[noreturn]] friend void tag_invoke(set_error_t, __as_receiver&&,
std::exception_ptr) noexcept
{
std::terminate();
}
+
friend void tag_invoke(set_stopped_t, __as_receiver&&) noexcept {}
+
friend empty_env tag_invoke(get_env_t, const __as_receiver&)
{
return {};
@@ -2617,13 +2783,14 @@
{
template <scheduler _Scheduler, class _Fun>
requires __callable<_Fun&> && move_constructible<_Fun>
- void operator()(_Scheduler&& __sched, _Fun __fun) const
+ void operator()(_Scheduler&& __sched, _Fun __fun) const //
noexcept(noexcept(__submit(schedule((_Scheduler &&) __sched),
__as_receiver<_Fun>{(_Fun &&) __fun})))
{
(void)__submit(schedule((_Scheduler &&) __sched),
__as_receiver<_Fun>{(_Fun &&) __fun});
}
+
template <scheduler _Scheduler, class _Fun>
requires __callable<_Fun&> && move_constructible<_Fun> &&
tag_invocable<execute_t, _Scheduler, _Fun>
@@ -2634,29 +2801,30 @@
}
};
} // namespace __execute_
+
using __execute_::execute_t;
inline constexpr execute_t execute{};
// NOT TO SPEC:
namespace __closure
{
-template <__class _D>
+template <__class _Dp>
struct sender_adaptor_closure;
}
+
using __closure::sender_adaptor_closure;
-template <class _T>
+template <class _Tp>
concept __sender_adaptor_closure =
- derived_from<remove_cvref_t<_T>,
- sender_adaptor_closure<remove_cvref_t<_T>>> &&
- move_constructible<remove_cvref_t<_T>> &&
- constructible_from<remove_cvref_t<_T>, _T>;
+ derived_from<__decay_t<_Tp>, sender_adaptor_closure<__decay_t<_Tp>>> &&
+ move_constructible<__decay_t<_Tp>> &&
+ constructible_from<__decay_t<_Tp>, _Tp>;
-template <class _T, class _Sender>
+template <class _Tp, class _Sender>
concept __sender_adaptor_closure_for =
- __sender_adaptor_closure<_T> && sender<remove_cvref_t<_Sender>> &&
- __callable<_T, remove_cvref_t<_Sender>> &&
- sender<__call_result_t<_T, remove_cvref_t<_Sender>>>;
+ __sender_adaptor_closure<_Tp> && sender<__decay_t<_Sender>> &&
+ __callable<_Tp, __decay_t<_Sender>> &&
+ sender<__call_result_t<_Tp, __decay_t<_Sender>>>;
namespace __closure
{
@@ -2685,7 +2853,7 @@
}
};
-template <__class _D>
+template <__class _Dp>
struct sender_adaptor_closure
{};
@@ -2697,8 +2865,7 @@
}
template <__sender_adaptor_closure _T0, __sender_adaptor_closure _T1>
-__compose<remove_cvref_t<_T0>, remove_cvref_t<_T1>> operator|(_T0&& __t0,
- _T1&& __t1)
+__compose<__decay_t<_T0>, __decay_t<_T1>> operator|(_T0&& __t0, _T1&& __t1)
{
return {{}, (_T0 &&) __t0, (_T1 &&) __t1};
}
@@ -2725,8 +2892,8 @@
template <sender _Sender>
requires __callable<const _Fun&, _Sender, const _As&...>
__call_result_t<const _Fun&, _Sender, const _As&...>
- operator()(_Sender&& __sndr) const& noexcept(
- __nothrow_callable<const _Fun&, _Sender, const _As&...>)
+ operator()(_Sender&& __sndr) const& //
+ noexcept(__nothrow_callable<const _Fun&, _Sender, const _As&...>)
{
return std::apply(
[&__sndr, this](const _As&... __as) {
@@ -2736,32 +2903,37 @@
}
};
} // namespace __closure
+
using __closure::__binder_back;
namespace __adaptors
{
// A derived-to-base cast that works even when the base is not
// accessible from derived.
-template <class _T, class _U>
+template <class _Tp, class _Up>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
- __copy_cvref_t<_U&&, _T>
- __c_cast(_U&& u) noexcept
- requires __decays_to<_T, _T>
+ __copy_cvref_t<_Up&&, _Tp>
+ __c_cast(_Up&& u) noexcept
+ requires __decays_to<_Tp, _Tp>
{
- static_assert(std::is_reference_v<__copy_cvref_t<_U&&, _T>>);
- static_assert(std::is_base_of_v<_T, std::remove_reference_t<_U>>);
- return (__copy_cvref_t<_U&&, _T>)(_U &&) u;
+ static_assert(std::is_reference_v<__copy_cvref_t<_Up&&, _Tp>>);
+ static_assert(std::is_base_of_v<_Tp, __decay_t<_Up>>);
+ return (__copy_cvref_t<_Up&&, _Tp>)(_Up &&) u;
}
+
namespace __no
{
struct __nope
{};
+
struct __receiver : __nope
{};
+
void tag_invoke(set_error_t, __receiver, std::exception_ptr) noexcept;
void tag_invoke(set_stopped_t, __receiver) noexcept;
empty_env tag_invoke(get_env_t, __receiver) noexcept;
} // namespace __no
+
using __not_a_receiver = __no::__receiver;
template <class _Base>
@@ -2800,6 +2972,7 @@
}
};
};
+
template <derived_from<__no::__nope> _Base>
struct __adaptor<_Base>
{
@@ -2821,21 +2994,20 @@
->decltype(((_Self &&) __self)._TAG((_Ts &&) __ts...)) \
{ \
return ((_Self &&) __self)._TAG((_Ts &&) __ts...); \
- } \
- /**/
+ } /**/
#define _CALL_MEMBER(_TAG, ...) __call_##_TAG(__VA_ARGS__)
#if STDEXEC_CLANG()
// Only clang gets this right.
-#define _MISSING_MEMBER(_D, _TAG) requires { typename _D::_TAG; }
+#define _MISSING_MEMBER(_Dp, _TAG) requires { typename _Dp::_TAG; }
#define _DEFINE_MEMBER(_TAG) _DISPATCH_MEMBER(_TAG) using _TAG = void
#else
-#define _MISSING_MEMBER(_D, _TAG) (__missing_##_TAG<_D>())
+#define _MISSING_MEMBER(_Dp, _TAG) (__missing_##_TAG<_Dp>())
#define _DEFINE_MEMBER(_TAG) \
- template <class _D> \
+ template <class _Dp> \
static constexpr bool __missing_##_TAG() noexcept \
{ \
- return requires { requires bool(int(_D::_TAG)); }; \
+ return requires { requires bool(int(_Dp::_TAG)); }; \
} \
_DISPATCH_MEMBER(_TAG) \
static constexpr int _TAG = 1 /**/
@@ -2854,28 +3026,28 @@
static constexpr bool __has_base = !derived_from<_Base, __no::__nope>;
- template <class _D>
- using __base_from_derived_t = decltype(__declval<_D>().base());
+ 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 _D>
- using __base_t = __minvoke<__get_base_t, _D&&>;
+ template <class _Dp>
+ using __base_t = __minvoke<__get_base_t, _Dp&&>;
- template <class _D>
+ template <class _Dp>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
- static __base_t<_D>
- __get_base(_D&& __self) noexcept
+ static __base_t<_Dp>
+ __get_base(_Dp&& __self) noexcept
{
if constexpr (__has_base)
{
- return __c_cast<__t>((_D &&) __self).base();
+ return __c_cast<__t>((_Dp &&) __self).base();
}
else
{
- return ((_D &&) __self).base();
+ return ((_Dp &&) __self).base();
}
}
@@ -2891,15 +3063,15 @@
_CALL_MEMBER(set_value, (_Derived &&) __self, (_As &&) __as...);
}
- template <same_as<set_value_t> _SetValue, class _D = _Derived,
+ template <same_as<set_value_t> _SetValue, class _Dp = _Derived,
class... _As>
- requires _MISSING_MEMBER(_D, set_value) &&
- tag_invocable<set_value_t, __base_t<_D>, _As...>
+ requires _MISSING_MEMBER(_Dp, set_value) &&
+ tag_invocable<set_value_t, __base_t<_Dp>, _As...>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
friend void tag_invoke(_SetValue, _Derived&& __self,
_As&&... __as) noexcept
{
- stdexec::set_value(__get_base((_D &&) __self), (_As &&) __as...);
+ stdexec::set_value(__get_base((_Dp &&) __self), (_As &&) __as...);
}
template <same_as<set_error_t> _SetError, class _Error>
@@ -2915,9 +3087,9 @@
}
template <same_as<set_error_t> _SetError, class _Error,
- class _D = _Derived>
- requires _MISSING_MEMBER(_D, set_error) &&
- tag_invocable<set_error_t, __base_t<_D>, _Error>
+ class _Dp = _Derived>
+ requires _MISSING_MEMBER(_Dp, set_error) &&
+ tag_invocable<set_error_t, __base_t<_Dp>, _Error>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
friend void tag_invoke(_SetError, _Derived&& __self,
_Error&& __err) noexcept
@@ -2926,20 +3098,20 @@
(_Error &&) __err);
}
- template <same_as<set_stopped_t> _SetStopped, class _D = _Derived>
+ template <same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
friend auto
tag_invoke(_SetStopped, _Derived&& __self) noexcept
- -> decltype(_CALL_MEMBER(set_stopped, (_D &&) __self))
+ -> 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_stopped_t> _SetStopped, class _D = _Derived>
- requires _MISSING_MEMBER(_D, set_stopped) &&
- tag_invocable<set_stopped_t, __base_t<_D>>
+ template <same_as<set_stopped_t> _SetStopped, class _Dp = _Derived>
+ requires _MISSING_MEMBER(_Dp, set_stopped) &&
+ tag_invocable<set_stopped_t, __base_t<_Dp>>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
friend void tag_invoke(_SetStopped, _Derived&& __self) noexcept
{
@@ -2947,20 +3119,20 @@
}
// Pass through the get_env receiver query
- template <same_as<get_env_t> _GetEnv, class _D = _Derived>
+ template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
friend auto
tag_invoke(_GetEnv, const _Derived& __self)
- -> decltype(_CALL_MEMBER(get_env, (const _D&)__self))
+ -> decltype(_CALL_MEMBER(get_env, (const _Dp&)__self))
{
return _CALL_MEMBER(get_env, __self);
}
- template <same_as<get_env_t> _GetEnv, class _D = _Derived>
- requires _MISSING_MEMBER(_D, get_env)
+ template <same_as<get_env_t> _GetEnv, class _Dp = _Derived>
+ requires _MISSING_MEMBER(_Dp, get_env)
STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
friend auto tag_invoke(_GetEnv, const _Derived& __self)
- -> __call_result_t<get_env_t, __base_t<const _D&>>
+ -> __call_result_t<get_env_t, __base_t<const _Dp&>>
{
return stdexec::get_env(__get_base(__self));
}
@@ -2989,9 +3161,8 @@
__receiver_of_maybe_void<_Receiver, std::invoke_result_t<_Fun, _As...>>;
template <class _Receiver, class _Fun, class... _As>
-void __set_value_invoke_(
- _Receiver&& __rcvr, _Fun&& __fun,
- _As&&... __as) noexcept(__nothrow_invocable<_Fun, _As...>)
+void __set_value_invoke_(_Receiver&& __rcvr, _Fun&& __fun, _As&&... __as) //
+ noexcept(__nothrow_invocable<_Fun, _As...>)
{
if constexpr (same_as<void, std::invoke_result_t<_Fun, _As...>>)
{
@@ -3030,10 +3201,10 @@
template <class _Fun, class... _Args>
requires invocable<_Fun, _Args...>
-using __non_throwing_ = __bool<__nothrow_invocable<_Fun, _Args...>>;
+using __non_throwing_ = __mbool<__nothrow_invocable<_Fun, _Args...>>;
template <class _Tag, class _Fun, class _Sender, class _Env>
-using __with_error_invoke_t =
+using __with_error_invoke_t = //
__if_c<__v<__gather_completions_for<_Tag, _Sender, _Env,
__mbind_front_q<__non_throwing_, _Fun>,
__q<__mand>>>,
@@ -3041,7 +3212,7 @@
template <class _Fun, class... _Args>
requires invocable<_Fun, _Args...>
-using __set_value_invoke_t =
+using __set_value_invoke_t = //
completion_signatures<__minvoke<__remove<void, __qf<set_value_t>>,
std::invoke_result_t<_Fun, _Args...>>>;
@@ -3053,6 +3224,7 @@
struct __receiver
{
using _Receiver = stdexec::__t<_ReceiverId>;
+
struct __data
{
_Receiver __rcvr_;
@@ -3097,13 +3269,17 @@
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<_Sender, __receiver_t> __op_;
- __t(_Sender&& __sndr, _Receiver __rcvr, _Fun __fun) :
+ __t(_Sender&& __sndr, _Receiver __rcvr, _Fun __fun) //
+ noexcept(__nothrow_decay_copyable<_Receiver> //
+ && __nothrow_decay_copyable<_Fun> //
+ && __nothrow_connectable<_Sender, __receiver_t>) :
__data_{(_Receiver &&) __rcvr, (_Fun &&) __fun},
__op_(connect((_Sender &&) __sndr, __receiver_t{&__data_}))
{}
@@ -3129,21 +3305,27 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
[[no_unique_address]] _Sender __sndr_;
[[no_unique_address]] _Fun __fun_;
template <class _Self, class _Env>
- using __completion_signatures = __make_completion_signatures<
- __copy_cvref_t<_Self, _Sender>, _Env,
- __with_error_invoke_t<set_value_t, _Fun,
- __copy_cvref_t<_Self, _Sender>, _Env>,
- __mbind_front_q<__set_value_invoke_t, _Fun>>;
+ using __completion_signatures = //
+ __make_completion_signatures<
+ __copy_cvref_t<_Self, _Sender>, _Env,
+ __with_error_invoke_t<set_value_t, _Fun,
+ __copy_cvref_t<_Self, _Sender>, _Env>,
+ __mbind_front_q<__set_value_invoke_t, _Fun>>;
template <__decays_to<__t> _Self, receiver _Receiver>
requires sender_to<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
- friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr)
- -> __operation<_Self, _Receiver>
+ friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) //
+ noexcept(__nothrow_constructible_from<
+ __operation<_Self, _Receiver>,
+ __copy_cvref_t<_Self, _Sender>, _Receiver&&,
+ __copy_cvref_t<_Self, _Fun>>)
+ -> __operation<_Self, _Receiver>
{
return {((_Self &&) __self).__sndr_, (_Receiver &&) __rcvr,
((_Self &&) __self).__fun_};
@@ -3158,9 +3340,9 @@
-> __completion_signatures<_Self, _Env>
requires true;
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -3170,7 +3352,7 @@
struct then_t
{
template <class _Sender, class _Fun>
- using __sender = __t<__sender<stdexec::__id<decay_t<_Sender>>, _Fun>>;
+ using __sender = __t<__sender<stdexec::__id<__decay_t<_Sender>>, _Fun>>;
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<then_t, set_value_t,
@@ -3181,6 +3363,7 @@
{
return __sender<_Sender, _Fun>{(_Sender &&) __sndr, (_Fun &&) __fun};
}
+
template <sender _Sender, __movable_value _Fun>
requires __tag_invocable_with_completion_scheduler<then_t, set_value_t,
_Sender, _Fun>
@@ -3193,6 +3376,7 @@
return tag_invoke(then_t{}, std::move(__sched), (_Sender &&) __sndr,
(_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<then_t, set_value_t,
_Sender, _Fun>) &&
@@ -3202,6 +3386,7 @@
{
return tag_invoke(then_t{}, (_Sender &&) __sndr, (_Fun &&) __fun);
}
+
template <class _Fun>
__binder_back<then_t, _Fun> operator()(_Fun __fun) const
{
@@ -3209,6 +3394,7 @@
}
};
} // namespace __then
+
using __then::then_t;
inline constexpr then_t then{};
@@ -3274,25 +3460,26 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
[[no_unique_address]] _Sender __sndr_;
[[no_unique_address]] _Fun __fun_;
template <class _Self, class _Env>
- using __completion_signatures = __make_completion_signatures<
- __copy_cvref_t<_Self, _Sender>, _Env,
- __with_error_invoke_t<set_error_t, _Fun,
- __copy_cvref_t<_Self, _Sender>, _Env>,
- __q<__compl_sigs::__default_set_value>,
- __mbind_front_q<__set_value_invoke_t, _Fun>>;
+ using __completion_signatures = //
+ __make_completion_signatures<
+ __copy_cvref_t<_Self, _Sender>, _Env,
+ __with_error_invoke_t<set_error_t, _Fun,
+ __copy_cvref_t<_Self, _Sender>, _Env>,
+ __q<__compl_sigs::__default_set_value>,
+ __mbind_front_q<__set_value_invoke_t, _Fun>>;
template <__decays_to<__t> _Self, receiver _Receiver>
requires sender_to<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
- friend auto
- tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) noexcept(
- __nothrow_connectable<__copy_cvref_t<_Self, _Sender>,
- __receiver<_Receiver>>)
+ friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) //
+ noexcept(__nothrow_connectable<__copy_cvref_t<_Self, _Sender>,
+ __receiver<_Receiver>>)
-> connect_result_t<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
{
@@ -3310,9 +3497,9 @@
-> __completion_signatures<_Self, _Env>
requires true;
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -3322,8 +3509,7 @@
struct upon_error_t
{
template <class _Sender, class _Fun>
- using __sender =
- __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>, _Fun>>;
+ using __sender = __t<__sender<stdexec::__id<__decay_t<_Sender>>, _Fun>>;
template <sender _Sender, __movable_value _Fun>
requires __tag_invocable_with_completion_scheduler<
@@ -3338,6 +3524,7 @@
return tag_invoke(upon_error_t{}, std::move(__sched),
(_Sender &&) __sndr, (_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
upon_error_t, set_error_t, _Sender, _Fun>) &&
@@ -3347,6 +3534,7 @@
{
return tag_invoke(upon_error_t{}, (_Sender &&) __sndr, (_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
upon_error_t, set_error_t, _Sender, _Fun>) &&
@@ -3356,6 +3544,7 @@
{
return __sender<_Sender, _Fun>{(_Sender &&) __sndr, (_Fun &&) __fun};
}
+
template <class _Fun>
__binder_back<upon_error_t, _Fun> operator()(_Fun __fun) const
{
@@ -3363,6 +3552,7 @@
}
};
} // namespace __upon_error
+
using __upon_error::upon_error_t;
inline constexpr upon_error_t upon_error{};
@@ -3422,28 +3612,29 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
[[no_unique_address]] _Sender __sndr_;
[[no_unique_address]] _Fun __fun_;
template <class _Self, class _Env>
- using __completion_signatures = __make_completion_signatures<
- __copy_cvref_t<_Self, _Sender>, _Env,
- __with_error_invoke_t<set_stopped_t, _Fun,
- __copy_cvref_t<_Self, _Sender>, _Env>,
- __q<__compl_sigs::__default_set_value>,
- __q<__compl_sigs::__default_set_error>, __set_value_invoke_t<_Fun>>;
+ using __completion_signatures = //
+ __make_completion_signatures<
+ __copy_cvref_t<_Self, _Sender>, _Env,
+ __with_error_invoke_t<set_stopped_t, _Fun,
+ __copy_cvref_t<_Self, _Sender>, _Env>,
+ __q<__compl_sigs::__default_set_value>,
+ __q<__compl_sigs::__default_set_error>,
+ __set_value_invoke_t<_Fun>>;
template <__decays_to<__t> _Self, receiver _Receiver>
requires __receiver_of_invoke_result<_Receiver, _Fun> &&
sender_to<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
- friend auto tag_invoke(
- connect_t, _Self&& __self,
- _Receiver
- __rcvr) noexcept(__nothrow_connectable<_Sender,
- __receiver<
- _Receiver>>)
+ friend auto tag_invoke(connect_t, _Self&& __self,
+ _Receiver __rcvr) //
+ noexcept(
+ __nothrow_connectable<_Sender, __receiver<_Receiver>>)
-> connect_result_t<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
{
@@ -3461,9 +3652,9 @@
-> __completion_signatures<_Self, _Env>
requires true;
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -3473,7 +3664,7 @@
struct upon_stopped_t
{
template <class _Sender, class _Fun>
- using __sender = __t<__sender<__id<remove_cvref_t<_Sender>>, _Fun>>;
+ using __sender = __t<__sender<__id<__decay_t<_Sender>>, _Fun>>;
template <sender _Sender, __movable_value _Fun>
requires __tag_invocable_with_completion_scheduler<
@@ -3489,6 +3680,7 @@
return tag_invoke(upon_stopped_t{}, std::move(__sched),
(_Sender &&) __sndr, (_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
upon_stopped_t, set_stopped_t, _Sender, _Fun>) &&
@@ -3499,6 +3691,7 @@
return tag_invoke(upon_stopped_t{}, (_Sender &&) __sndr,
(_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
upon_stopped_t, set_stopped_t, _Sender, _Fun>) &&
@@ -3508,6 +3701,7 @@
{
return __sender<_Sender, _Fun>{(_Sender &&) __sndr, (_Fun &&) __fun};
}
+
template <__callable _Fun>
__binder_back<upon_stopped_t, _Fun> operator()(_Fun __fun) const
{
@@ -3515,6 +3709,7 @@
}
};
} // namespace __upon_stopped
+
using __upon_stopped::upon_stopped_t;
inline constexpr upon_stopped_t upon_stopped{};
@@ -3566,6 +3761,7 @@
public:
using __id = __receiver;
+
explicit __t(_Receiver __rcvr, _Shape __shape, _Fun __fun) :
receiver_adaptor<__t, _Receiver>((_Receiver &&) __rcvr),
__shape_(__shape), __f_((_Fun &&) __fun)
@@ -3573,6 +3769,9 @@
};
};
+template <class _Ty>
+using __decay_ref = __decay_t<_Ty>&;
+
template <class _SenderId, integral _Shape, class _Fun>
struct __sender
{
@@ -3585,30 +3784,34 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
[[no_unique_address]] _Sender __sndr_;
[[no_unique_address]] _Shape __shape_;
[[no_unique_address]] _Fun __fun_;
template <class _Sender, class _Env>
- using __with_error_invoke_t = __if_c<
- __v<__value_types_of_t<
- _Sender, _Env, __mbind_front_q<__non_throwing_, _Fun, _Shape>,
- __q<__mand>>>,
- completion_signatures<>, __with_exception_ptr>;
+ using __with_error_invoke_t = //
+ __if_c<
+ __v<__value_types_of_t<
+ _Sender, _Env,
+ __transform<__q<__decay_ref>,
+ __mbind_front_q<__non_throwing_, _Fun, _Shape>>,
+ __q<__mand>>>,
+ completion_signatures<>, __with_exception_ptr>;
template <class _Self, class _Env>
- using __completion_signatures = __make_completion_signatures<
- __copy_cvref_t<_Self, _Sender>, _Env,
- __with_error_invoke_t<__copy_cvref_t<_Self, _Sender>, _Env>>;
+ using __completion_signatures = //
+ __make_completion_signatures<
+ __copy_cvref_t<_Self, _Sender>, _Env,
+ __with_error_invoke_t<__copy_cvref_t<_Self, _Sender>, _Env>>;
template <__decays_to<__t> _Self, receiver _Receiver>
requires sender_to<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
- friend auto
- tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) noexcept(
- __nothrow_connectable<__copy_cvref_t<_Self, _Sender>,
- __receiver<_Receiver>>)
+ friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) //
+ noexcept(__nothrow_connectable<__copy_cvref_t<_Self, _Sender>,
+ __receiver<_Receiver>>)
-> connect_result_t<__copy_cvref_t<_Self, _Sender>,
__receiver<_Receiver>>
{
@@ -3627,9 +3830,9 @@
-> __completion_signatures<_Self, _Env>
requires true;
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -3640,7 +3843,7 @@
{
template <sender _Sender, integral _Shape, class _Fun>
using __sender =
- __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>, _Shape, _Fun>>;
+ __t<__sender<stdexec::__id<__decay_t<_Sender>>, _Shape, _Fun>>;
template <sender _Sender, integral _Shape, __movable_value _Fun>
requires __tag_invocable_with_completion_scheduler<
@@ -3654,6 +3857,7 @@
return tag_invoke(bulk_t{}, std::move(__sched), (_Sender &&) __sndr,
(_Shape &&) __shape, (_Fun &&) __fun);
}
+
template <sender _Sender, integral _Shape, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
bulk_t, set_value_t, _Sender, _Shape, _Fun>) &&
@@ -3664,6 +3868,7 @@
return tag_invoke(bulk_t{}, (_Sender &&) __sndr, (_Shape &&) __shape,
(_Fun &&) __fun);
}
+
template <sender _Sender, integral _Shape, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
bulk_t, set_value_t, _Sender, _Shape, _Fun>) &&
@@ -3674,6 +3879,7 @@
return __sender<_Sender, _Shape, _Fun>{(_Sender &&) __sndr, __shape,
(_Fun &&) __fun};
}
+
template <integral _Shape, class _Fun>
__binder_back<bulk_t, _Shape, _Fun> operator()(_Shape __shape,
_Fun __fun) const
@@ -3682,6 +3888,7 @@
}
};
} // namespace __bulk
+
using __bulk::bulk_t;
inline constexpr bulk_t bulk{};
@@ -3690,21 +3897,22 @@
namespace __split
{
template <class _BaseEnv>
-using __env_t = __make_env_t<_BaseEnv, // BUGBUG NOT TO SPEC
- __with<get_stop_token_t, in_place_stop_token>>;
+using __env_t = //
+ __make_env_t<_BaseEnv, // BUGBUG NOT TO SPEC
+ __with<get_stop_token_t, in_place_stop_token>>;
-template <class _SenderId, class _EnvId>
+template <class _CvrefSenderId, class _EnvId>
struct __sh_state;
-template <class _SenderId, class _EnvId>
+template <class _CvrefSenderId, class _EnvId>
struct __receiver
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
using _Env = stdexec::__t<_EnvId>;
class __t
{
- stdexec::__t<__sh_state<_SenderId, _EnvId>>& __sh_state_;
+ stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>& __sh_state_;
public:
using __id = __receiver;
@@ -3713,7 +3921,7 @@
class... _As>
friend void tag_invoke(_Tag __tag, __t&& __self, _As&&... __as) noexcept
{
- stdexec::__t<__sh_state<_SenderId, _EnvId>>& __state =
+ stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>& __state =
__self.__sh_state_;
try
@@ -3738,8 +3946,8 @@
return __self.__sh_state_.__env_;
}
- explicit __t(
- stdexec::__t<__sh_state<_SenderId, _EnvId>>& __sh_state) noexcept :
+ explicit __t(stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>&
+ __sh_state) noexcept :
__sh_state_(__sh_state)
{}
};
@@ -3753,10 +3961,10 @@
__notify_fn* __notify_{};
};
-template <class _SenderId, class _EnvId>
+template <class _CvrefSenderId, class _EnvId>
struct __sh_state
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
using _Env = stdexec::__t<_EnvId>;
struct __t
@@ -3764,36 +3972,37 @@
using __id = __sh_state;
template <class... _Ts>
- using __bind_tuples =
+ 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<_Sender, __env_t<_Env>,
+ 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<
- _Sender, __env_t<_Env>,
- __transform<__mbind_front_q<__decayed_tuple, set_error_t>,
- __bound_values_t>>;
+ 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<_SenderId, _EnvId>>;
+ 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<_Sender&, __receiver_> __op_state2_;
+ connect_result_t<_CvrefSender, __receiver_> __op_state2_;
- explicit __t(_Sender& __sndr, _Env __env) :
+ explicit __t(_CvrefSender&& __sndr, _Env __env) :
__env_(__make_env(
(_Env &&) __env,
__with_(get_stop_token, __stop_source_.get_token()))),
- __op_state2_(connect(__sndr, __receiver_{*this}))
+ __op_state2_(connect((_CvrefSender &&) __sndr, __receiver_{*this}))
{}
void __notify() noexcept
@@ -3814,10 +4023,10 @@
};
};
-template <class _SenderId, class _EnvId, class _ReceiverId>
+template <class _CvrefSenderId, class _EnvId, class _ReceiverId>
struct __operation
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
using _Env = stdexec::__t<_EnvId>;
using _Receiver = stdexec::__t<_ReceiverId>;
@@ -3826,30 +4035,35 @@
struct __on_stop_requested
{
in_place_stop_source& __stop_source_;
+
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>>;
+
+ using __on_stop = //
+ std::optional<typename stop_token_of_t<env_of_t<_Receiver>&>::
+ template callback_type<__on_stop_requested>>;
_Receiver __recvr_;
__on_stop __on_stop_{};
- std::shared_ptr<stdexec::__t<__sh_state<_SenderId, _EnvId>>>
+ 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<_SenderId, _EnvId>>>
- __shared_state) noexcept(std::
- is_nothrow_move_constructible_v<
- _Receiver>) :
+
+ __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},
__recvr_((_Receiver &&) __rcvr),
__shared_state_(std::move(__shared_state))
{}
+
STDEXEC_IMMOVABLE(__t);
static void __notify(__operation_base* __self) noexcept
@@ -3871,7 +4085,7 @@
friend void tag_invoke(start_t, __t& __self) noexcept
{
- stdexec::__t<__sh_state<_SenderId, _EnvId>>* __shared_state =
+ 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);
@@ -3915,46 +4129,54 @@
};
};
-template <class _SenderId, class _EnvId>
+template <class _CvrefSenderId, class _EnvId>
struct __sender
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
using _Env = stdexec::__t<_EnvId>;
template <class _Receiver>
- using __operation =
- stdexec::__t<__operation<_SenderId, _EnvId, stdexec::__id<_Receiver>>>;
+ using __operation = stdexec::__t<
+ __operation<_CvrefSenderId, _EnvId, stdexec::__id<_Receiver>>>;
- class __t
+ struct __t
{
- using __sh_state_ = stdexec::__t<__sh_state<_SenderId, _EnvId>>;
+ using __id = __sender;
+ using is_sender = void;
+
+ explicit __t(_CvrefSender&& __sndr, _Env __env) :
+ __shared_state_{std::make_shared<__sh_state_>(
+ (_CvrefSender &&) __sndr, (_Env &&) __env)}
+ {}
+
+ private:
+ using __sh_state_ = stdexec::__t<__sh_state<_CvrefSenderId, _EnvId>>;
template <class... _Tys>
using __set_value_t =
- completion_signatures<set_value_t(const decay_t<_Tys>&...)>;
+ 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>&)>;
+ completion_signatures<set_error_t(const __decay_t<_Ty>&)>;
template <class _Self>
- using __completions_t = make_completion_signatures<
- _Sender&, __env_t<__make_dependent_on<_Env, _Self>>,
- completion_signatures<set_error_t(const std::exception_ptr&),
- set_stopped_t()>, // NOT TO SPEC
- __set_value_t, __set_error_t>;
+ using __completions_t = //
+ make_completion_signatures<
+ // NOT TO SPEC:
+ // See
+ // https://github.com/brycelelbach/wg21_p2300_execution/issues/26
+ _CvrefSender, __env_t<__make_dependent_on<_Env, _Self>>,
+ completion_signatures<set_error_t(const std::exception_ptr&),
+ set_stopped_t()>, // NOT TO SPEC
+ __set_value_t, __set_error_t>;
- _Sender __sndr_;
std::shared_ptr<__sh_state_> __shared_state_;
- public:
- using __id = __sender;
-
template <__decays_to<__t> _Self,
receiver_of<__completions_t<_Self>> _Receiver>
- friend auto
- tag_invoke(connect_t, _Self&& __self, _Receiver __recvr) noexcept(
- std::is_nothrow_move_constructible_v<_Receiver>)
+ friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __recvr) //
+ noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
-> __operation<_Receiver>
{
return __operation<_Receiver>{(_Receiver &&) __recvr,
@@ -3964,12 +4186,6 @@
template <__decays_to<__t> _Self, class _OtherEnv>
friend auto tag_invoke(get_completion_signatures_t, _Self&&, _OtherEnv)
-> __completions_t<_Self>;
-
- explicit __t(_Sender __sndr, _Env __env) :
- __sndr_((_Sender &&) __sndr), __shared_state_{
- std::make_shared<__sh_state_>(
- __sndr_, (_Env &&) __env)}
- {}
};
};
@@ -3979,28 +4195,27 @@
// are the signatures to test against, in order:
using _Sender = __0;
using _Env = __1;
-using __cust_sigs = __types<
- tag_invoke_t(split_t,
- get_completion_scheduler_t<set_value_t>(get_env_t(_Sender&)),
- _Sender),
- tag_invoke_t(split_t,
- get_completion_scheduler_t<set_value_t>(get_env_t(_Sender&)),
- _Sender, _Env),
- tag_invoke_t(split_t, get_scheduler_t(_Env&), _Sender),
- tag_invoke_t(split_t, get_scheduler_t(_Env&), _Sender, _Env),
- tag_invoke_t(split_t, _Sender), tag_invoke_t(split_t, _Sender, _Env)>;
+using __cust_sigs = //
+ __types<tag_invoke_t(split_t,
+ get_completion_scheduler_t<set_value_t>(
+ get_env_t(const _Sender&)),
+ _Sender),
+ tag_invoke_t(split_t,
+ get_completion_scheduler_t<set_value_t>(
+ get_env_t(const _Sender&)),
+ _Sender, _Env),
+ tag_invoke_t(split_t, get_scheduler_t(_Env&), _Sender),
+ tag_invoke_t(split_t, get_scheduler_t(_Env&), _Sender, _Env),
+ tag_invoke_t(split_t, _Sender),
+ tag_invoke_t(split_t, _Sender, _Env)>;
template <class _Sender, class _Env>
inline constexpr bool __is_split_customized =
__minvocable<__which<__cust_sigs>, _Sender, _Env>;
template <class _Sender, class _Env>
-using __sender_t = __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>,
- stdexec::__id<remove_cvref_t<_Env>>>>;
-
-template <class _Sender, class _Env>
-using __receiver_t = __t<__receiver<stdexec::__id<remove_cvref_t<_Sender>>,
- stdexec::__id<remove_cvref_t<_Env>>>>;
+using __sender_t = __t<__sender<stdexec::__cvref_id<_Sender, _Sender>,
+ stdexec::__id<__decay_t<_Env>>>>;
template <class _Sender, class _Env>
using __dispatcher_for =
@@ -4010,8 +4225,8 @@
struct split_t
{
template <sender _Sender, class _Env = empty_env>
- requires(copy_constructible<remove_cvref_t<_Sender>> &&
- sender_to<_Sender&, __receiver_t<_Sender, _Env>>) ||
+ requires(sender_in<_Sender, _Env> &&
+ __decay_copyable<env_of_t<_Sender>>) ||
__is_split_customized<_Sender, _Env>
auto operator()(_Sender&& __sndr, _Env&& __env = _Env{}) const
noexcept(__nothrow_callable<__dispatcher_for<_Sender, _Env>,
@@ -4029,6 +4244,7 @@
}
};
} // namespace __split
+
using __split::split_t;
inline constexpr split_t split{};
@@ -4037,8 +4253,9 @@
namespace __ensure_started
{
template <class _BaseEnv>
-using __env_t = __make_env_t<_BaseEnv, // NOT TO SPEC
- __with<get_stop_token_t, in_place_stop_token>>;
+using __env_t = //
+ __make_env_t<_BaseEnv, // NOT TO SPEC
+ __with<get_stop_token_t, in_place_stop_token>>;
template <class _SenderId, class _EnvId>
struct __sh_state;
@@ -4056,6 +4273,7 @@
public:
using __id = __receiver;
+
explicit __t(stdexec::__t<__sh_state<_SenderId, _EnvId>>&
__shared_state) noexcept :
__shared_state_(__shared_state.__intrusive_from_this())
@@ -4110,22 +4328,23 @@
using __id = __sh_state;
template <class... _Ts>
- using __bind_tuples =
+ 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 =
+ using __bound_values_t = //
__value_types_of_t<_Sender, __env_t<_Env>,
__mbind_front_q<__decayed_tuple, set_value_t>,
__q<__bind_tuples>>;
- using __variant_t = __error_types_of_t<
- _Sender, __env_t<_Env>,
- __transform<__mbind_front_q<__decayed_tuple, set_error_t>,
- __bound_values_t>>;
+ using __variant_t = //
+ __error_types_of_t<
+ _Sender, __env_t<_Env>,
+ __transform<__mbind_front_q<__decayed_tuple, set_error_t>,
+ __bound_values_t>>;
using __receiver_t = stdexec::__t<__receiver<_SenderId, _EnvId>>;
@@ -4176,13 +4395,16 @@
struct __on_stop_requested
{
in_place_stop_source& __stop_source_;
+
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>>;
+
+ 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_{};
@@ -4191,15 +4413,17 @@
public:
using __id = __operation;
- __t(_Receiver __rcvr,
+
+ __t( //
+ _Receiver __rcvr, //
__intrusive_ptr<stdexec::__t<__sh_state<_SenderId, _EnvId>>>
- __shared_state) noexcept(std::
- is_nothrow_move_constructible_v<
- _Receiver>) :
+ __shared_state) //
+ noexcept(std::is_nothrow_move_constructible_v<_Receiver>) :
__operation_base{__notify},
__rcvr_((_Receiver &&) __rcvr),
__shared_state_(std::move(__shared_state))
{}
+
~__t()
{
// Check to see if this operation was ever started. If not,
@@ -4210,6 +4434,7 @@
__shared_state_->__detach();
}
}
+
STDEXEC_IMMOVABLE(__t);
static void __notify(__operation_base* __self) noexcept
@@ -4280,53 +4505,17 @@
using _Sender = stdexec::__t<_SenderId>;
using _Env = stdexec::__t<_EnvId>;
- class __t
+ struct __t
{
- using __sh_state_ = stdexec::__t<__sh_state<_SenderId, _EnvId>>;
- template <class _Receiver>
- using __operation = stdexec::__t<
- __operation<_SenderId, _EnvId, stdexec::__id<_Receiver>>>;
-
- 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 _Self>
- using __completions_t = make_completion_signatures<
- _Sender&, __env_t<__make_dependent_on<_Env, _Self>>,
- completion_signatures<set_error_t(std::exception_ptr&&),
- set_stopped_t()>, // BUGBUG NOT TO SPEC
- __set_value_t, __set_error_t>;
-
- _Sender __sndr_;
- __intrusive_ptr<__sh_state_> __shared_state_;
-
- template <same_as<__t> _Self,
- receiver_of<__completions_t<_Self>> _Receiver>
- friend auto
- tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) noexcept(
- std::is_nothrow_move_constructible_v<_Receiver>)
- -> __operation<_Receiver>
- {
- return __operation<_Receiver>{(_Receiver &&) __rcvr,
- std::move(__self).__shared_state_};
- }
-
- template <same_as<__t> _Self, class _OtherEnv>
- friend auto tag_invoke(get_completion_signatures_t, _Self&&, _OtherEnv)
- -> __completions_t<_Self>;
-
- public:
using __id = __sender;
+ using is_sender = void;
+
explicit __t(_Sender __sndr, _Env __env) :
__sndr_((_Sender &&) __sndr), __shared_state_{
__make_intrusive<__sh_state_>(
__sndr_, (_Env &&) __env)}
{}
+
~__t()
{
if (nullptr != __shared_state_)
@@ -4336,8 +4525,48 @@
__shared_state_->__detach(); // BUGBUG NOT TO SPEC
}
}
+
// Move-only:
__t(__t&&) = default;
+
+ private:
+ using __sh_state_ = stdexec::__t<__sh_state<_SenderId, _EnvId>>;
+ template <class _Receiver>
+ using __operation = stdexec::__t<
+ __operation<_SenderId, _EnvId, stdexec::__id<_Receiver>>>;
+
+ 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 _Self>
+ using __completions_t = //
+ make_completion_signatures<
+ _Sender&, __env_t<__make_dependent_on<_Env, _Self>>,
+ completion_signatures<set_error_t(std::exception_ptr&&),
+ set_stopped_t()>, // BUGBUG NOT TO SPEC
+ __set_value_t, __set_error_t>;
+
+ _Sender __sndr_;
+ __intrusive_ptr<__sh_state_> __shared_state_;
+
+ template <same_as<__t> _Self,
+ receiver_of<__completions_t<_Self>> _Receiver>
+ friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr) //
+ noexcept(std::is_nothrow_move_constructible_v<_Receiver>)
+ -> __operation<_Receiver>
+ {
+ return __operation<_Receiver>{(_Receiver &&) __rcvr,
+ std::move(__self).__shared_state_};
+ }
+
+ template <same_as<__t> _Self, class _OtherEnv>
+ friend auto tag_invoke(get_completion_signatures_t, _Self&&, _OtherEnv)
+ -> __completions_t<_Self>;
};
};
@@ -4347,29 +4576,32 @@
// are the signatures to test against, in order:
using _Sender = __0;
using _Env = __1;
-using __cust_sigs = __types<
- tag_invoke_t(ensure_started_t,
- get_completion_scheduler_t<set_value_t>(get_env_t(_Sender&)),
- _Sender),
- tag_invoke_t(ensure_started_t,
- get_completion_scheduler_t<set_value_t>(get_env_t(_Sender&)),
- _Sender, _Env),
- tag_invoke_t(ensure_started_t, get_scheduler_t(_Env&), _Sender),
- tag_invoke_t(ensure_started_t, get_scheduler_t(_Env&), _Sender, _Env),
- tag_invoke_t(ensure_started_t, _Sender),
- tag_invoke_t(ensure_started_t, _Sender, _Env)>;
+using __cust_sigs = //
+ __types<tag_invoke_t(
+ ensure_started_t,
+ get_completion_scheduler_t<set_value_t>(get_env_t(_Sender&)),
+ _Sender),
+ tag_invoke_t(
+ ensure_started_t,
+ get_completion_scheduler_t<set_value_t>(get_env_t(_Sender&)),
+ _Sender, _Env),
+ tag_invoke_t(ensure_started_t, get_scheduler_t(_Env&), _Sender),
+ tag_invoke_t(ensure_started_t, get_scheduler_t(_Env&), _Sender,
+ _Env),
+ tag_invoke_t(ensure_started_t, _Sender),
+ tag_invoke_t(ensure_started_t, _Sender, _Env)>;
template <class _Sender, class _Env>
inline constexpr bool __is_ensure_started_customized =
__minvocable<__which<__cust_sigs>, _Sender, _Env>;
template <class _Sender, class _Env>
-using __sender_t = __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>,
- stdexec::__id<remove_cvref_t<_Env>>>>;
+using __sender_t = __t<__sender<stdexec::__id<__decay_t<_Sender>>,
+ stdexec::__id<__decay_t<_Env>>>>;
template <class _Sender, class _Env>
-using __receiver_t = __t<__receiver<stdexec::__id<remove_cvref_t<_Sender>>,
- stdexec::__id<remove_cvref_t<_Env>>>>;
+using __receiver_t = __t<__receiver<stdexec::__id<__decay_t<_Sender>>,
+ stdexec::__id<__decay_t<_Env>>>>;
template <class _Sender, class _Env>
using __dispatcher_for =
@@ -4380,14 +4612,15 @@
void __test_ensure_started_sender(const __sender<_SenderId, _EnvId>& __sndr2){};
template <class _Sender>
-concept __ensure_started_sender = requires(typename _Sender::__id __sndr1) {
- __test_ensure_started_sender(__sndr1);
- };
+concept __ensure_started_sender = //
+ requires(typename _Sender::__id __sndr1) {
+ __test_ensure_started_sender(__sndr1);
+ };
struct ensure_started_t
{
template <sender _Sender, class _Env = empty_env>
- requires(copy_constructible<remove_cvref_t<_Sender>> &&
+ requires(copy_constructible<__decay_t<_Sender>> &&
sender_to<_Sender&, __receiver_t<_Sender, _Env>>) ||
__is_ensure_started_customized<_Sender, _Env>
auto operator()(_Sender&& __sndr, _Env&& __env = _Env{}) const
@@ -4412,6 +4645,7 @@
}
};
} // namespace __ensure_started
+
using __ensure_started::ensure_started_t;
inline constexpr ensure_started_t ensure_started{};
@@ -4421,8 +4655,8 @@
// [execution.senders.adaptors.let_stopped]
namespace __let
{
-template <class _T>
-using __decay_ref = decay_t<_T>&;
+template <class _Tp>
+using __decay_ref = __decay_t<_Tp>&;
template <class _Fun>
using __result_sender =
@@ -4443,10 +4677,12 @@
struct __tfx_signal_<_Set, _Set(_Args...)>
{
template <class _Env, class _Fun>
- using __f = make_completion_signatures<
- __minvoke<__result_sender<_Fun>, _Args...>, _Env,
- // because we don't know if connect-ing the result sender will throw:
- completion_signatures<set_error_t(std::exception_ptr)>>;
+ using __f = //
+ make_completion_signatures<
+ __minvoke<__result_sender<_Fun>, _Args...>, _Env,
+ // because we don't know if connect-ing the result sender will
+ // throw:
+ completion_signatures<set_error_t(std::exception_ptr)>>;
};
template <class _Env, class _Fun, class _Set, class _Sig>
@@ -4461,7 +4697,7 @@
{
using __id = __operation_base_;
using __results_variant_t = std::variant<std::monostate, _Tuples...>;
- using __op_state_variant_t =
+ using __op_state_variant_t = //
__minvoke<__transform<__uncurry<__op_state_for<_Receiver, _Fun>>,
__nullable_variant_t>,
_Tuples...>;
@@ -4488,28 +4724,31 @@
sender_to<__minvoke<__result_sender<_Fun>, _As...>,
_Receiver>
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>, _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(
- std::apply(std::move(__self.__op_state_->__fun_),
- __args),
- std::move(__self.__op_state_->__rcvr_));
- }});
- start(__op);
- }
- catch (...)
- {
- set_error(std::move(__self.__op_state_->__rcvr_),
- std::current_exception());
+ try
+ {
+ using __tuple_t = __decayed_tuple<_As...>;
+ using __op_state_t =
+ __minvoke<__op_state_for<_Receiver, _Fun>, _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(
+ std::apply(
+ std::move(__self.__op_state_->__fun_),
+ __args),
+ std::move(__self.__op_state_->__rcvr_));
+ }});
+ start(__op);
+ }
+ catch (...)
+ {
+ set_error(std::move(__self.__op_state_->__rcvr_),
+ std::current_exception());
+ }
}
template <__one_of<set_value_t, set_error_t, set_stopped_t> _Tag,
@@ -4534,10 +4773,11 @@
};
template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Let>
-using __receiver = stdexec::__t<__gather_completions_for<
- _Let, __cvref_t<_CvrefSenderId>, env_of_t<__t<_ReceiverId>>,
- __q<__decayed_tuple>,
- __munique<__mbind_front_q<__receiver_, _ReceiverId, _Fun, _Let>>>>;
+using __receiver = //
+ stdexec::__t<__gather_completions_for<
+ _Let, __cvref_t<_CvrefSenderId>, env_of_t<__t<_ReceiverId>>,
+ __q<__decayed_tuple>,
+ __munique<__mbind_front_q<__receiver_, _ReceiverId, _Fun, _Let>>>>;
template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Let>
using __operation_base = typename __receiver<_CvrefSenderId, _ReceiverId, _Fun,
@@ -4580,9 +4820,10 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
template <class _Self, class _Receiver>
- using __operation_t =
+ using __operation_t = //
stdexec::__t<__operation<stdexec::__cvref_id<_Self, _Sender>,
stdexec::__id<_Receiver>, _Fun, _Set>>;
template <class _Self, class _Receiver>
@@ -4590,10 +4831,11 @@
stdexec::__id<_Receiver>, _Fun, _Set>;
template <class _Sender, class _Env>
- using __completions = __mapply<
- __transform<__mbind_front_q<__tfx_signal_t, _Env, _Fun, _Set>,
- __q<__concat_completion_signatures_t>>,
- completion_signatures_of_t<_Sender, _Env>>;
+ using __completions = //
+ __mapply<
+ __transform<__mbind_front_q<__tfx_signal_t, _Env, _Fun, _Set>,
+ __q<__concat_completion_signatures_t>>,
+ completion_signatures_of_t<_Sender, _Env>>;
template <__decays_to<__t> _Self, receiver _Receiver>
requires sender_to<__copy_cvref_t<_Self, _Sender>,
@@ -4606,9 +4848,9 @@
((_Self &&) __self).__fun_};
}
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -4632,7 +4874,7 @@
using __t = _SetTag;
template <class _Sender, class _Fun>
using __sender = stdexec::__t<
- __let::__sender<stdexec::__id<remove_cvref_t<_Sender>>, _Fun, _LetTag>>;
+ __let::__sender<stdexec::__id<__decay_t<_Sender>>, _Fun, _LetTag>>;
template <sender _Sender, __movable_value _Fun>
requires __tag_invocable_with_completion_scheduler<_LetTag, set_value_t,
@@ -4646,6 +4888,7 @@
return tag_invoke(_LetTag{}, std::move(__sched), (_Sender &&) __sndr,
(_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
_LetTag, set_value_t, _Sender, _Fun>) &&
@@ -4655,6 +4898,7 @@
{
return tag_invoke(_LetTag{}, (_Sender &&) __sndr, (_Fun &&) __fun);
}
+
template <sender _Sender, __movable_value _Fun>
requires(!__tag_invocable_with_completion_scheduler<
_LetTag, set_value_t, _Sender, _Fun>) &&
@@ -4664,6 +4908,7 @@
{
return __sender<_Sender, _Fun>{(_Sender &&) __sndr, (_Fun &&) __fun};
}
+
template <class _Fun>
__binder_back<_LetTag, _Fun> operator()(_Fun __fun) const
{
@@ -4680,6 +4925,7 @@
struct let_stopped_t : __let::__let_xxx_t<let_stopped_t, set_stopped_t>
{};
} // namespace __let
+
using __let::let_value_t;
inline constexpr let_value_t let_value{};
using __let::let_error_t;
@@ -4709,6 +4955,7 @@
{
return (_Receiver &&) __op_->__rcvr_;
}
+
const _Receiver& base() const& noexcept
{
return __op_->__rcvr_;
@@ -4716,19 +4963,22 @@
template <class _Ty>
void set_value(_Ty&& __a) && noexcept
- try
{
- using _Value =
- __single_sender_value_t<_Sender, env_of_t<_Receiver>>;
- static_assert(constructible_from<_Value, _Ty>);
- stdexec::set_value(((__t &&) * this).base(),
- std::optional<_Value>{(_Ty &&) __a});
+ try
+ {
+ using _Value =
+ __single_sender_value_t<_Sender, env_of_t<_Receiver>>;
+ static_assert(constructible_from<_Value, _Ty>);
+ stdexec::set_value(((__t &&) * this).base(),
+ std::optional<_Value>{(_Ty &&) __a});
+ }
+ catch (...)
+ {
+ stdexec::set_error(((__t &&) * this).base(),
+ std::current_exception());
+ }
}
- catch (...)
- {
- stdexec::set_error(((__t &&) * this).base(),
- std::current_exception());
- }
+
void set_stopped() && noexcept
{
using _Value =
@@ -4751,10 +5001,12 @@
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
@@ -4775,6 +5027,7 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
template <class _Self, class _Receiver>
using __operation_t =
@@ -4797,9 +5050,9 @@
return {((_Self &&) __self).__sndr_, (_Receiver &&) __rcvr};
}
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -4827,10 +5080,11 @@
{
template <sender _Sender>
auto operator()(_Sender&& __sndr) const
- -> __t<__sender<stdexec::__id<decay_t<_Sender>>>>
+ -> __t<__sender<stdexec::__id<__decay_t<_Sender>>>>
{
return {(_Sender &&) __sndr};
}
+
__binder_back<stopped_as_optional_t> operator()() const noexcept
{
return {};
@@ -4843,11 +5097,13 @@
auto operator()(_Sender&& __sndr, _Error __err) const
{
return (_Sender &&) __sndr |
- let_stopped([__err2 = (_Error &&) __err]() mutable noexcept(
- std::is_nothrow_move_constructible_v<_Error>) {
- return just_error((_Error &&) __err2);
- });
+ let_stopped(
+ [__err2 = (_Error &&) __err]() mutable //
+ noexcept(std::is_nothrow_move_constructible_v<_Error>) {
+ return just_error((_Error &&) __err2);
+ });
}
+
template <__movable_value _Error>
auto operator()(_Error __err) const
-> __binder_back<stopped_as_error_t, _Error>
@@ -4856,6 +5112,7 @@
}
};
} // namespace __stopped_as_xxx
+
using __stopped_as_xxx::stopped_as_optional_t;
inline constexpr stopped_as_optional_t stopped_as_optional{};
using __stopped_as_xxx::stopped_as_error_t;
@@ -4870,6 +5127,7 @@
struct __task : __immovable
{
__task* __next_ = this;
+
union
{
void (*__execute_)(__task*) noexcept;
@@ -4915,6 +5173,7 @@
}
explicit __t(__task* __tail) noexcept : __task{.__tail_ = __tail} {}
+
__t(__task* __next, run_loop* __loop, _Receiver __rcvr) :
__task{{}, __next, {&__execute_impl}}, __loop_{__loop},
__rcvr_{(_Receiver &&) __rcvr}
@@ -4949,7 +5208,8 @@
{
using __t = __schedule_task;
using __id = __schedule_task;
- using completion_signatures =
+ using is_sender = void;
+ using completion_signatures = //
__completion_signatures_<set_value_t(),
set_error_t(std::exception_ptr),
set_stopped_t()>;
@@ -4983,7 +5243,7 @@
friend __scheduler tag_invoke(get_completion_scheduler_t<_CPO>,
const __env& __self) noexcept
{
- return __scheduler{__self.__loop_};
+ return __self.__loop_->get_scheduler();
}
};
@@ -5018,7 +5278,7 @@
}
// BUGBUG NOT TO SPEC
- friend bool tag_invoke(this_thread::execute_may_block_caller_t,
+ friend bool tag_invoke(execute_may_block_caller_t,
const __scheduler&) noexcept
{
return false;
@@ -5031,6 +5291,7 @@
run_loop* __loop_;
};
+
__scheduler get_scheduler() noexcept
{
return __scheduler{this};
@@ -5052,13 +5313,15 @@
template <class _ReceiverId>
inline void __operation<_ReceiverId>::__t::__start_() noexcept
-try
{
- __loop_->__push_back_(this);
-}
-catch (...)
-{
- set_error((_Receiver &&) __rcvr_, std::current_exception());
+ try
+ {
+ __loop_->__push_back_(this);
+ }
+ catch (...)
+ {
+ set_error((_Receiver &&) __rcvr_, std::current_exception());
+ }
}
inline void run_loop::run()
@@ -5107,11 +5370,11 @@
// variant<
// monostate,
// tuple<set_stopped_t>,
-// tuple<set_value_t, decay_t<_Values1>...>,
-// tuple<set_value_t, decay_t<_Values2>...>,
+// tuple<set_value_t, __decay_t<_Values1>...>,
+// tuple<set_value_t, __decay_t<_Values2>...>,
// ...
-// tuple<set_error_t, decay_t<_Error1>>,
-// tuple<set_error_t, decay_t<_Error2>>,
+// tuple<set_error_t, __decay_t<_Error1>>,
+// tuple<set_error_t, __decay_t<_Error2>>,
// ...
// >
template <class _State, class... _Tuples>
@@ -5129,10 +5392,11 @@
__make_bind<_State>>;
template <class _Sender, class _Env>
-using __variant_for_t = __minvoke<__minvoke<
- __mfold_right<__nullable_variant_t,
- __mbind_front_q<__bind_completions_t, _Sender, _Env>>,
- set_value_t, set_error_t, set_stopped_t>>;
+using __variant_for_t = //
+ __minvoke<__minvoke<
+ __mfold_right<__nullable_variant_t,
+ __mbind_front_q<__bind_completions_t, _Sender, _Env>>,
+ set_value_t, set_error_t, set_stopped_t>>;
template <class _SchedulerId, class _CvrefSenderId, class _ReceiverId>
struct __operation1;
@@ -5207,9 +5471,8 @@
(__nothrow_decay_copyable<_Args> && ...);
template <class _Tag, class... _Args>
- static void __complete_(
- _Tag __tag, __t&& __self,
- _Args&&... __args) noexcept(__nothrow_complete_<_Args...>)
+ static void __complete_(_Tag, __t&& __self, _Args&&... __args) //
+ noexcept(__nothrow_complete_<_Args...>)
{
// Write the tag and the args into the operation state so that
// we can forward the completion from within the scheduler's
@@ -5268,6 +5531,7 @@
__state1_(connect((_CvrefSender &&) __sndr, __receiver1_t{this})),
__state2_(connect(schedule(__sched_), __receiver2_t{this}))
{}
+
STDEXEC_IMMOVABLE(__t);
friend void tag_invoke(start_t, __t& __op_state) noexcept
@@ -5276,8 +5540,8 @@
}
void __complete() noexcept
- try
{
+ STDEXEC_ASSERT(!__data_.valueless_by_exception());
std::visit(
[&]<class _Tup>(_Tup& __tupl) -> void {
if constexpr (same_as<_Tup, std::monostate>)
@@ -5298,16 +5562,12 @@
},
__data_);
}
- catch (...)
- {
- set_error((_Receiver &&) __rcvr_, std::current_exception());
- }
};
};
template <class _Tag>
using __decay_signature =
- __transform<__q<decay_t>,
+ __transform<__q<__decay_t>,
__mcompose<__q<completion_signatures>, __qf<_Tag>>>;
template <class _SchedulerId>
@@ -5340,10 +5600,11 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
_Attrs __env_;
_Sender __sndr_;
- template <__decays_to<__t> _Self, class _Receiver>
+ template <__decays_to<__t> _Self, receiver _Receiver>
requires sender_to<__copy_cvref_t<_Self, _Sender>, _Receiver>
friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr)
-> stdexec::__t<
@@ -5361,26 +5622,36 @@
template <class... _Errs>
using __all_nothrow_decay_copyable =
- __bool<(__nothrow_decay_copyable<_Errs> && ...)>;
+ __mbool<(__nothrow_decay_copyable<_Errs> && ...)>;
template <class _Env>
- using __with_error_t =
+ using __scheduler_with_error_t = //
__if_c<__v<error_types_of_t<schedule_result_t<_Scheduler>, _Env,
__all_nothrow_decay_copyable>>,
completion_signatures<>, __with_exception_ptr>;
template <class _Env>
- using __scheduler_completions_t =
+ using __scheduler_completions_t = //
__make_completion_signatures<schedule_result_t<_Scheduler>, _Env,
- __with_error_t<_Env>,
+ __scheduler_with_error_t<_Env>,
__mconst<completion_signatures<>>>;
+ template <class _Env>
+ using __input_sender_with_error_t = //
+ __if_c<__v<value_types_of_t<
+ _Sender, _Env, __all_nothrow_decay_copyable, __mand>> &&
+ __v<error_types_of_t<_Sender, _Env,
+ __all_nothrow_decay_copyable>>,
+ completion_signatures<>, __with_exception_ptr>;
+
template <__decays_to<__t> _Self, class _Env>
friend auto tag_invoke(get_completion_signatures_t, _Self&&, _Env)
-> __make_completion_signatures<
__copy_cvref_t<_Self, _Sender>, _Env,
- __scheduler_completions_t<_Env>, __decay_signature<set_value_t>,
- __decay_signature<set_error_t>>;
+ __concat_completion_signatures_t<
+ __scheduler_completions_t<_Env>,
+ __input_sender_with_error_t<_Env>>,
+ __decay_signature<set_value_t>, __decay_signature<set_error_t>>;
};
};
@@ -5397,13 +5668,14 @@
template <scheduler _Scheduler, sender _Sender>
auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const
- -> stdexec::__t<__sender<stdexec::__id<decay_t<_Scheduler>>,
- stdexec::__id<decay_t<_Sender>>>>
+ -> stdexec::__t<__sender<stdexec::__id<__decay_t<_Scheduler>>,
+ stdexec::__id<__decay_t<_Sender>>>>
{
return {{(_Scheduler &&) __sched}, (_Sender &&) __sndr};
}
};
} // namespace __schedule_from
+
using __schedule_from::schedule_from_t;
inline constexpr schedule_from_t schedule_from{};
@@ -5428,6 +5700,7 @@
return tag_invoke(transfer_t{}, std::move(csch), (_Sender &&) __sndr,
(_Scheduler &&) __sched);
}
+
template <sender _Sender, scheduler _Scheduler>
requires(!__tag_invocable_with_completion_scheduler<
transfer_t, set_value_t, _Sender, _Scheduler>) &&
@@ -5439,6 +5712,7 @@
return tag_invoke(transfer_t{}, (_Sender &&) __sndr,
(_Scheduler &&) __sched);
}
+
// NOT TO SPEC: permit non-typed senders:
template <sender _Sender, scheduler _Scheduler>
requires(!__tag_invocable_with_completion_scheduler<
@@ -5448,14 +5722,16 @@
{
return schedule_from((_Scheduler &&) __sched, (_Sender &&) __sndr);
}
+
template <scheduler _Scheduler>
- __binder_back<transfer_t, decay_t<_Scheduler>>
+ __binder_back<transfer_t, __decay_t<_Scheduler>>
operator()(_Scheduler&& __sched) const
{
return {{}, {}, {(_Scheduler &&) __sched}};
}
};
} // namespace __transfer
+
using __transfer::transfer_t;
inline constexpr transfer_t transfer{};
@@ -5478,14 +5754,17 @@
using __id = __receiver_ref;
stdexec::__t<__operation<_SchedulerId, _SenderId, _ReceiverId>>*
__op_state_;
+
_Receiver&& base() && noexcept
{
return (_Receiver &&) __op_state_->__rcvr_;
}
+
const _Receiver& base() const& noexcept
{
return __op_state_->__rcvr_;
}
+
auto get_env() const
-> __make_env_t<env_of_t<_Receiver>,
__with<get_scheduler_t, _Scheduler>>
@@ -5511,10 +5790,12 @@
stdexec::__t<__receiver_ref<_SchedulerId, _SenderId, _ReceiverId>>;
stdexec::__t<__operation<_SchedulerId, _SenderId, _ReceiverId>>*
__op_state_;
+
_Receiver&& base() && noexcept
{
return (_Receiver &&) __op_state_->__rcvr_;
}
+
const _Receiver& base() const& noexcept
{
return __op_state_->__rcvr_;
@@ -5571,6 +5852,7 @@
__receiver_t{{}, this});
}}}
{}
+
STDEXEC_IMMOVABLE(__t);
_Scheduler __scheduler_;
@@ -5592,6 +5874,8 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
+
template <class _ReceiverId>
using __receiver_ref_t =
stdexec::__t<__receiver_ref<_SchedulerId, _SenderId, _ReceiverId>>;
@@ -5620,9 +5904,9 @@
((_Self &&) __self).__sndr_, (_Receiver &&) __rcvr};
}
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
@@ -5655,8 +5939,8 @@
template <scheduler _Scheduler, sender _Sender>
auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const
- -> __t<__sender<stdexec::__id<decay_t<_Scheduler>>,
- stdexec::__id<decay_t<_Sender>>>>
+ -> __t<__sender<stdexec::__id<__decay_t<_Scheduler>>,
+ stdexec::__id<__decay_t<_Sender>>>>
{
// connect-based customization will remove the need for this check
using __has_customizations =
@@ -5669,6 +5953,7 @@
}
};
} // namespace __on
+
using __on::on_t;
inline constexpr on_t on{};
@@ -5692,6 +5977,7 @@
return tag_invoke(*this, (_Scheduler &&) __sched,
(_Values &&) __vals...);
}
+
template <scheduler _Scheduler, __movable_value... _Values>
requires(!tag_invocable<transfer_just_t, _Scheduler, _Values...> ||
!sender<tag_invoke_result_t<transfer_just_t, _Scheduler,
@@ -5704,6 +5990,7 @@
}
};
} // namespace __transfer_just
+
using __transfer_just::transfer_just_t;
inline constexpr transfer_just_t transfer_just{};
@@ -5712,46 +5999,55 @@
namespace __into_variant
{
template <class _Sender, class _Env>
- requires sender<_Sender, _Env>
+ requires sender_in<_Sender, _Env>
using __into_variant_result_t = value_types_of_t<_Sender, _Env>;
-template <class _SenderId, class _ReceiverId>
+template <class _ReceiverId, class _Variant>
struct __receiver
{
using _Receiver = stdexec::__t<_ReceiverId>;
- class __t : receiver_adaptor<__t, _Receiver>
+ struct __t
{
-#if STDEXEC_NON_LEXICAL_FRIENDSHIP
- public:
-#endif
- using _Sender = stdexec::__t<_SenderId>;
+ using __id = __receiver;
using _Receiver = stdexec::__t<_ReceiverId>;
- friend receiver_adaptor<__t, _Receiver>;
+ _Receiver __rcvr_;
// Customize set_value by building a variant and passing the result
// to the base class
template <class... _As>
- void set_value(_As&&... __as) && noexcept
- try
+ requires constructible_from<_Variant, std::tuple<_As&&...>>
+ friend void tag_invoke(set_value_t, __t&& __self,
+ _As&&... __as) noexcept
{
- using __variant_t =
- __into_variant_result_t<_Sender, env_of_t<_Receiver>>;
- static_assert(
- constructible_from<__variant_t, std::tuple<_As&&...>>);
- stdexec::set_value(
- ((__t &&) * this).base(),
- __variant_t{std::tuple<_As&&...>{(_As &&) __as...}});
- }
- catch (...)
- {
- stdexec::set_error(((__t &&) * this).base(),
- std::current_exception());
+ try
+ {
+ set_value((_Receiver &&) __self.__rcvr_,
+ _Variant{std::tuple<_As&&...>{(_As &&) __as...}});
+ }
+ catch (...)
+ {
+ set_error((_Receiver &&) __self.__rcvr_,
+ std::current_exception());
+ }
}
- public:
- using __id = __receiver;
- using receiver_adaptor<__t, _Receiver>::receiver_adaptor;
+ template <class _Error>
+ friend void tag_invoke(set_error_t, __t&& __self,
+ _Error&& __err) noexcept
+ {
+ set_error((_Receiver &&) __self.__rcvr_, (_Error &&) __err);
+ }
+
+ friend void tag_invoke(set_stopped_t, __t&& __self) noexcept
+ {
+ set_stopped((_Receiver &&) __self.__rcvr_);
+ }
+
+ friend env_of_t<_Receiver> tag_invoke(get_env_t, const __t& __self)
+ {
+ return get_env(__self.__rcvr_);
+ }
};
};
@@ -5760,30 +6056,41 @@
{
using _Sender = stdexec::__t<_SenderId>;
- template <class _Receiver>
- using __receiver_t =
- stdexec::__t<__receiver<_SenderId, stdexec::__id<_Receiver>>>;
+ template <class _Env>
+ using __variant_t = __into_variant_result_t<_Sender, _Env>;
- class __t
+ template <class _Receiver>
+ using __receiver_t = //
+ stdexec::__t<
+ __receiver<__id<_Receiver>, __variant_t<env_of_t<_Receiver>>>>;
+
+ struct __t
{
+ using __id = __sender;
+ using is_sender = void;
+
+ template <__decays_to<_Sender> _CvrefSender>
+ explicit __t(_CvrefSender&& __sndr) : __sndr_((_CvrefSender &&) __sndr)
+ {}
+
+ private:
template <class...>
using __value_t = completion_signatures<>;
template <class _Env>
- using __compl_sigs = make_completion_signatures<
- _Sender, _Env,
- completion_signatures<set_value_t(
- __into_variant_result_t<_Sender, _Env>),
- set_error_t(std::exception_ptr)>,
- __value_t>;
+ using __compl_sigs = //
+ make_completion_signatures<
+ _Sender, _Env,
+ completion_signatures<set_value_t(__variant_t<_Env>),
+ set_error_t(std::exception_ptr)>,
+ __value_t>;
_Sender __sndr_;
template <receiver _Receiver>
requires sender_to<_Sender, __receiver_t<_Receiver>>
- friend auto
- tag_invoke(connect_t, __t&& __self, _Receiver __rcvr) noexcept(
- __nothrow_connectable<_Sender, __receiver_t<_Receiver>>)
+ friend auto tag_invoke(connect_t, __t&& __self, _Receiver __rcvr) //
+ noexcept(__nothrow_connectable<_Sender, __receiver_t<_Receiver>>)
-> connect_result_t<_Sender, __receiver_t<_Receiver>>
{
return stdexec::connect(
@@ -5791,22 +6098,16 @@
__receiver_t<_Receiver>{(_Receiver &&) __rcvr});
}
- friend auto tag_invoke(get_env_t, const __t& __self) noexcept(
- __nothrow_callable<get_env_t, const _Sender&>)
- -> __call_result_t<get_env_t, const _Sender&>
+ friend auto tag_invoke(get_env_t, const __t& __self) //
+ noexcept(__nothrow_callable<get_env_t, const _Sender&>)
+ -> __call_result_t<get_env_t, const _Sender&>
{
return get_env(__self.__sndr_);
}
template <class _Env>
- friend auto tag_invoke(get_completion_signatures_t, __t&&, _Env)
+ friend auto tag_invoke(get_completion_signatures_t, __t&&, _Env) //
-> __compl_sigs<_Env>;
-
- public:
- using __id = __sender;
- template <__decays_to<_Sender> _CvrefSender>
- explicit __t(_CvrefSender&& __sndr) : __sndr_((_CvrefSender &&) __sndr)
- {}
};
};
@@ -5814,17 +6115,19 @@
{
template <sender _Sender>
auto operator()(_Sender&& __sndr) const
- -> __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>>>
+ -> __t<__sender<stdexec::__id<__decay_t<_Sender>>>>
{
- return __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>>>{
- (_Sender &&) __sndr};
+ return __t<__sender<stdexec::__id<__decay_t<_Sender>>>>{(_Sender &&)
+ __sndr};
}
+
auto operator()() const noexcept
{
return __binder_back<into_variant_t>{};
}
};
} // namespace __into_variant
+
using __into_variant::into_variant_t;
inline constexpr into_variant_t into_variant{};
@@ -5843,6 +6146,7 @@
struct __on_stop_requested
{
in_place_stop_source& __stop_source_;
+
void operator()() noexcept
{
__stop_source_.request_stop();
@@ -5853,6 +6157,7 @@
struct __env
{
using _Env = stdexec::__t<_EnvId>;
+
struct __t
{
using __id = __env;
@@ -5866,8 +6171,10 @@
}
// Forward the receiver queries:
- template <__none_of<get_completion_signatures_t, get_stop_token_t> _Tag,
- same_as<__t> _Self, class... _As>
+ template < //
+ __none_of<get_completion_signatures_t, get_stop_token_t> _Tag, //
+ same_as<__t> _Self, //
+ class... _As>
requires __callable<_Tag, const __make_dependent_on<_Env, _Self>&,
_As...>
friend auto tag_invoke(_Tag __tag, const _Self& __self,
@@ -5884,39 +6191,55 @@
template <class _Env>
using __env_t = __t<__if_c<same_as<_Env, no_env>, no_env, __env<__id<_Env>>>>;
-template <class _T>
-using __decay_rvalue_ref = decay_t<_T>&&;
+template <class _Tp>
+using __decay_rvalue_ref = __decay_t<_Tp>&&;
template <class _Sender, class _Env>
-concept __max1_sender = sender<_Sender, _Env> &&
+concept __max1_sender = sender_in<_Sender, _Env> &&
__valid<__value_types_of_t, _Sender, _Env,
__mconst<int>, __msingle_or<void>>;
template <class _Env, class _Sender>
-using __single_values_of_t =
+using __single_values_of_t = //
__value_types_of_t<_Sender, _Env,
__transform<__q<__decay_rvalue_ref>, __q<__types>>,
__q<__msingle>>;
template <class _Env, class... _Senders>
-using __set_values_sig_t =
+using __set_values_sig_t = //
completion_signatures<__minvoke<__mconcat<__qf<set_value_t>>,
__single_values_of_t<_Env, _Senders>...>>;
+template <class... _Args>
+using __all_nothrow_decay_copyable =
+ __mbool<(__nothrow_decay_copyable<_Args> && ...)>;
+
+template <class _Env, class... _SenderIds>
+using __all_value_and_error_args_nothrow_decay_copyable =
+ __mand<__mand<value_types_of_t<__t<_SenderIds>, _Env,
+ __all_nothrow_decay_copyable, __mand>...>,
+ __mand<error_types_of_t<__t<_SenderIds>, _Env,
+ __all_nothrow_decay_copyable>...>>;
+
template <class _Env, class... _Senders>
-using __completions_t = __concat_completion_signatures_t<
- completion_signatures<set_error_t(std::exception_ptr&&), // TODO add this
- // only if the
- // copies can fail
- set_stopped_t()>,
- __minvoke<__with_default<__mbind_front_q<__set_values_sig_t, _Env>,
- completion_signatures<>>,
- _Senders...>,
- __make_completion_signatures<
- _Senders, _Env, completion_signatures<>,
- __mconst<completion_signatures<>>,
- __mcompose<__q<completion_signatures>, __qf<set_error_t>,
- __q<__decay_rvalue_ref>>>...>;
+using __completions_t = //
+ __concat_completion_signatures_t<
+ __if<__all_value_and_error_args_nothrow_decay_copyable<
+ _Env, __id<_Senders>...>,
+ completion_signatures<set_stopped_t()>,
+ completion_signatures<set_stopped_t(),
+ set_error_t(std::exception_ptr&&)>>,
+ __minvoke<__with_default<__mbind_front_q<__set_values_sig_t, _Env>,
+ completion_signatures<>>,
+ _Senders...>,
+ __make_completion_signatures<
+ _Senders, _Env, completion_signatures<>,
+ __mconst<completion_signatures<>>,
+ __mcompose<__q<completion_signatures>, __qf<set_error_t>,
+ __q<__decay_rvalue_ref>>>...>;
+
+struct __not_an_error
+{};
struct __tie_fn
{
@@ -5931,11 +6254,21 @@
struct __complete_fn
{
_Receiver& __rcvr_;
+
__complete_fn(_Tag, _Receiver& __rcvr) noexcept : __rcvr_(__rcvr) {}
- template <class... _Ts>
- void operator()(_Ts&... __ts) const noexcept
+
+ template <class _Ty, class... _Ts>
+ void operator()(_Ty& __t, _Ts&... __ts) const noexcept
{
- _Tag{}((_Receiver &&) __rcvr_, (_Ts &&) __ts...);
+ if constexpr (!same_as<_Ty, __not_an_error>)
+ {
+ _Tag{}((_Receiver &&) __rcvr_, (_Ty &&) __t, (_Ts &&) __ts...);
+ }
+ }
+
+ void operator()() const noexcept
+ {
+ _Tag{}((_Receiver &&) __rcvr_);
}
};
@@ -5978,7 +6311,12 @@
}
break;
case __error:
- std::visit(__complete_fn{set_error, __recvr_}, __errors_);
+ if constexpr (!same_as<_ErrorsVariant,
+ std::variant<std::monostate>>)
+ {
+ // One or more child operations completed with an error:
+ std::visit(__complete_fn{set_error, __recvr_}, __errors_);
+ }
break;
case __stopped:
stdexec::set_stopped((_Receiver &&) __recvr_);
@@ -6013,6 +6351,7 @@
struct __t
{
using __id = __receiver;
+
template <class _Error>
void __set_error(_Error&& __err) noexcept
{
@@ -6022,18 +6361,29 @@
__op_state_->__stop_source_.request_stop();
// We won the race, free to write the error into the operation
// state without worry.
- try
+ if constexpr (__nothrow_decay_copyable<_Error>)
{
- __op_state_->__errors_.template emplace<decay_t<_Error>>(
+ __op_state_->__errors_.template emplace<__decay_t<_Error>>(
(_Error &&) __err);
}
- catch (...)
+ else
{
- __op_state_->__errors_.template emplace<std::exception_ptr>(
- std::current_exception());
+ try
+ {
+ __op_state_->__errors_
+ .template emplace<__decay_t<_Error>>((_Error &&)
+ __err);
+ }
+ catch (...)
+ {
+ __op_state_->__errors_
+ .template emplace<std::exception_ptr>(
+ std::current_exception());
+ }
}
}
}
+
template <class... _Values>
requires same_as<_ValuesTuple, __ignore> ||
constructible_from<_TupleType, _Values...>
@@ -6043,29 +6393,38 @@
if constexpr (!same_as<_ValuesTuple, __ignore>)
{
static_assert(
- same_as<_TupleType, std::tuple<decay_t<_Values>...>>,
+ 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)
{
- try
+ if constexpr ((__nothrow_decay_copyable<_Values> && ...))
{
std::get<_Index>(__self.__op_state_->__values_)
.emplace((_Values &&) __vals...);
}
- catch (...)
+ else
{
- __self.__set_error(std::current_exception());
+ try
+ {
+ std::get<_Index>(__self.__op_state_->__values_)
+ .emplace((_Values &&) __vals...);
+ }
+ catch (...)
+ {
+ __self.__set_error(std::current_exception());
+ }
}
}
}
__self.__op_state_->__arrive();
}
+
template <class _Error>
requires requires(_ErrorsVariant& __errors, _Error&& __err) {
- __errors.template emplace<decay_t<_Error>>((_Error &&)
- __err);
+ __errors.template emplace<__decay_t<_Error>>(
+ (_Error &&) __err);
}
friend void tag_invoke(set_error_t, __t&& __self,
_Error&& __err) noexcept
@@ -6073,6 +6432,7 @@
__self.__set_error((_Error &&) __err);
__self.__op_state_->__arrive();
}
+
friend void tag_invoke(set_stopped_t, __t&& __self) noexcept
requires receiver_of<_Receiver,
completion_signatures<set_stopped_t()>>
@@ -6088,20 +6448,22 @@
}
__self.__op_state_->__arrive();
}
+
friend __env_t<env_of_t<_Receiver>> tag_invoke(get_env_t,
const __t& __self)
{
return {stdexec::get_env(__self.__op_state_->__recvr_),
__self.__op_state_->__stop_source_.get_token()};
}
+
__operation_base<_ReceiverId, _ValuesTuple, _ErrorsVariant>*
__op_state_;
};
};
template <class _Env, class _Sender>
-using __values_opt_tuple_t =
- __value_types_of_t<_Sender, __env_t<__id<_Env>>,
+using __values_opt_tuple_t = //
+ __value_types_of_t<_Sender, __env_t<_Env>,
__mcompose<__q<std::optional>, __q<__decayed_tuple>>,
__q<__msingle>>;
@@ -6111,15 +6473,26 @@
using __completions = __completions_t<__env_t<_Env>, _Senders...>;
// tuple<optional<tuple<Vs1...>>, optional<tuple<Vs2...>>, ...>
- using __values_tuple = __minvoke<
- __with_default<__transform<__mbind_front_q<__values_opt_tuple_t, _Env>,
- __q<std::tuple>>,
- __ignore>,
- _Senders...>;
+ using __values_tuple = //
+ __minvoke<__with_default<
+ __transform<__mbind_front_q<__values_opt_tuple_t, _Env>,
+ __q<std::tuple>>,
+ __ignore>,
+ _Senders...>;
- using __errors_variant =
- __minvoke<__mconcat<__q<__variant>>, __types<std::exception_ptr>,
- error_types_of_t<_Senders, __env_t<__id<_Env>>, __types>...>;
+ using __nullable_variant_t_ =
+ __munique<__mbind_front_q<std::variant, __not_an_error>>;
+
+ using __error_types = //
+ __minvoke<__mconcat<__transform<__q<__decay_t>, __nullable_variant_t_>>,
+ error_types_of_t<_Senders, __env_t<_Env>, __types>...>;
+
+ using __errors_variant = //
+ __if<__all_value_and_error_args_nothrow_decay_copyable<
+ _Env, __id<_Senders>...>,
+ __error_types,
+ __minvoke<__push_back_unique<__q<std::variant>>, __error_types,
+ std::exception_ptr>>;
};
template <receiver _Receiver,
@@ -6144,7 +6517,7 @@
using __op_state = connect_result_t<_Sender, __receiver<__v<_Index>>>;
template <class _Tuple = __q<std::tuple>>
- using __op_states_tuple =
+ using __op_states_tuple = //
__minvoke<__mzip_with2<__q<__op_state>, _Tuple>, __types<_Senders...>,
__mindex_sequence_for<_Senders...>>;
};
@@ -6187,6 +6560,7 @@
__receiver_t<_Is>{this});
}}...}
{}
+
template <class _SendersTuple>
__t(_SendersTuple&& __sndrs, _Receiver __rcvr) :
__t((_SendersTuple &&) __sndrs, (_Receiver &&) __rcvr, _Indices{})
@@ -6249,6 +6623,7 @@
struct __t
{
using __id = __sender;
+ using is_sender = void;
template <class... _Sndrs>
explicit(sizeof...(_Sndrs) == 1) __t(_Sndrs&&... __sndrs) :
@@ -6290,7 +6665,7 @@
{
template <class... _Senders>
using __sender_t = __t<__sender<std::index_sequence_for<_Senders...>,
- __id<decay_t<_Senders>>...>>;
+ __id<__decay_t<_Senders>>...>>;
template <sender... _Senders>
requires tag_invocable<when_all_t, _Senders...> &&
@@ -6389,6 +6764,7 @@
}
};
} // namespace __when_all
+
using __when_all::when_all_t;
inline constexpr when_all_t when_all{};
using __when_all::when_all_with_variant_t;
@@ -6405,19 +6781,23 @@
struct __operation
{
using _Receiver = stdexec::__t<_ReceiverId>;
+
struct __t : __immovable
{
using __id = __operation;
_Receiver __rcvr_;
+
friend void tag_invoke(start_t, __t& __self) noexcept
- try
{
- auto __env = get_env(__self.__rcvr_);
- set_value(std::move(__self.__rcvr_), _Tag{}(__env));
- }
- catch (...)
- {
- set_error(std::move(__self.__rcvr_), std::current_exception());
+ try
+ {
+ auto __env = get_env(__self.__rcvr_);
+ set_value(std::move(__self.__rcvr_), _Tag{}(__env));
+ }
+ catch (...)
+ {
+ set_error(std::move(__self.__rcvr_), std::current_exception());
+ }
}
};
};
@@ -6427,17 +6807,19 @@
{
using __t = __sender;
using __id = __sender;
+ using is_sender = void;
+
template <class _Env>
requires __callable<_Tag, _Env>
- using __completions_t =
+ using __completions_t = //
completion_signatures<set_value_t(__call_result_t<_Tag, _Env>),
set_error_t(std::exception_ptr)>;
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>>>
+ 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};
}
@@ -6473,14 +6855,17 @@
{
return read(get_scheduler);
}
+
inline auto get_delegatee_scheduler_t::operator()() const noexcept
{
return read(get_delegatee_scheduler);
}
+
inline auto get_allocator_t::operator()() const noexcept
{
return read(get_allocator);
}
+
inline auto get_stop_token_t::operator()() const noexcept
{
return read(get_stop_token);
@@ -6519,11 +6904,10 @@
// What should sync_wait(just_stopped()) return?
template <class _Sender, class _Continuation>
-using __sync_wait_result_impl =
- __value_types_of_t<_Sender, __env, __transform<__q<decay_t>, _Continuation>,
- __q<__msingle>>;
+using __sync_wait_result_impl = __value_types_of_t<
+ _Sender, __env, __transform<__q<__decay_t>, _Continuation>, __q<__msingle>>;
-template <stdexec::sender<__env> _Sender>
+template <stdexec::sender_in<__env> _Sender>
using __sync_wait_result_t = __sync_wait_result_impl<_Sender, __q<std::tuple>>;
template <class _Sender>
@@ -6546,6 +6930,7 @@
using __id = __receiver;
__state<_Values...>* __state_;
stdexec::run_loop* __loop_;
+
template <class _Error>
void __set_error(_Error __err) noexcept
{
@@ -6559,31 +6944,37 @@
std::make_exception_ptr((_Error &&) __err));
__loop_->finish();
}
+
template <class... _As>
requires constructible_from<std::tuple<_Values...>, _As...>
friend void tag_invoke(stdexec::set_value_t, __t&& __rcvr,
_As&&... __as) noexcept
- try
{
- __rcvr.__state_->__data_.template emplace<1>((_As &&) __as...);
- __rcvr.__loop_->finish();
+ try
+ {
+ __rcvr.__state_->__data_.template emplace<1>((_As &&) __as...);
+ __rcvr.__loop_->finish();
+ }
+ catch (...)
+ {
+ __rcvr.__set_error(std::current_exception());
+ }
}
- catch (...)
- {
- __rcvr.__set_error(std::current_exception());
- }
+
template <class _Error>
friend void tag_invoke(stdexec::set_error_t, __t&& __rcvr,
_Error __err) noexcept
{
__rcvr.__set_error((_Error &&) __err);
}
+
friend void tag_invoke(stdexec::set_stopped_t __d,
__t&& __rcvr) noexcept
{
__rcvr.__state_->__data_.template emplace<3>(__d);
__rcvr.__loop_->finish();
}
+
friend __env tag_invoke(stdexec::get_env_t, const __t& __rcvr) noexcept
{
return {__rcvr.__loop_->get_scheduler()};
@@ -6633,7 +7024,7 @@
requires(!__tag_invocable_with_completion_scheduler<
sync_wait_t, set_value_t, _Sender>) &&
(!tag_invocable<sync_wait_t, _Sender>) &&
- sender<_Sender, __env> &&
+ sender_in<_Sender, __env> &&
sender_to<_Sender, __receiver_t<_Sender>>
auto operator()(_Sender&& __sndr) const
-> std::optional<__sync_wait_result_t<_Sender>>
@@ -6665,7 +7056,7 @@
// [execution.senders.consumers.sync_wait_with_variant]
struct sync_wait_with_variant_t
{
- template <sender<__env> _Sender>
+ template <sender_in<__env> _Sender>
requires __tag_invocable_with_completion_scheduler<
sync_wait_with_variant_t, set_value_t, _Sender>
tag_invoke_result_t<sync_wait_with_variant_t,
@@ -6689,7 +7080,8 @@
return tag_invoke(sync_wait_with_variant_t{}, std::move(__sched),
(_Sender &&) __sndr);
}
- template <sender<__env> _Sender>
+
+ template <sender_in<__env> _Sender>
requires(!__tag_invocable_with_completion_scheduler<
sync_wait_with_variant_t, set_value_t, _Sender>) &&
tag_invocable<sync_wait_with_variant_t, _Sender>
@@ -6706,7 +7098,8 @@
return tag_invoke(sync_wait_with_variant_t{}, (_Sender &&) __sndr);
}
- template <sender<__env> _Sender>
+
+ template <sender_in<__env> _Sender>
requires(!__tag_invocable_with_completion_scheduler<
sync_wait_with_variant_t, set_value_t, _Sender>) &&
(!tag_invocable<sync_wait_with_variant_t, _Sender>) &&
@@ -6718,10 +7111,12 @@
}
};
} // namespace __sync_wait
+
using __sync_wait::sync_wait_t;
inline constexpr sync_wait_t sync_wait{};
using __sync_wait::sync_wait_with_variant_t;
inline constexpr sync_wait_with_variant_t sync_wait_with_variant{};
+
} // namespace stdexec
#include "__detail/__p2300.hpp"
diff --git a/include/sdbusplus/async/stdexec/functional.hpp b/include/sdbusplus/async/stdexec/functional.hpp
index c023f47..0a6a603 100644
--- a/include/sdbusplus/async/stdexec/functional.hpp
+++ b/include/sdbusplus/async/stdexec/functional.hpp
@@ -29,10 +29,11 @@
#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
using std::invocable;
#else
-template <class _F, class... _As>
-concept invocable = requires(_F&& __f, _As&&... __as) {
- std::invoke((_F &&) __f, (_As &&) __as...);
- };
+template <class _Fun, class... _As>
+concept invocable = //
+ requires(_Fun&& __f, _As&&... __as) {
+ std::invoke((_Fun &&) __f, (_As &&) __as...);
+ };
#endif
} // namespace stdexec::__std_concepts
@@ -43,18 +44,20 @@
namespace stdexec
{
-template <class _F, class... _As>
-concept __nothrow_invocable = invocable<_F, _As...> &&
- requires(_F&& __f, _As&&... __as) {
- {
- std::invoke((_F &&) __f, (_As &&) __as...)
- } noexcept;
- };
+template <class _Fun, class... _As>
+concept __nothrow_invocable = //
+ invocable<_Fun, _As...> && //
+ requires(_Fun&& __f, _As&&... __as) {
+ {
+ std::invoke((_Fun &&) __f, (_As &&) __as...)
+ } noexcept;
+ };
template <auto _Fun>
struct __fun_c_t
{
using _FunT = decltype(_Fun);
+
template <class... _Args>
requires __callable<_FunT, _Args...>
auto operator()(_Args&&... __args) const
@@ -64,6 +67,7 @@
return _Fun((_Args &&) __args...);
}
};
+
template <auto _Fun>
inline constexpr __fun_c_t<_Fun> __fun_c{};
@@ -76,14 +80,23 @@
// std::invoke is more expensive at compile time than necessary,
// and results in diagnostics that are more verbose than necessary.
template <class _Tag, class... _Args>
-concept tag_invocable = requires(_Tag __tag, _Args&&... __args) {
- tag_invoke((_Tag &&) __tag, (_Args &&) __args...);
- };
+concept tag_invocable = //
+ requires(_Tag __tag, _Args&&... __args) {
+ tag_invoke((_Tag &&) __tag, (_Args &&) __args...);
+ };
+
+template <class _Ret, class _Tag, class... _Args>
+concept __tag_invocable_r = //
+ requires(_Tag __tag, _Args&&... __args) {
+ {
+ static_cast<_Ret>(tag_invoke((_Tag &&) __tag, (_Args &&) __args...))
+ };
+ };
// NOT TO SPEC: nothrow_tag_invocable subsumes tag_invocable
template <class _Tag, class... _Args>
concept nothrow_tag_invocable =
- tag_invocable<_Tag, _Args...> &&
+ tag_invocable<_Tag, _Args...> && //
requires(_Tag __tag, _Args&&... __args) {
{
tag_invoke((_Tag &&) __tag, (_Args &&) __args...)
@@ -124,8 +137,9 @@
inline constexpr tag_invoke_t tag_invoke{};
template <auto& _Tag>
-using tag_t = decay_t<decltype(_Tag)>;
+using tag_t = __decay_t<decltype(_Tag)>;
+using __tag_invoke::__tag_invocable_r;
using __tag_invoke::nothrow_tag_invocable;
using __tag_invoke::tag_invocable;
using __tag_invoke::tag_invoke_result;
diff --git a/include/sdbusplus/async/stdexec/import b/include/sdbusplus/async/stdexec/import
index 01c0705..7fbd6c2 100755
--- a/include/sdbusplus/async/stdexec/import
+++ b/include/sdbusplus/async/stdexec/import
@@ -4,7 +4,7 @@
git -C "${execution_dir}" rev-parse HEAD > commit.info
cp -r "${execution_dir}"/include/stdexec/* .
-cp "${execution_dir}"/include/exec/{scope,task}.hpp .
+cp "${execution_dir}"/include/exec/{any_sender_of,at_coroutine_exit,inline_scheduler,scope,task}.hpp .
(find . -name "*.hpp" -print0 || true) | while IFS= read -r -d '' f
do
diff --git a/include/sdbusplus/async/stdexec/inline_scheduler.hpp b/include/sdbusplus/async/stdexec/inline_scheduler.hpp
new file mode 100644
index 0000000..ec7ca3c
--- /dev/null
+++ b/include/sdbusplus/async/stdexec/inline_scheduler.hpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "../stdexec/execution.hpp"
+
+#include <exception>
+#include <type_traits>
+
+namespace exec
+{
+// A simple scheduler that executes its continuation inline, on the
+// thread of the caller of start().
+struct inline_scheduler
+{
+ template <class R_>
+ struct __op
+ {
+ using R = stdexec::__t<R_>;
+ [[no_unique_address]] R rec_;
+
+ friend void tag_invoke(stdexec::start_t, __op& op) noexcept
+ {
+ stdexec::set_value((R &&) op.rec_);
+ }
+ };
+
+ struct __sender
+ {
+ using is_sender = void;
+ using completion_signatures =
+ stdexec::completion_signatures<stdexec::set_value_t()>;
+
+ template <class R>
+ friend auto tag_invoke(stdexec::connect_t, __sender, R&& rec) //
+ noexcept(
+ stdexec::__nothrow_constructible_from<stdexec::__decay_t<R>, R>)
+ -> __op<stdexec::__x<stdexec::__decay_t<R>>>
+ {
+ return {(R &&) rec};
+ }
+
+ struct __env
+ {
+ friend inline_scheduler tag_invoke(
+ stdexec::get_completion_scheduler_t<stdexec::set_value_t>,
+ const __env&) //
+ noexcept
+ {
+ return {};
+ }
+ };
+
+ friend __env tag_invoke(stdexec::get_env_t, const __sender&) noexcept
+ {
+ return {};
+ }
+ };
+
+ friend __sender tag_invoke(stdexec::schedule_t,
+ const inline_scheduler&) noexcept
+ {
+ return {};
+ }
+
+ friend stdexec::forward_progress_guarantee
+ tag_invoke(stdexec::get_forward_progress_guarantee_t,
+ const inline_scheduler&) noexcept
+ {
+ return stdexec::forward_progress_guarantee::weakly_parallel;
+ }
+
+ bool operator==(const inline_scheduler&) const noexcept = default;
+};
+} // namespace exec
diff --git a/include/sdbusplus/async/stdexec/scope.hpp b/include/sdbusplus/async/stdexec/scope.hpp
index 57215a2..5b86305 100644
--- a/include/sdbusplus/async/stdexec/scope.hpp
+++ b/include/sdbusplus/async/stdexec/scope.hpp
@@ -15,29 +15,23 @@
*/
#pragma once
-#include "../stdexec/__detail/__meta.hpp"
+#include "../stdexec/__detail/__scope.hpp"
namespace exec
{
-template <stdexec::__nothrow_callable _Fn>
+
+template <class _Fn, class... _Ts>
+ requires stdexec::__nothrow_callable<_Fn, _Ts...>
struct scope_guard
{
- [[no_unique_address]] _Fn __fn_;
- [[no_unique_address]] stdexec::__immovable __hidden_{};
- bool __dismissed_{false};
-
- ~scope_guard()
- {
- if (!__dismissed_)
- ((_Fn &&) __fn_)();
- }
+ stdexec::__scope_guard<_Fn, _Ts...> __guard_;
void dismiss() noexcept
{
- __dismissed_ = true;
+ __guard_.__dismiss();
}
};
+template <class _Fn, class... _Ts>
+scope_guard(_Fn, _Ts...) -> scope_guard<_Fn, _Ts...>;
-template <stdexec::__nothrow_callable _Fn>
-scope_guard(_Fn) -> scope_guard<_Fn>;
} // namespace exec
diff --git a/include/sdbusplus/async/stdexec/stop_token.hpp b/include/sdbusplus/async/stdexec/stop_token.hpp
index 6fd2719..a518051 100644
--- a/include/sdbusplus/async/stdexec/stop_token.hpp
+++ b/include/sdbusplus/async/stdexec/stop_token.hpp
@@ -53,8 +53,10 @@
protected:
using __execute_fn_t = void(__in_place_stop_callback_base*) noexcept;
- explicit __in_place_stop_callback_base(const in_place_stop_source* __source,
- __execute_fn_t* __execute) noexcept :
+
+ explicit __in_place_stop_callback_base( //
+ const in_place_stop_source* __source, //
+ __execute_fn_t* __execute) noexcept :
__source_(__source),
__execute_(__execute)
{}
@@ -110,14 +112,17 @@
public:
template <class>
using callback_type = __callback_type;
+
static constexpr bool stop_requested() noexcept
{
return false;
}
+
static constexpr bool stop_possible() noexcept
{
return false;
}
+
bool operator==(const never_stop_token&) const noexcept = default;
};
@@ -135,6 +140,7 @@
in_place_stop_token get_token() const noexcept;
bool request_stop() noexcept;
+
bool stop_requested() const noexcept
{
return (__state_.load(std::memory_order_acquire) &
@@ -232,9 +238,9 @@
public:
template <class _Fun2>
requires constructible_from<_Fun, _Fun2>
- explicit in_place_stop_callback(
- in_place_stop_token __token,
- _Fun2&& __fun) noexcept(std::is_nothrow_constructible_v<_Fun, _Fun2>) :
+ explicit in_place_stop_callback(in_place_stop_token __token,
+ _Fun2&& __fun) //
+ noexcept(__nothrow_constructible_from<_Fun, _Fun2>) :
__stok::__in_place_stop_callback_base(
__token.__source_, &in_place_stop_callback::__execute_impl_),
__fun_((_Fun2 &&) __fun)
@@ -442,11 +448,11 @@
}
template <class _Token>
-concept stoppable_token = copy_constructible<_Token> &&
- move_constructible<_Token> &&
- std::is_nothrow_copy_constructible_v<_Token> &&
- std::is_nothrow_move_constructible_v<_Token> &&
- equality_comparable<_Token> &&
+concept stoppable_token = copy_constructible<_Token> && //
+ move_constructible<_Token> && //
+ std::is_nothrow_copy_constructible_v<_Token> && //
+ std::is_nothrow_move_constructible_v<_Token> && //
+ equality_comparable<_Token> && //
requires(const _Token& __token) {
{
__token.stop_requested()
@@ -463,23 +469,28 @@
template <class _Token, typename _Callback, typename _Initializer = _Callback>
concept stoppable_token_for =
- stoppable_token<_Token> && __callable<_Callback> &&
- requires { typename _Token::template callback_type<_Callback>; } &&
- constructible_from<_Callback, _Initializer> &&
- constructible_from<typename _Token::template callback_type<_Callback>,
- _Token, _Initializer> &&
- constructible_from<typename _Token::template callback_type<_Callback>,
- _Token&, _Initializer> &&
- constructible_from<typename _Token::template callback_type<_Callback>,
- const _Token, _Initializer> &&
+ stoppable_token<_Token> && __callable<_Callback> && //
+ requires { typename _Token::template callback_type<_Callback>; } && //
+ constructible_from<_Callback, _Initializer> && //
+ constructible_from< //
+ typename _Token::template callback_type<_Callback>, _Token,
+ _Initializer> && //
+ constructible_from< //
+ typename _Token::template callback_type<_Callback>, _Token&,
+ _Initializer> && //
+ constructible_from< //
+ typename _Token::template callback_type<_Callback>, const _Token,
+ _Initializer> && //
constructible_from<typename _Token::template callback_type<_Callback>,
const _Token&, _Initializer>;
template <class _Token>
-concept unstoppable_token = stoppable_token<_Token> &&
- requires {
- {
- _Token::stop_possible()
- } -> __boolean_testable_;
- } && (!_Token::stop_possible());
+concept unstoppable_token = //
+ stoppable_token<_Token> && //
+ requires {
+ {
+ _Token::stop_possible()
+ } -> __boolean_testable_;
+ } && //
+ (!_Token::stop_possible());
} // namespace stdexec
diff --git a/include/sdbusplus/async/stdexec/task.hpp b/include/sdbusplus/async/stdexec/task.hpp
index a5066cd..a3d84eb 100644
--- a/include/sdbusplus/async/stdexec/task.hpp
+++ b/include/sdbusplus/async/stdexec/task.hpp
@@ -18,6 +18,9 @@
#include "../stdexec/__detail/__meta.hpp"
#include "../stdexec/coroutine.hpp"
#include "../stdexec/execution.hpp"
+#include "any_sender_of.hpp"
+#include "at_coroutine_exit.hpp"
+#include "inline_scheduler.hpp"
#include "scope.hpp"
#include <any>
@@ -33,20 +36,48 @@
{
namespace __task
{
-template <class _Ty>
-concept __stop_token_provider =
- requires(const _Ty& t) { stdexec::get_stop_token(t); };
+using namespace stdexec;
+
+using __any_scheduler = //
+ any_receiver_ref< //
+ completion_signatures<set_error_t(std::exception_ptr),
+ set_stopped_t()> //
+ >::any_sender<>::any_scheduler<>;
template <class _Ty>
-concept __indirect_stop_token_provider = requires(const _Ty& t) {
- {
- stdexec::get_env(t)
- } -> __stop_token_provider;
- };
+concept __stop_token_provider = //
+ requires(const _Ty& t) { //
+ get_stop_token(t);
+ };
+
+template <class _Ty>
+concept __indirect_stop_token_provider = //
+ requires(const _Ty& t) {
+ {
+ get_env(t)
+ } -> __stop_token_provider;
+ };
+
+template <class _Ty>
+concept __indirect_scheduler_provider = //
+ requires(const _Ty& t) {
+ {
+ get_env(t)
+ } -> __scheduler_provider;
+ };
+
+template <class _ParentPromise>
+void __check_parent_promise_has_scheduler() noexcept
+{
+ static_assert(__indirect_scheduler_provider<_ParentPromise>,
+ "exec::task<T> cannot be co_await-ed in a coroutine that "
+ "does not have an associated scheduler.");
+}
struct __forward_stop_request
{
- stdexec::in_place_stop_source& __stop_source_;
+ in_place_stop_source& __stop_source_;
+
void operator()() noexcept
{
__stop_source_.request_stop();
@@ -59,16 +90,37 @@
////////////////////////////////////////////////////////////////////////////////
// This is the context that is associated with basic_task's promise type
// by default. It handles forwarding of stop requests from parent to child.
+enum class __scheduler_affinity
+{
+ __none,
+ __sticky
+};
+
+template <__scheduler_affinity _SchedulerAffinity =
+ __scheduler_affinity::__sticky>
class __default_task_context_impl
{
template <class _ParentPromise>
friend struct __default_awaiter_context;
- stdexec::in_place_stop_token __stop_token_;
+ static constexpr bool __with_scheduler = _SchedulerAffinity ==
+ __scheduler_affinity::__sticky;
- friend auto tag_invoke(stdexec::get_stop_token_t,
+ [[no_unique_address]] __if_c<__with_scheduler, __any_scheduler, __ignore> //
+ __scheduler_{exec::inline_scheduler{}};
+ in_place_stop_token __stop_token_;
+
+ friend const __any_scheduler&
+ tag_invoke(get_scheduler_t,
+ const __default_task_context_impl& __self) noexcept
+ requires(__with_scheduler)
+ {
+ return __self.__scheduler_;
+ }
+
+ friend auto tag_invoke(get_stop_token_t,
const __default_task_context_impl& __self) noexcept
- -> stdexec::in_place_stop_token
+ -> in_place_stop_token
{
return __self.__stop_token_;
}
@@ -76,11 +128,23 @@
public:
__default_task_context_impl() = default;
+ template <scheduler _Scheduler>
+ explicit __default_task_context_impl(_Scheduler&& __scheduler) :
+ __scheduler_{(_Scheduler &&) __scheduler}
+ {}
+
bool stop_requested() const noexcept
{
return __stop_token_.stop_requested();
}
+ template <scheduler _Scheduler>
+ void set_scheduler(_Scheduler&& __sched)
+ requires(__with_scheduler)
+ {
+ __scheduler_ = (_Scheduler &&) __sched;
+ }
+
template <class _ThisPromise>
using promise_context_t = __default_task_context_impl;
@@ -89,16 +153,29 @@
};
template <class _Ty>
-using default_task_context = __default_task_context_impl;
+using default_task_context =
+ __default_task_context_impl<__scheduler_affinity::__sticky>;
+
+template <class _Ty>
+using __raw_task_context =
+ __default_task_context_impl<__scheduler_affinity::__none>;
// This is the context associated with basic_task's awaiter. By default
// it does nothing.
template <class _ParentPromise>
struct __default_awaiter_context
{
- explicit __default_awaiter_context(__default_task_context_impl&,
- _ParentPromise&) noexcept
- {}
+ template <__scheduler_affinity _Affinity>
+ explicit __default_awaiter_context(
+ __default_task_context_impl<_Affinity>& __self,
+ _ParentPromise& __parent) noexcept
+ {
+ if constexpr (_Affinity == __scheduler_affinity::__sticky)
+ {
+ __check_parent_promise_has_scheduler<_ParentPromise>();
+ __self.__scheduler_ = get_scheduler(get_env(__parent));
+ }
+ }
};
////////////////////////////////////////////////////////////////////////////////
@@ -108,56 +185,74 @@
template <__indirect_stop_token_provider _ParentPromise>
struct __default_awaiter_context<_ParentPromise>
{
- using __stop_token_t =
- stdexec::stop_token_of_t<stdexec::env_of_t<_ParentPromise>>;
+ using __stop_token_t = stop_token_of_t<env_of_t<_ParentPromise>>;
using __stop_callback_t =
typename __stop_token_t::template callback_type<__forward_stop_request>;
- explicit __default_awaiter_context(__default_task_context_impl& __self,
- _ParentPromise& __parent) noexcept
+ template <__scheduler_affinity _Affinity>
+ explicit __default_awaiter_context(
+ __default_task_context_impl<_Affinity>& __self,
+ _ParentPromise& __parent) noexcept
// Register a callback that will request stop on this basic_task's
// stop_source when stop is requested on the parent coroutine's stop
// token.
:
- __stop_callback_{stdexec::get_stop_token(stdexec::get_env(__parent)),
+ __stop_callback_{get_stop_token(get_env(__parent)),
__forward_stop_request{__stop_source_}}
{
+ if constexpr (_Affinity == __scheduler_affinity::__sticky)
+ {
+ __check_parent_promise_has_scheduler<_ParentPromise>();
+ __self.__scheduler_ = get_scheduler(get_env(__parent));
+ }
static_assert(
std::is_nothrow_constructible_v<__stop_callback_t, __stop_token_t,
__forward_stop_request>);
__self.__stop_token_ = __stop_source_.get_token();
}
- stdexec::in_place_stop_source __stop_source_{};
+ in_place_stop_source __stop_source_{};
__stop_callback_t __stop_callback_;
};
// If the parent coroutine's type has a stop token of type in_place_stop_token,
// we don't need to register a stop callback.
template <__indirect_stop_token_provider _ParentPromise>
- requires std::same_as<
- stdexec::in_place_stop_token,
- stdexec::stop_token_of_t<stdexec::env_of_t<_ParentPromise>>>
+ requires std::same_as<in_place_stop_token,
+ stop_token_of_t<env_of_t<_ParentPromise>>>
struct __default_awaiter_context<_ParentPromise>
{
- explicit __default_awaiter_context(__default_task_context_impl& __self,
- _ParentPromise& __parent) noexcept
+ template <__scheduler_affinity _Affinity>
+ explicit __default_awaiter_context(
+ __default_task_context_impl<_Affinity>& __self,
+ _ParentPromise& __parent) noexcept
{
- __self.__stop_token_ =
- stdexec::get_stop_token(stdexec::get_env(__parent));
+ if constexpr (_Affinity == __scheduler_affinity::__sticky)
+ {
+ __check_parent_promise_has_scheduler<_ParentPromise>();
+ __self.__scheduler_ = get_scheduler(get_env(__parent));
+ }
+ __self.__stop_token_ = get_stop_token(get_env(__parent));
}
};
// If the parent coroutine's stop token is unstoppable, there's no point
// forwarding stop tokens or stop requests at all.
template <__indirect_stop_token_provider _ParentPromise>
- requires stdexec::unstoppable_token<
- stdexec::stop_token_of_t<stdexec::env_of_t<_ParentPromise>>>
+ requires unstoppable_token<stop_token_of_t<env_of_t<_ParentPromise>>>
struct __default_awaiter_context<_ParentPromise>
{
- explicit __default_awaiter_context(__default_task_context_impl&,
- _ParentPromise&) noexcept
- {}
+ template <__scheduler_affinity _Affinity>
+ explicit __default_awaiter_context(
+ __default_task_context_impl<_Affinity>& __self,
+ _ParentPromise& __parent) noexcept
+ {
+ if constexpr (_Affinity == __scheduler_affinity::__sticky)
+ {
+ __check_parent_promise_has_scheduler<_ParentPromise>();
+ __self.__scheduler_ = get_scheduler(get_env(__parent));
+ }
+ }
};
// Finally, if we don't know the parent coroutine's promise type, assume the
@@ -165,32 +260,42 @@
template <>
struct __default_awaiter_context<void>
{
- template <class _Ty>
- explicit __default_awaiter_context(__default_task_context_impl&,
- _Ty&) noexcept
- {}
-
- template <__indirect_stop_token_provider _ParentPromise>
- explicit __default_awaiter_context(__default_task_context_impl& __self,
- _ParentPromise& __parent)
+ template <__scheduler_affinity _Affinity, class _ParentPromise>
+ explicit __default_awaiter_context(
+ __default_task_context_impl<_Affinity>& __self,
+ _ParentPromise& __parent) noexcept
{
+ if constexpr (_Affinity == __scheduler_affinity::__sticky)
+ {
+ __check_parent_promise_has_scheduler<_ParentPromise>();
+ __self.__scheduler_ = get_scheduler(get_env(__parent));
+ }
+ }
+
+ template <__scheduler_affinity _Affinity,
+ __indirect_stop_token_provider _ParentPromise>
+ explicit __default_awaiter_context(
+ __default_task_context_impl<_Affinity>& __self,
+ _ParentPromise& __parent)
+ {
+ if constexpr (_Affinity == __scheduler_affinity::__sticky)
+ {
+ __check_parent_promise_has_scheduler<_ParentPromise>();
+ __self.__scheduler_ = get_scheduler(get_env(__parent));
+ }
// Register a callback that will request stop on this basic_task's
// stop_source when stop is requested on the parent coroutine's stop
// token.
- using __stop_token_t =
- stdexec::stop_token_of_t<stdexec::env_of_t<_ParentPromise>>;
+ using __stop_token_t = stop_token_of_t<env_of_t<_ParentPromise>>;
using __stop_callback_t =
typename __stop_token_t::template callback_type<
__forward_stop_request>;
- if constexpr (std::same_as<__stop_token_t,
- stdexec::in_place_stop_token>)
+ if constexpr (std::same_as<__stop_token_t, in_place_stop_token>)
{
- __self.__stop_token_ =
- stdexec::get_stop_token(stdexec::get_env(__parent));
+ __self.__stop_token_ = get_stop_token(get_env(__parent));
}
- else if (auto __token =
- stdexec::get_stop_token(stdexec::get_env(__parent));
+ else if (auto __token = get_stop_token(get_env(__parent));
__token.stop_possible())
{
__stop_callback_.emplace<__stop_callback_t>(
@@ -199,13 +304,14 @@
}
}
- stdexec::in_place_stop_source __stop_source_{};
+ in_place_stop_source __stop_source_{};
std::any __stop_callback_{};
};
template <class _Promise, class _ParentPromise = void>
-using awaiter_context_t = typename stdexec::env_of_t<
- _Promise>::template awaiter_context_t<_Promise, _ParentPromise>;
+using awaiter_context_t = //
+ typename __decay_t<env_of_t<_Promise>> //
+ ::template awaiter_context_t<_Promise, _ParentPromise>;
////////////////////////////////////////////////////////////////////////////////
// In a base class so it can be specialized when _Ty is void:
@@ -216,6 +322,7 @@
{
__data_.template emplace<1>(std::move(value));
}
+
std::variant<std::monostate, _Ty, std::exception_ptr> __data_{};
};
@@ -224,13 +331,37 @@
{
struct __void
{};
+
void return_void() noexcept
{
__data_.template emplace<1>(__void{});
}
+
std::variant<std::monostate, __void, std::exception_ptr> __data_{};
};
+enum class disposition : unsigned
+{
+ stopped,
+ succeeded,
+ failed,
+};
+
+struct __reschedule_coroutine_on
+{
+ template <class _Scheduler>
+ struct __wrap
+ {
+ _Scheduler __sched_;
+ };
+
+ template <scheduler _Scheduler>
+ __wrap<_Scheduler> operator()(_Scheduler __sched) const noexcept
+ {
+ return {(_Scheduler &&) __sched};
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
// basic_task
template <class _Ty, class _Context = default_task_context<_Ty>>
@@ -260,43 +391,97 @@
{
return {};
}
+
static __coro::coroutine_handle<>
await_suspend(__coro::coroutine_handle<__promise> __h) noexcept
{
return __h.promise().continuation().handle();
}
+
static void await_resume() noexcept {}
};
- struct __promise :
- __promise_base<_Ty>,
- stdexec::with_awaitable_senders<__promise>
+ struct __promise : __promise_base<_Ty>, with_awaitable_senders<__promise>
{
basic_task get_return_object() noexcept
{
return basic_task(
__coro::coroutine_handle<__promise>::from_promise(*this));
}
+
__coro::suspend_always initial_suspend() noexcept
{
return {};
}
+
__final_awaitable final_suspend() noexcept
{
return {};
}
+
+ __task::disposition disposition() const noexcept
+ {
+ return static_cast<__task::disposition>(this->__data_.index());
+ }
+
void unhandled_exception() noexcept
{
this->__data_.template emplace<2>(std::current_exception());
}
+
+ template <sender _Awaitable>
+ requires __scheduler_provider<_Context> decltype(auto)
+ await_transform(_Awaitable&& __awaitable) noexcept
+ {
+ // TODO: If we have a complete-where-it-starts query then we can
+ // optimize this to avoid the reschedule
+ return as_awaitable(transfer((_Awaitable &&) __awaitable,
+ get_scheduler(__context_)),
+ *this);
+ }
+
+ template <class _Scheduler>
+ requires __scheduler_provider<_Context> decltype(auto)
+ await_transform(
+ __reschedule_coroutine_on::__wrap<_Scheduler> __box) noexcept
+ {
+ if (!std::exchange(__rescheduled_, true))
+ {
+ // Create a cleanup action that transitions back onto the
+ // current scheduler:
+ auto __sched = get_scheduler(__context_);
+ auto __cleanup_task = at_coroutine_exit(schedule,
+ std::move(__sched));
+ // Insert the cleanup action into the head of the continuation
+ // chain by making direct calls to the cleanup task's awaiter
+ // member functions. See type _cleanup_task in
+ // at_coroutine_exit.hpp:
+ __cleanup_task.await_suspend(
+ __coro::coroutine_handle<__promise>::from_promise(*this));
+ (void)__cleanup_task.await_resume();
+ }
+ __context_.set_scheduler(__box.__sched_);
+ return as_awaitable(schedule(__box.__sched_), *this);
+ }
+
+ template <class _Awaitable>
+ decltype(auto) await_transform(_Awaitable&& __awaitable) noexcept
+ {
+ return with_awaitable_senders<__promise>::await_transform(
+ (_Awaitable &&) __awaitable);
+ }
+
using __context_t =
typename _Context::template promise_context_t<__promise>;
- friend __context_t tag_invoke(stdexec::get_env_t,
- const __promise& __self)
+
+ friend const __context_t& tag_invoke(get_env_t,
+ const __promise& __self) noexcept
{
return __self.__context_;
}
+
__context_t __context_;
+ bool __rescheduled_{false};
};
template <class _ParentPromise = void>
@@ -316,15 +501,15 @@
{
return {};
}
- template <class ParentPromise2>
+
+ template <class _ParentPromise2>
__coro::coroutine_handle<> await_suspend(
- __coro::coroutine_handle<ParentPromise2> __parent) noexcept
+ __coro::coroutine_handle<_ParentPromise2> __parent) noexcept
{
- static_assert(
- stdexec::__one_of<_ParentPromise, ParentPromise2, void>);
- __coro_.promise().set_continuation(__parent);
+ static_assert(__one_of<_ParentPromise, _ParentPromise2, void>);
__context_.emplace(__coro_.promise().__context_,
__parent.promise());
+ __coro_.promise().set_continuation(__parent);
if constexpr (requires {
__coro_.promise().stop_requested() ? 0 : 1;
})
@@ -334,6 +519,7 @@
}
return __coro_;
}
+
_Ty await_resume()
{
__context_.reset();
@@ -349,10 +535,10 @@
// Make this task awaitable within a particular context:
template <class _ParentPromise>
- requires stdexec::constructible_from<
+ requires constructible_from<
awaiter_context_t<__promise, _ParentPromise>, __promise&,
_ParentPromise&>
- friend __task_awaitable<_ParentPromise> tag_invoke(stdexec::as_awaitable_t,
+ friend __task_awaitable<_ParentPromise> tag_invoke(as_awaitable_t,
basic_task&& __self,
_ParentPromise&) noexcept
{
@@ -362,7 +548,7 @@
// Make this task generally awaitable:
friend __task_awaitable<> operator co_await(basic_task&& __self) noexcept
- requires stdexec::__valid<awaiter_context_t, __promise>
+ requires __valid<awaiter_context_t, __promise>
{
return __task_awaitable<>{std::exchange(__self.__coro_, {})};
}
@@ -371,19 +557,17 @@
// the resulting list to __qf<set_value_t>, which uses the list of types
// as arguments of a function type. In other words, set_value_t() if _Ty
// is void, and set_value_t(_Ty) otherwise.
- using __set_value_sig_t = stdexec::__minvoke<
- stdexec::__remove<void, stdexec::__qf<stdexec::set_value_t>>, _Ty>;
+ using __set_value_sig_t = __minvoke<__remove<void, __qf<set_value_t>>, _Ty>;
// Specify basic_task's completion signatures
// This is only necessary when basic_task is not generally awaitable
// owing to constraints imposed by its _Context parameter.
- using __task_traits_t =
- stdexec::completion_signatures<__set_value_sig_t,
- stdexec::set_error_t(std::exception_ptr),
- stdexec::set_stopped_t()>;
+ using __task_traits_t = //
+ completion_signatures<__set_value_sig_t,
+ set_error_t(std::exception_ptr), set_stopped_t()>;
- friend auto tag_invoke(stdexec::get_completion_signatures_t,
- const basic_task&, auto) -> __task_traits_t;
+ friend auto tag_invoke(get_completion_signatures_t, const basic_task&, auto)
+ -> __task_traits_t;
explicit basic_task(__coro::coroutine_handle<promise_type> __coro) noexcept
:
@@ -394,6 +578,8 @@
};
} // namespace __task
+using task_disposition = __task::disposition;
+
template <class _Ty>
using default_task_context = __task::default_task_context<_Ty>;
@@ -405,6 +591,8 @@
template <class _Ty>
using task = basic_task<_Ty, default_task_context<_Ty>>;
+
+inline constexpr __task::__reschedule_coroutine_on reschedule_coroutine_on{};
} // namespace exec
STDEXEC_PRAGMA_POP()