stdexec: update to latest commit
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: Idaa873100bd02f06455b0eb5a00ca62f93b08acc
diff --git a/include/sdbusplus/async/stdexec/__detail/__config.hpp b/include/sdbusplus/async/stdexec/__detail/__config.hpp
index 142bf16..5be8786 100644
--- a/include/sdbusplus/async/stdexec/__detail/__config.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__config.hpp
@@ -67,6 +67,12 @@
#define STDEXEC_MSVC() 0
#endif
+#if STDEXEC_CLANG() && defined(__CUDACC__)
+#define STDEXEC_DETAIL_CUDACC_HOST_DEVICE __host__ __device__
+#else
+#define STDEXEC_DETAIL_CUDACC_HOST_DEVICE
+#endif
+
#ifdef STDEXEC_ASSERT
#error \
"Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead."
diff --git a/include/sdbusplus/async/stdexec/__detail/__intrusive_queue.hpp b/include/sdbusplus/async/stdexec/__detail/__intrusive_queue.hpp
index 1693cdc..edd0e88 100644
--- a/include/sdbusplus/async/stdexec/__detail/__intrusive_queue.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__intrusive_queue.hpp
@@ -79,7 +79,10 @@
{
STDEXEC_ASSERT(!empty());
_Item* __item = std::exchange(__head_, __head_->*_Next);
- if (__head_ == nullptr)
+ // This should test if __head_ == nullptr, but due to a bug in
+ // nvc++'s optimization, `__head_` isn't assigned until later.
+ // Filed as NVBug#3952534.
+ if (__item->*_Next == nullptr)
{
__tail_ = nullptr;
}
diff --git a/include/sdbusplus/async/stdexec/__detail/__meta.hpp b/include/sdbusplus/async/stdexec/__detail/__meta.hpp
index 1977521..3d0cd50 100644
--- a/include/sdbusplus/async/stdexec/__detail/__meta.hpp
+++ b/include/sdbusplus/async/stdexec/__detail/__meta.hpp
@@ -499,13 +499,20 @@
using __x = __t<_X<_Ty>>;
template <class _Ty>
+concept __has_id = requires { typename _Ty::__id; };
+
+template <class _Ty>
struct _Y
{
using __t = _Ty;
-};
-template <class _Ty>
-concept __has_id = requires { typename _Ty::__id; };
+ // Uncomment the line below to find any code that likely misuses the
+ // ADL isolation mechanism. In particular, '__id<T>' when T is a
+ // reference is a likely misuse. The static_assert below will trigger
+ // when the type passed to the __id alias template is a reference to
+ // a type that is setup to use ADL isolation.
+ // static_assert(!__has_id<std::remove_cvref_t<_Ty>>);
+};
template <bool = true>
struct __id_
{
@@ -521,6 +528,12 @@
template <class _Ty>
using __id = __minvoke<__id_<__has_id<_Ty>>, _Ty>;
+template <class _Ty>
+using __cvref_t = __copy_cvref_t<_Ty, __t<std::remove_cvref_t<_Ty>>>;
+
+template <class _From, class _To>
+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...);
diff --git a/include/sdbusplus/async/stdexec/commit.info b/include/sdbusplus/async/stdexec/commit.info
index 9fe5b5f..a7276cd 100644
--- a/include/sdbusplus/async/stdexec/commit.info
+++ b/include/sdbusplus/async/stdexec/commit.info
@@ -1 +1 @@
-218931e835b0313c67be469adb721df8c43eb684
+268b9d858c0a0e63af4806c3065dc096319375d6
diff --git a/include/sdbusplus/async/stdexec/coroutine.hpp b/include/sdbusplus/async/stdexec/coroutine.hpp
index 52840af..597355a 100644
--- a/include/sdbusplus/async/stdexec/coroutine.hpp
+++ b/include/sdbusplus/async/stdexec/coroutine.hpp
@@ -31,28 +31,25 @@
namespace stdexec
{
#if !_STD_NO_COROUTINES_
-// Defined some concepts and utilities for working with awaitables
-template <class _Promise, class _Awaiter>
-decltype(auto) __await_suspend(_Awaiter& __await)
-{
- if constexpr (!same_as<_Promise, void>)
- {
- return __await.await_suspend(__coro::coroutine_handle<_Promise>{});
- }
-}
-
+// 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 _Awaiter, class _Promise>
+concept __with_await_suspend =
+ same_as<_Promise, void> ||
+ requires(_Awaiter& __await, __coro::coroutine_handle<_Promise> __h) {
+ {
+ __await.await_suspend(__h)
+ } -> __await_suspend_result;
+ };
+
template <class _Awaiter, class _Promise = void>
concept __awaiter = requires(_Awaiter& __await) {
__await.await_ready() ? 1 : 0;
- {
- (__await_suspend<_Promise>)(__await)
- } -> __await_suspend_result;
__await.await_resume();
- };
+ } && __with_await_suspend<_Awaiter, _Promise>;
template <class _Awaitable>
decltype(auto) __get_awaiter(_Awaitable&& __await, void*)
diff --git a/include/sdbusplus/async/stdexec/execution.hpp b/include/sdbusplus/async/stdexec/execution.hpp
index 10f6abe..be0acf3 100644
--- a/include/sdbusplus/async/stdexec/execution.hpp
+++ b/include/sdbusplus/async/stdexec/execution.hpp
@@ -24,6 +24,7 @@
#include <atomic>
#include <cassert>
+#include <concepts>
#include <condition_variable>
#include <memory>
#include <mutex>
@@ -56,6 +57,18 @@
#pragma diag_suppress 497
#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.")]]
+#else
+#define R5_SENDER_DEPR_WARNING
+#define R5_RECEIVER_DEPR_WARNING
+#endif
+
STDEXEC_PRAGMA_PUSH()
STDEXEC_PRAGMA_IGNORE("-Wundefined-inline")
STDEXEC_PRAGMA_IGNORE("-Wundefined-internal")
@@ -68,6 +81,75 @@
using std::remove_cvref_t;
+// [exec.queries.queryable]
+template <class T>
+concept queryable = destructible<T>;
+
+// [exec.fwd_env]
+namespace __forwarding_query
+{
+struct forwarding_query_t
+{
+ template <class _Query>
+ constexpr bool operator()(_Query __query) const noexcept
+ {
+ if constexpr (tag_invocable<forwarding_query_t, _Query>)
+ {
+ return tag_invoke(*this, (_Query &&) __query);
+ }
+ else if constexpr (std::derived_from<_Query, forwarding_query_t>)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+};
+} // namespace __forwarding_query
+inline constexpr __forwarding_query::forwarding_query_t forwarding_query{};
+using __forwarding_query::forwarding_query_t;
+
+/////////////////////////////////////////////////////////////////////////////
+// [execution.receivers]
+template <class _Receiver>
+inline constexpr bool enable_receiver =
+ requires { typename _Receiver::is_receiver; };
+
+/////////////////////////////////////////////////////////////////////////////
+// completion_signatures
+namespace __compl_sigs
+{
+template <class _Env>
+struct __env_promise;
+struct __dependent;
+} // namespace __compl_sigs
+
+/////////////////////////////////////////////////////////////////////////////
+// env_of
+namespace __env
+{
+struct empty_env
+{
+ using __t = empty_env;
+ using __id = empty_env;
+};
+} // namespace __env
+using __env::empty_env;
+using __empty_env
+ [[deprecated("Please use stdexec::empty_env now.")]] = empty_env;
+
+/////////////////////////////////////////////////////////////////////////////
+// [execution.senders]
+template <class _Sender>
+concept __enable_sender =
+ requires { typename _Sender::is_sender; } ||
+ __awaitable<_Sender, __compl_sigs::__env_promise<empty_env>>;
+
+template <class _Sender>
+inline constexpr bool enable_sender = __enable_sender<_Sender>;
+
// [execution.schedulers.queries], scheduler queries
namespace __scheduler_queries
{
@@ -115,11 +197,6 @@
// env_of
namespace __env
{
-struct __empty_env
-{
- using __t = __empty_env;
- using __id = __empty_env;
-};
struct no_env
{
using __t = no_env;
@@ -220,7 +297,7 @@
__with<_Tags, _Values>... __ws) const
noexcept(std::is_nothrow_move_constructible_v<_Value> &&
(std::is_nothrow_move_constructible_v<_Values> && ...))
- -> __env_t<__empty_env, __with<_Tag, _Value>,
+ -> __env_t<empty_env, __with<_Tag, _Value>,
__with<_Tags, _Values>...>
{
return {{std::move(__w)}, {std::move(__ws)}..., {}};
@@ -250,11 +327,31 @@
noexcept(nothrow_tag_invocable<get_env_t, const _EnvProvider&>)
-> tag_invoke_result_t<get_env_t, const _EnvProvider&>
{
+ static_assert(
+ queryable<tag_invoke_result_t<get_env_t, const _EnvProvider&>>);
return tag_invoke(*this, __with_env);
}
+
+ // NOT TO SPEC: The overload below checks the non-standard
+ // enable_sender to determine whether to provide backwards
+ // compatible behavior for R5 version sender types. When we
+ // deprecate R5 support, we can bring this overload in line with
+ // P2300R7.
+ template <class _EnvProvider>
+ constexpr decltype(auto)
+ operator()(const _EnvProvider& __with_env) const noexcept
+ {
+ if constexpr (!enable_sender<_EnvProvider>)
+ {
+ return __with_env;
+ }
+ else
+ {
+ return empty_env{};
+ }
+ }
};
} // namespace __env
-using __env::__empty_env;
using __env::__with;
using __env::__with_;
@@ -268,7 +365,7 @@
using __env::no_env;
template <class _EnvProvider>
-using env_of_t = decay_t<__call_result_t<get_env_t, _EnvProvider>>;
+using env_of_t = __call_result_t<get_env_t, _EnvProvider>;
template <class _EnvProvider>
concept environment_provider = requires(_EnvProvider& __ep) {
@@ -288,7 +385,9 @@
template <class _Receiver, class... _As>
requires tag_invocable<set_value_t, _Receiver, _As...>
- void operator()(_Receiver&& __rcvr, _As&&... __as) const noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ void
+ operator()(_Receiver&& __rcvr, _As&&... __as) const noexcept
{
static_assert(nothrow_tag_invocable<set_value_t, _Receiver, _As...>);
(void)tag_invoke(set_value_t{}, (_Receiver &&) __rcvr,
@@ -304,7 +403,9 @@
template <class _Receiver, class _Error>
requires tag_invocable<set_error_t, _Receiver, _Error>
- void operator()(_Receiver&& __rcvr, _Error&& __err) const noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ void
+ operator()(_Receiver&& __rcvr, _Error&& __err) const noexcept
{
static_assert(nothrow_tag_invocable<set_error_t, _Receiver, _Error>);
(void)tag_invoke(set_error_t{}, (_Receiver &&) __rcvr,
@@ -320,7 +421,9 @@
template <class _Receiver>
requires tag_invocable<set_stopped_t, _Receiver>
- void operator()(_Receiver&& __rcvr) const noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ void
+ operator()(_Receiver&& __rcvr) const noexcept
{
static_assert(nothrow_tag_invocable<set_stopped_t, _Receiver>);
(void)tag_invoke(set_stopped_t{}, (_Receiver &&) __rcvr);
@@ -363,6 +466,13 @@
}
} __try_call{};
+namespace __as_awaitable
+{
+struct as_awaitable_t;
+}
+using __as_awaitable::as_awaitable_t;
+extern const as_awaitable_t as_awaitable;
+
/////////////////////////////////////////////////////////////////////////////
// completion_signatures
namespace __compl_sigs
@@ -400,12 +510,35 @@
__types<> __test(...);
#endif
+// To be kept in sync with the promise type used in __connect_awaitable
+template <class _Env>
+struct __env_promise
+{
+ template <class _Ty>
+ _Ty&& await_transform(_Ty&& __value) noexcept
+ {
+ return (_Ty &&) __value;
+ }
+
+ template <class _Ty>
+ requires tag_invocable<as_awaitable_t, _Ty, __env_promise&>
+ auto await_transform(_Ty&& __value) noexcept(
+ nothrow_tag_invocable<as_awaitable_t, _Ty, __env_promise&>)
+ -> tag_invoke_result_t<as_awaitable_t, _Ty, __env_promise&>
+ {
+ return tag_invoke(as_awaitable, (_Ty &&) __value, *this);
+ }
+
+ friend auto tag_invoke(get_env_t, const __env_promise&) noexcept
+ -> const _Env&;
+};
+
// BUGBUG not to spec!
struct __dependent
{
#if !_STD_NO_COROUTINES_
bool await_ready();
- void await_suspend(const __coro::coroutine_handle<no_env>&);
+ void await_suspend(const __coro::coroutine_handle<__env_promise<no_env>>&);
__dependent await_resume();
#endif
};
@@ -428,6 +561,8 @@
#endif
} // namespace __compl_sigs
using __compl_sigs::__completion_signature;
+using __compl_sigs::__env_promise;
+using no_env_promise = __env_promise<no_env>;
template <same_as<no_env>>
using dependent_completion_signatures = __compl_sigs::__dependent;
@@ -542,10 +677,21 @@
/////////////////////////////////////////////////////////////////////////////
// [execution.receivers]
+
template <class _Receiver>
-concept receiver = environment_provider<__cref_t<_Receiver>> &&
- move_constructible<remove_cvref_t<_Receiver>> &&
- constructible_from<remove_cvref_t<_Receiver>, _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>;
template <class _Receiver, class _Completions>
concept receiver_of =
@@ -591,9 +737,9 @@
{
return __q<__member_alias_t>{};
}
- else if constexpr (__awaitable<_Sender, _Env>)
+ else if constexpr (__awaitable<_Sender, __env_promise<_Env>>)
{
- using _Result = __await_result_t<_Sender, _Env>;
+ using _Result = __await_result_t<_Sender, __env_promise<_Env>>;
if constexpr (same_as<_Result,
dependent_completion_signatures<no_env>>)
{
@@ -614,7 +760,8 @@
template <class _Sender, class _Env = no_env>
requires(__with_tag_invoke<_Sender, _Env> ||
- __with_member_alias<_Sender> || __awaitable<_Sender, _Env>)
+ __with_member_alias<_Sender> ||
+ __awaitable<_Sender, __env_promise<_Env>>)
constexpr auto operator()(_Sender&&, const _Env& = {}) const noexcept
-> __minvoke<__impl_fn<_Sender, _Env>, _Sender, _Env>
{
@@ -636,15 +783,32 @@
// [execution.senders]
// NOT TO SPEC (YET)
template <class _Sender, class _Env>
-concept __sender =
- __valid<__completion_signatures_of_t, _Sender, _Env> &&
+concept __with_completion_signatures =
+ __callable<get_completion_signatures_t, _Sender, _Env> &&
__valid_completion_signatures<__completion_signatures_of_t<_Sender, _Env>,
- _Env> &&
+ _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>);
+
+/////////////////////////////////////////////////////////////////////////////
+// [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>;
-template <class _Sender, class _Env = no_env>
-concept sender = __sender<_Sender, no_env> && __sender<_Sender, _Env>;
+template <class _Sender, class _Env>
+concept sender_in = sender<_Sender, _Env>;
// __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
@@ -925,7 +1089,9 @@
template <class _Scheduler>
requires tag_invocable<schedule_t, _Scheduler> &&
sender<tag_invoke_result_t<schedule_t, _Scheduler>>
- auto operator()(_Scheduler&& __sched) const
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ auto
+ operator()(_Scheduler&& __sched) const
noexcept(nothrow_tag_invocable<schedule_t, _Scheduler>)
{
return tag_invoke(schedule_t{}, (_Scheduler &&) __sched);
@@ -1027,7 +1193,8 @@
requires(_Scheduler&& __sched,
const get_completion_scheduler_t<set_value_t>&& __tag) {
{
- tag_invoke(std::move(__tag), schedule((_Scheduler &&) __sched))
+ tag_invoke(std::move(__tag),
+ get_env(schedule((_Scheduler &&) __sched)))
} -> same_as<remove_cvref_t<_Scheduler>>;
};
@@ -1051,6 +1218,11 @@
struct 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&>>
@@ -1065,6 +1237,11 @@
struct get_delegatee_scheduler_t
{
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const get_delegatee_scheduler_t&) noexcept
+ {
+ return true;
+ }
template <class _T>
requires nothrow_tag_invocable<get_delegatee_scheduler_t,
__cref_t<_T>> &&
@@ -1083,6 +1260,11 @@
struct 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&>>
@@ -1097,6 +1279,11 @@
struct 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
{
@@ -1168,13 +1355,6 @@
};
#if !_STD_NO_COROUTINES_
-namespace __as_awaitable
-{
-struct as_awaitable_t;
-}
-using __as_awaitable::as_awaitable_t;
-extern const as_awaitable_t as_awaitable;
-
/////////////////////////////////////////////////////////////////////////////
// __connect_awaitable_
namespace __connect_awaitable_
@@ -1479,33 +1659,67 @@
{
struct connect_t;
+template <class _T>
+R5_SENDER_DEPR_WARNING void
+ __update_sender_type_to_p2300r7_by_adding_enable_sender_trait()
+{}
+
+template <class _T>
+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 =
- sender<_Sender, env_of_t<_Receiver>> &&
+ receiver<_Receiver> && sender<_Sender, env_of_t<_Receiver>> &&
__receiver_from<_Receiver, _Sender> &&
tag_invocable<connect_t, _Sender, _Receiver>;
struct connect_t
{
template <class _Sender, class _Receiver>
- static constexpr bool __nothrow_connect() noexcept
+ static constexpr auto __select_impl() noexcept
{
+ // Report that 2300R5-style senders and receivers are deprecated:
+ if constexpr (!enable_sender<remove_cvref_t<_Sender>>)
+ __update_sender_type_to_p2300r7_by_adding_enable_sender_trait<
+ remove_cvref_t<_Sender>>();
+
+ if constexpr (!enable_receiver<remove_cvref_t<_Receiver>>)
+ __update_receiver_type_to_p2300r7_by_adding_enable_receiver_trait<
+ remove_cvref_t<_Receiver>>();
+
if constexpr (__connectable_with_tag_invoke<_Sender, _Receiver>)
{
- return nothrow_tag_invocable<connect_t, _Sender, _Receiver>;
+ using _Result = tag_invoke_result_t<connect_t, _Sender, _Receiver>;
+ constexpr bool _Nothrow =
+ nothrow_tag_invocable<connect_t, _Sender, _Receiver>;
+ return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
+ }
+ else if constexpr (__callable<__connect_awaitable_t, _Sender,
+ _Receiver>)
+ {
+ using _Result =
+ __call_result_t<__connect_awaitable_t, _Sender, _Receiver>;
+ return static_cast<_Result (*)()>(nullptr);
}
else
{
- return false;
+ return static_cast<void (*)() noexcept>(nullptr);
}
}
template <class _Sender, class _Receiver>
+ using __select_impl_t = decltype(__select_impl<_Sender, _Receiver>());
+
+ template <class _Sender, class _Receiver>
requires __connectable_with_tag_invoke<_Sender, _Receiver> ||
__callable<__connect_awaitable_t, _Sender, _Receiver> ||
tag_invocable<__is_debug_env_t, env_of_t<_Receiver>>
- auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const
- noexcept(__nothrow_connect<_Sender, _Receiver>())
+ auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const
+ noexcept(
+ __nothrow_callable<__select_impl_t<_Sender, _Receiver>>)
+ -> __call_result_t<__select_impl_t<_Sender, _Receiver>>
{
if constexpr (__connectable_with_tag_invoke<_Sender, _Receiver>)
{
@@ -1528,8 +1742,7 @@
// This should generate an instantiate backtrace that contains
// useful debugging information.
using __tag_invoke::tag_invoke;
- return tag_invoke(*this, (_Sender &&) __sndr,
- (_Receiver &&) __rcvr);
+ tag_invoke(*this, (_Sender &&) __sndr, (_Receiver &&) __rcvr);
}
}
@@ -1563,7 +1776,7 @@
// understand where in a chain of senders the problem is occurring.
//
// ```c++
-// template <class _Sigs, class _Env = __empty_env, class _Sender>
+// template <class _Sigs, class _Env = empty_env, class _Sender>
// void __debug_sender(_Sender&& __sndr, _Env = {});
//
// template <class _Sender>
@@ -1600,7 +1813,7 @@
// constraint that failed.
namespace __debug
{
-template <class _Sigs, class _Env = __empty_env, class _Sender>
+template <class _Sigs, class _Env = empty_env, class _Sender>
void __debug_sender(_Sender&& __sndr, _Env = {})
{
using _Receiver = __debug_receiver<_Env, _Sigs>;
@@ -1610,7 +1823,7 @@
template <class _Sender>
void __debug_sender(_Sender&& __sndr)
{
- using _Receiver = __any_debug_receiver<__empty_env>;
+ using _Receiver = __any_debug_receiver<empty_env>;
(void)connect_t{}((_Sender &&) __sndr, _Receiver{});
}
@@ -1627,7 +1840,8 @@
/////////////////////////////////////////////////////////////////////////////
// [exec.snd]
template <class _Sender, class _Receiver>
-concept sender_to = sender<_Sender, env_of_t<_Receiver>> &&
+concept sender_to = receiver<_Receiver> &&
+ sender<_Sender, env_of_t<_Receiver>> &&
__receiver_from<_Receiver, _Sender> &&
requires(_Sender&& __sndr, _Receiver&& __rcvr) {
connect((_Sender &&) __sndr, (_Receiver &&) __rcvr);
@@ -1652,25 +1866,31 @@
template <__one_of<set_value_t, set_error_t, set_stopped_t> _CPO>
struct get_completion_scheduler_t
{
+ // NOT TO SPEC:
friend constexpr bool tag_invoke(forwarding_sender_query_t,
const get_completion_scheduler_t&) noexcept
{
return true;
}
+ friend constexpr bool tag_invoke(forwarding_query_t,
+ const get_completion_scheduler_t&) noexcept
+ {
+ return true;
+ }
- template <sender _Sender>
- requires tag_invocable<get_completion_scheduler_t, const _Sender&> &&
+ template <queryable _Queryable>
+ requires tag_invocable<get_completion_scheduler_t, const _Queryable&> &&
scheduler<tag_invoke_result_t<get_completion_scheduler_t,
- const _Sender&>>
- auto operator()(const _Sender& __sndr) const noexcept
+ const _Queryable&>>
+ auto operator()(const _Queryable& __queryable) const noexcept
-> tag_invoke_result_t<get_completion_scheduler_t,
- const _Sender&>
+ const _Queryable&>
{
// NOT TO SPEC:
- static_assert(
- nothrow_tag_invocable<get_completion_scheduler_t, const _Sender&>,
- "get_completion_scheduler<_CPO> should be noexcept");
- return tag_invoke(*this, __sndr);
+ static_assert(nothrow_tag_invocable<get_completion_scheduler_t,
+ const _Queryable&>,
+ "get_completion_scheduler<_CPO> should be noexcept");
+ return tag_invoke(*this, __queryable);
}
};
} // namespace __sender_queries
@@ -1682,11 +1902,13 @@
template <class _Sender, class _CPO>
concept __has_completion_scheduler =
- __callable<get_completion_scheduler_t<_CPO>, _Sender>;
+ __callable<get_completion_scheduler_t<_CPO>,
+ __call_result_t<get_env_t, const _Sender&>>;
template <class _Sender, class _CPO>
using __completion_scheduler_for =
- __call_result_t<get_completion_scheduler_t<_CPO>, _Sender>;
+ __call_result_t<get_completion_scheduler_t<_CPO>,
+ __call_result_t<get_env_t, const _Sender&>>;
template <class _Fun, class _CPO, class _Sender, class... _As>
concept __tag_invocable_with_completion_scheduler =
@@ -1706,6 +1928,9 @@
template <class _Value>
using __expected_t =
std::variant<std::monostate, __value_or_void_t<_Value>, std::exception_ptr>;
+template <class _Promise>
+using __env_t = __minvoke<__with_default<__q<__call_result_t>, empty_env>,
+ get_env_t, _Promise>;
template <class _Value>
struct __receiver_base
@@ -1761,19 +1986,25 @@
}
// Forward get_env query to the coroutine promise
- friend auto tag_invoke(get_env_t, const __t& __self)
- -> env_of_t<_Promise>
+ friend __env_t<_Promise&> tag_invoke(get_env_t, const __t& __self)
{
- auto __continuation =
- __coro::coroutine_handle<_Promise>::from_address(
- __self.__continuation_.address());
- return get_env(__continuation.promise());
+ 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{};
+ }
}
};
};
template <class _Sender, class _Promise>
-using __value_t = __single_sender_value_t<_Sender, env_of_t<_Promise>>;
+using __value_t = __single_sender_value_t<_Sender, __env_t<_Promise>>;
template <class _Sender, class _Promise>
using __receiver_t =
@@ -1814,8 +2045,7 @@
{
using _Promise = stdexec::__t<_PromiseId>;
using _Sender = stdexec::__t<_SenderId>;
- using __value =
- __value_t<stdexec::__t<_SenderId>, stdexec::__t<_PromiseId>>;
+ using __value = __value_t<_Sender, _Promise>;
struct __t : __sender_awaitable_base<__value>
{
__t(_Sender&& sndr,
@@ -1840,14 +2070,9 @@
using __sender_awaitable_t =
__t<__sender_awaitable<__id<_Promise>, __id<_Sender>>>;
-template <class _T, class _Promise>
-concept __custom_tag_invoke_awaiter =
- tag_invocable<as_awaitable_t, _T, _Promise&> &&
- __awaitable<tag_invoke_result_t<as_awaitable_t, _T, _Promise&>, _Promise>;
-
template <class _Sender, class _Promise>
concept __awaitable_sender =
- __single_typed_sender<_Sender, env_of_t<_Promise>> &&
+ __single_typed_sender<_Sender, __env_t<_Promise>> &&
sender_to<_Sender, __receiver_t<_Sender, _Promise>> &&
requires(_Promise& __promise) {
{
@@ -1858,37 +2083,47 @@
struct as_awaitable_t
{
template <class _T, class _Promise>
- static constexpr bool __is_noexcept() noexcept
+ static constexpr auto __select_impl_() noexcept
{
- if constexpr (__custom_tag_invoke_awaiter<_T, _Promise>)
+ if constexpr (tag_invocable<as_awaitable_t, _T, _Promise&>)
{
- return nothrow_tag_invocable<as_awaitable_t, _T, _Promise&>;
+ using _Result = tag_invoke_result_t<as_awaitable_t, _T, _Promise&>;
+ constexpr bool _Nothrow =
+ nothrow_tag_invocable<as_awaitable_t, _T, _Promise&>;
+ return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
}
else if constexpr (__awaitable<_T>)
- {
- return true;
+ { // NOT __awaitable<_T, _Promise> !!
+ return static_cast < _T && (*)() noexcept > (nullptr);
}
else if constexpr (__awaitable_sender<_T, _Promise>)
{
- using _Sender = __sender_awaitable_t<_Promise, _T>;
- return std::is_nothrow_constructible_v<
- _Sender, _T, __coro::coroutine_handle<_Promise>>;
+ using _Result = __sender_awaitable_t<_Promise, _T>;
+ constexpr bool _Nothrow = __nothrow_constructible_from<
+ _Result, _T, __coro::coroutine_handle<_Promise>>;
+ return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
}
else
{
- return true;
+ return static_cast < _T && (*)() noexcept > (nullptr);
}
}
template <class _T, class _Promise>
- decltype(auto) operator()(_T&& __t, _Promise& __promise) const
- noexcept(__is_noexcept<_T, _Promise>())
+ using __select_impl_t = decltype(__select_impl_<_T, _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>>
{
- if constexpr (__custom_tag_invoke_awaiter<_T, _Promise>)
+ if constexpr (tag_invocable<as_awaitable_t, _T, _Promise&>)
{
+ using _Result = tag_invoke_result_t<as_awaitable_t, _T, _Promise&>;
+ static_assert(__awaitable<_Result, _Promise>);
return tag_invoke(*this, (_T &&) __t, __promise);
}
else if constexpr (__awaitable<_T>)
- {
+ { // NOT __awaitable<_T, _Promise> !!
return (_T &&) __t;
}
else if constexpr (__awaitable_sender<_T, _Promise>)
@@ -1909,6 +2144,82 @@
namespace __with_awaitable_senders
{
+
+template <class _Promise = void>
+class __continuation_handle;
+
+template <>
+class __continuation_handle<void>
+{
+ public:
+ __continuation_handle() = default;
+
+ template <class _Promise>
+ __continuation_handle(__coro::coroutine_handle<_Promise> __coro) noexcept :
+ __coro_(__coro)
+ {
+ if constexpr (requires(_Promise & __promise) {
+ __promise.unhandled_stopped();
+ })
+ {
+ __stopped_callback_ =
+ [](void* __address) noexcept -> __coro::coroutine_handle<> {
+ // This causes the rest of the coroutine (the part after the
+ // co_await of the sender) to be skipped and invokes the calling
+ // coroutine's stopped handler.
+ return __coro::coroutine_handle<_Promise>::from_address(
+ __address)
+ .promise()
+ .unhandled_stopped();
+ };
+ }
+ // If _Promise doesn't implement unhandled_stopped(), then if a
+ // "stopped" unwind reaches this point, it's considered an unhandled
+ // exception and terminate() is called.
+ }
+
+ __coro::coroutine_handle<> handle() const noexcept
+ {
+ return __coro_;
+ }
+
+ __coro::coroutine_handle<> unhandled_stopped() const noexcept
+ {
+ return __stopped_callback_(__coro_.address());
+ }
+
+ private:
+ __coro::coroutine_handle<> __coro_{};
+ using __stopped_callback_t = __coro::coroutine_handle<> (*)(void*) noexcept;
+ __stopped_callback_t __stopped_callback_ =
+ [](void*) noexcept -> __coro::coroutine_handle<> { std::terminate(); };
+};
+
+template <class _Promise>
+class __continuation_handle
+{
+ public:
+ __continuation_handle() = default;
+
+ __continuation_handle(__coro::coroutine_handle<_Promise> __coro) noexcept :
+ __continuation_{__coro}
+ {}
+
+ __coro::coroutine_handle<_Promise> handle() const noexcept
+ {
+ return __coro::coroutine_handle<_Promise>::from_address(
+ __continuation_.handle().address());
+ }
+
+ __coro::coroutine_handle<> unhandled_stopped() const noexcept
+ {
+ return __continuation_.unhandled_stopped();
+ }
+
+ private:
+ __continuation_handle<> __continuation_{};
+};
+
struct __with_awaitable_senders_base
{
template <class _OtherPromise>
@@ -1917,40 +2228,25 @@
{
static_assert(!std::is_void_v<_OtherPromise>);
__continuation_ = __hcoro;
- if constexpr (requires(_OtherPromise & __other) {
- __other.unhandled_stopped();
- })
- {
- __stopped_callback_ =
- [](void* __address) noexcept -> __coro::coroutine_handle<> {
- // This causes the rest of the coroutine (the part after the
- // co_await of the sender) to be skipped and invokes the calling
- // coroutine's stopped handler.
- return __coro::coroutine_handle<_OtherPromise>::from_address(
- __address)
- .promise()
- .unhandled_stopped();
- };
- }
- // If _OtherPromise doesn't implement unhandled_stopped(), then if a
- // "stopped" unwind reaches this point, it's considered an unhandled
- // exception and terminate() is called.
}
- __coro::coroutine_handle<> continuation() const noexcept
+ void set_continuation(__continuation_handle<> __continuation) noexcept
+ {
+ __continuation_ = __continuation;
+ }
+
+ __continuation_handle<> continuation() const noexcept
{
return __continuation_;
}
__coro::coroutine_handle<> unhandled_stopped() noexcept
{
- return (*__stopped_callback_)(__continuation_.address());
+ return __continuation_.unhandled_stopped();
}
private:
- __coro::coroutine_handle<> __continuation_{};
- __coro::coroutine_handle<> (*__stopped_callback_)(void*) noexcept =
- [](void*) noexcept -> __coro::coroutine_handle<> { std::terminate(); };
+ __continuation_handle<> __continuation_{};
};
template <class _Promise>
@@ -1965,6 +2261,7 @@
}
};
} // namespace __with_awaitable_senders
+using __with_awaitable_senders::__continuation_handle;
using __with_awaitable_senders::with_awaitable_senders;
#endif
@@ -2059,13 +2356,6 @@
{
return {{}, (_Receiver &&) __rcvr};
}
-
- template <class CPO>
- friend __scheduler tag_invoke(get_completion_scheduler_t<CPO>,
- __sender) noexcept
- {
- return {};
- }
};
friend __sender tag_invoke(schedule_t, __scheduler)
@@ -2143,7 +2433,7 @@
struct start_detached_t
{
- template <sender _Sender, class _Env = __empty_env>
+ template <sender _Sender, class _Env = empty_env>
requires sender_to<_Sender, __detached_receiver_t<_Env>> ||
__is_start_detached_customized<_Sender, _Env>
void operator()(_Sender&& __sndr, _Env&& __env = _Env{}) const noexcept(
@@ -2199,6 +2489,8 @@
{
using __id = __basic_sender;
using completion_signatures = __completion_signatures_<_Tag, _Ts...>;
+ using is_sender = void;
+
std::tuple<_Ts...> __vals_;
template <receiver_of<completion_signatures> _Receiver>
@@ -2220,6 +2512,11 @@
{
return {{}, ((__t &&) __sndr).__vals_, (_Receiver &&) __rcvr};
}
+
+ friend empty_env tag_invoke(get_env_t, const __t&) noexcept
+ {
+ return {};
+ }
};
};
@@ -2252,7 +2549,9 @@
inline constexpr struct __just_t
{
template <__movable_value... _Ts>
- __t<__sender<decay_t<_Ts>...>> operator()(_Ts&&... __ts) const
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ __t<__sender<decay_t<_Ts>...>>
+ operator()(_Ts&&... __ts) const
noexcept((std::is_nothrow_constructible_v<decay_t<_Ts>, _Ts> && ...))
{
return {{{(_Ts &&) __ts...}}};
@@ -2262,7 +2561,9 @@
inline constexpr struct __just_error_t
{
template <__movable_value _Error>
- __t<__error_sender<decay_t<_Error>>> operator()(_Error&& __err) const
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ __t<__error_sender<decay_t<_Error>>>
+ operator()(_Error&& __err) const
noexcept(std::is_nothrow_constructible_v<decay_t<_Error>, _Error>)
{
return {{{(_Error &&) __err}}};
@@ -2271,7 +2572,9 @@
inline constexpr struct __just_stopped_t
{
- __stopped_sender operator()() const noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ __stopped_sender
+ operator()() const noexcept
{
return {{}};
}
@@ -2304,7 +2607,7 @@
std::terminate();
}
friend void tag_invoke(set_stopped_t, __as_receiver&&) noexcept {}
- friend __empty_env tag_invoke(get_env_t, const __as_receiver&)
+ friend empty_env tag_invoke(get_env_t, const __as_receiver&)
{
return {};
}
@@ -2440,7 +2743,9 @@
// A derived-to-base cast that works even when the base is not
// accessible from derived.
template <class _T, class _U>
-__copy_cvref_t<_U&&, _T> __c_cast(_U&& u) noexcept
+STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ __copy_cvref_t<_U&&, _T>
+ __c_cast(_U&& u) noexcept
requires __decays_to<_T, _T>
{
static_assert(std::is_reference_v<__copy_cvref_t<_U&&, _T>>);
@@ -2455,7 +2760,7 @@
{};
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;
+empty_env tag_invoke(get_env_t, __receiver) noexcept;
} // namespace __no
using __not_a_receiver = __no::__receiver;
@@ -2473,15 +2778,23 @@
[[no_unique_address]] _Base __base_;
protected:
- _Base& base() & noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ _Base&
+ base() & noexcept
{
return __base_;
}
- const _Base& base() const& noexcept
+
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ const _Base&
+ base() const& noexcept
{
return __base_;
}
- _Base&& base() && noexcept
+
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ _Base&&
+ base() && noexcept
{
return (_Base &&) __base_;
}
@@ -2502,9 +2815,10 @@
// but 'int(type::existing_member_function)' is an error (as desired).
#define _DISPATCH_MEMBER(_TAG) \
template <class _Self, class... _Ts> \
- static auto __call_##_TAG(_Self&& __self, _Ts&&... __ts) noexcept( \
- noexcept(((_Self &&) __self)._TAG((_Ts &&) __ts...))) \
- ->decltype(((_Self &&) __self)._TAG((_Ts &&) __ts...)) \
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE static auto \
+ __call_##_TAG(_Self&& __self, _Ts&&... __ts) noexcept( \
+ noexcept(((_Self &&) __self)._TAG((_Ts &&) __ts...))) \
+ ->decltype(((_Self &&) __self)._TAG((_Ts &&) __ts...)) \
{ \
return ((_Self &&) __self)._TAG((_Ts &&) __ts...); \
} \
@@ -2551,7 +2865,9 @@
using __base_t = __minvoke<__get_base_t, _D&&>;
template <class _D>
- static __base_t<_D> __get_base(_D&& __self) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ static __base_t<_D>
+ __get_base(_D&& __self) noexcept
{
if constexpr (__has_base)
{
@@ -2564,8 +2880,9 @@
}
template <same_as<set_value_t> _SetValue, class... _As>
- friend auto tag_invoke(_SetValue, _Derived&& __self,
- _As&&... __as) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend auto
+ tag_invoke(_SetValue, _Derived&& __self, _As&&... __as) noexcept
-> decltype(_CALL_MEMBER(set_value, (_Derived &&) __self,
(_As &&) __as...))
{
@@ -2578,15 +2895,17 @@
class... _As>
requires _MISSING_MEMBER(_D, set_value) &&
tag_invocable<set_value_t, __base_t<_D>, _As...>
- friend void tag_invoke(_SetValue, _Derived&& __self,
- _As&&... __as) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend void tag_invoke(_SetValue, _Derived&& __self,
+ _As&&... __as) noexcept
{
stdexec::set_value(__get_base((_D &&) __self), (_As &&) __as...);
}
template <same_as<set_error_t> _SetError, class _Error>
- friend auto tag_invoke(_SetError, _Derived&& __self,
- _Error&& __err) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend auto
+ tag_invoke(_SetError, _Derived&& __self, _Error&& __err) noexcept
-> decltype(_CALL_MEMBER(set_error, (_Derived &&) __self,
(_Error &&) __err))
{
@@ -2599,15 +2918,18 @@
class _D = _Derived>
requires _MISSING_MEMBER(_D, set_error) &&
tag_invocable<set_error_t, __base_t<_D>, _Error>
- friend void tag_invoke(_SetError, _Derived&& __self,
- _Error&& __err) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend void tag_invoke(_SetError, _Derived&& __self,
+ _Error&& __err) noexcept
{
stdexec::set_error(__get_base((_Derived &&) __self),
(_Error &&) __err);
}
template <same_as<set_stopped_t> _SetStopped, class _D = _Derived>
- friend auto tag_invoke(_SetStopped, _Derived&& __self) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend auto
+ tag_invoke(_SetStopped, _Derived&& __self) noexcept
-> decltype(_CALL_MEMBER(set_stopped, (_D &&) __self))
{
static_assert(
@@ -2618,23 +2940,27 @@
template <same_as<set_stopped_t> _SetStopped, class _D = _Derived>
requires _MISSING_MEMBER(_D, set_stopped) &&
tag_invocable<set_stopped_t, __base_t<_D>>
- friend void tag_invoke(_SetStopped, _Derived&& __self) noexcept
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend void tag_invoke(_SetStopped, _Derived&& __self) noexcept
{
stdexec::set_stopped(__get_base((_Derived &&) __self));
}
// Pass through the get_env receiver query
template <same_as<get_env_t> _GetEnv, class _D = _Derived>
- friend auto tag_invoke(_GetEnv, const _Derived& __self)
- -> decltype(_CALL_MEMBER(get_env, (const _D&)__self))
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend auto
+ tag_invoke(_GetEnv, const _Derived& __self)
+ -> decltype(_CALL_MEMBER(get_env, (const _D&)__self))
{
return _CALL_MEMBER(get_env, __self);
}
template <same_as<get_env_t> _GetEnv, class _D = _Derived>
requires _MISSING_MEMBER(_D, get_env)
- friend auto tag_invoke(_GetEnv, const _Derived& __self)
- -> __call_result_t<get_env_t, __base_t<const _D&>>
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ friend auto tag_invoke(_GetEnv, const _Derived& __self)
+ -> __call_result_t<get_env_t, __base_t<const _D&>>
{
return stdexec::get_env(__get_base(__self));
}
@@ -2642,6 +2968,8 @@
public:
__t() = default;
using __adaptor_base<_Base>::__adaptor_base;
+
+ using is_receiver = void;
};
};
} // namespace __adaptors
@@ -2830,17 +3158,11 @@
-> __completion_signatures<_Self, _Env>
requires true;
- // forward sender queries:
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return get_env(__self.__sndr_);
}
};
};
@@ -2867,7 +3189,7 @@
then_t, __completion_scheduler_for<_Sender, set_value_t>,
_Sender, _Fun>)
{
- auto __sched = get_completion_scheduler<set_value_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_value_t>(get_env(__sndr));
return tag_invoke(then_t{}, std::move(__sched), (_Sender &&) __sndr,
(_Fun &&) __fun);
}
@@ -2899,29 +3221,45 @@
{
using _Receiver = stdexec::__t<_ReceiverId>;
- class __t : receiver_adaptor<__t, _Receiver>
+ struct __t
{
- friend receiver_adaptor<__t, _Receiver>;
- [[no_unique_address]] _Fun __f_;
+ using __id = __receiver;
+
+ _Receiver __rcvr_;
+ [[no_unique_address]] _Fun __fun_;
+
+ 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.__rcvr_, (_Args &&) __args...);
+ }
// Customize set_error by invoking the invocable and passing the result
// to the base class
- template <class _Error>
+ template <__decays_to<__t> _Self, class _Error>
requires invocable<_Fun, _Error> &&
__receiver_of_invoke_result<_Receiver, _Fun, _Error>
- void set_error(_Error&& __err) && noexcept
+ friend void tag_invoke(set_error_t, _Self&& __self,
+ _Error&& __error) noexcept
{
- stdexec::__set_value_invoke(((__t &&) * this).base(),
- (_Fun &&) __f_, (_Error &&) __err);
+ stdexec::__set_value_invoke((_Receiver &&) __self.__rcvr_,
+ (_Fun &&) __self.__fun_,
+ (_Error &&) __error);
}
- public:
- using __id = __receiver;
+ friend void tag_invoke(set_stopped_t, __t&& __self) noexcept
+ requires __callable<set_stopped_t, _Receiver>
+ {
+ set_stopped((_Receiver &&) __self.__rcvr_);
+ }
- explicit __t(_Receiver __rcvr, _Fun __fun) :
- receiver_adaptor<__t, _Receiver>((_Receiver &&) __rcvr),
- __f_((_Fun &&) __fun)
- {}
+ friend env_of_t<_Receiver> tag_invoke(get_env_t,
+ const __t& __self) noexcept
+ {
+ return get_env(__self.__rcvr_);
+ }
};
};
@@ -2931,7 +3269,7 @@
using _Sender = stdexec::__t<_SenderId>;
template <class _Receiver>
- using __receiver = stdexec::__t<__receiver<stdexec::__id<_Receiver>, _Fun>>;
+ using __receiver = stdexec::__t<__receiver<__id<_Receiver>, _Fun>>;
struct __t
{
@@ -2972,16 +3310,11 @@
-> __completion_signatures<_Self, _Env>
requires true;
- template <tag_category<forwarding_sender_query> _Tag, class _Error>
- requires __callable<_Tag, const _Sender&, _Error>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _Error&& __err) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _Error>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _Error>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_Error &&) __err);
+ return get_env(__self.__sndr_);
}
};
};
@@ -3000,7 +3333,8 @@
upon_error_t, __completion_scheduler_for<_Sender, set_error_t>,
_Sender, _Fun>)
{
- auto __sched = get_completion_scheduler<set_error_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_error_t>(
+ get_env(__sndr)); // TODO ADD TEST!
return tag_invoke(upon_error_t{}, std::move(__sched),
(_Sender &&) __sndr, (_Fun &&) __fun);
}
@@ -3041,25 +3375,39 @@
{
using _Receiver = stdexec::__t<_ReceiverId>;
- class __t : receiver_adaptor<__t, _Receiver>
+ struct __t
{
- friend receiver_adaptor<__t, _Receiver>;
- [[no_unique_address]] _Fun __f_;
+ using __id = __receiver;
+ _Receiver __rcvr_;
+ [[no_unique_address]] _Fun __fun_;
- // Customize set_stopped by invoking the invocable and passing the
- // result to the base class
- void set_stopped() && noexcept
+ 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
{
- stdexec::__set_value_invoke(((__t &&) * this).base(),
- (_Fun &&) __f_);
+ set_value((_Receiver &&) __self.__rcvr_, (_Args &&) __args...);
}
- public:
- using __id = __receiver;
- explicit __t(_Receiver __rcvr, _Fun __fun) :
- receiver_adaptor<__t, _Receiver>((_Receiver &&) __rcvr),
- __f_((_Fun &&) __fun)
- {}
+ 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.__rcvr_, (_Error &&) __error);
+ }
+
+ friend void tag_invoke(set_stopped_t, __t&& __self) noexcept
+ {
+ stdexec::__set_value_invoke((_Receiver &&) __self.__rcvr_,
+ (_Fun &&) __self.__fun_);
+ }
+
+ friend env_of_t<_Receiver> tag_invoke(get_env_t,
+ const __t& __self) noexcept
+ {
+ return get_env(__self.__rcvr_);
+ }
};
};
@@ -3069,7 +3417,7 @@
using _Sender = stdexec::__t<_SenderId>;
template <class _Receiver>
- using __receiver = stdexec::__t<__receiver<stdexec::__id<_Receiver>, _Fun>>;
+ using __receiver = stdexec::__t<__receiver<__id<_Receiver>, _Fun>>;
struct __t
{
@@ -3113,14 +3461,11 @@
-> __completion_signatures<_Self, _Env>
requires true;
- template <tag_category<forwarding_sender_query> _Tag>
- requires __callable<_Tag, const _Sender&>
- friend auto tag_invoke(_Tag __tag, const __t& __self) noexcept(
- __nothrow_callable<_Tag, const _Sender&>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, 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 ((_Tag &&) __tag)(__self.__sndr_);
+ return get_env(__self.__sndr_);
}
};
};
@@ -3128,8 +3473,7 @@
struct upon_stopped_t
{
template <class _Sender, class _Fun>
- using __sender =
- __t<__sender<stdexec::__id<remove_cvref_t<_Sender>>, _Fun>>;
+ using __sender = __t<__sender<__id<remove_cvref_t<_Sender>>, _Fun>>;
template <sender _Sender, __movable_value _Fun>
requires __tag_invocable_with_completion_scheduler<
@@ -3140,7 +3484,8 @@
upon_stopped_t, __completion_scheduler_for<_Sender, set_stopped_t>,
_Sender, _Fun>)
{
- auto __sched = get_completion_scheduler<set_stopped_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_stopped_t>(
+ get_env(__sndr)); // TODO ADD TEST!
return tag_invoke(upon_stopped_t{}, std::move(__sched),
(_Sender &&) __sndr, (_Fun &&) __fun);
}
@@ -3282,16 +3627,11 @@
-> __completion_signatures<_Self, _Env>
requires true;
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return get_env(__self.__sndr_);
}
};
};
@@ -3310,7 +3650,7 @@
bulk_t, __completion_scheduler_for<_Sender, set_value_t>,
_Sender, _Shape, _Fun>)
{
- auto __sched = get_completion_scheduler<set_value_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_value_t>(get_env(__sndr));
return tag_invoke(bulk_t{}, std::move(__sched), (_Sender &&) __sndr,
(_Shape &&) __shape, (_Fun &&) __fun);
}
@@ -3621,21 +3961,6 @@
__self.__shared_state_};
}
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires(!__is_instance_of<_Tag, get_completion_scheduler_t>) &&
- __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag,
- const _Sender&,
- _As...>)
- -> __call_result_if_t<
- tag_category<_Tag, forwarding_sender_query>, _Tag,
- const _Sender&, _As...>
- {
- return ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
- }
-
template <__decays_to<__t> _Self, class _OtherEnv>
friend auto tag_invoke(get_completion_signatures_t, _Self&&, _OtherEnv)
-> __completions_t<_Self>;
@@ -3655,9 +3980,11 @@
using _Sender = __0;
using _Env = __1;
using __cust_sigs = __types<
- tag_invoke_t(split_t, get_completion_scheduler_t<set_value_t>(_Sender&),
+ 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>(_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),
@@ -3682,7 +4009,7 @@
struct split_t
{
- template <sender _Sender, class _Env = __empty_env>
+ template <sender _Sender, class _Env = empty_env>
requires(copy_constructible<remove_cvref_t<_Sender>> &&
sender_to<_Sender&, __receiver_t<_Sender, _Env>>) ||
__is_split_customized<_Sender, _Env>
@@ -3989,21 +4316,6 @@
std::move(__self).__shared_state_};
}
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires(!__is_instance_of<_Tag, get_completion_scheduler_t>) &&
- __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag,
- const _Sender&,
- _As...>)
- -> __call_result_if_t<
- tag_category<_Tag, forwarding_sender_query>, _Tag,
- const _Sender&, _As...>
- {
- return ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
- }
-
template <same_as<__t> _Self, class _OtherEnv>
friend auto tag_invoke(get_completion_signatures_t, _Self&&, _OtherEnv)
-> __completions_t<_Self>;
@@ -4037,10 +4349,11 @@
using _Env = __1;
using __cust_sigs = __types<
tag_invoke_t(ensure_started_t,
- get_completion_scheduler_t<set_value_t>(_Sender&), _Sender),
+ 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>(_Sender&), _Sender,
- _Env),
+ 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),
@@ -4063,9 +4376,17 @@
__make_dispatcher<__cust_sigs, __mconstructor_for<__sender_t>, _Sender,
_Env>;
+template <class _SenderId, class _EnvId>
+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);
+ };
+
struct ensure_started_t
{
- template <sender _Sender, class _Env = __empty_env>
+ template <sender _Sender, class _Env = empty_env>
requires(copy_constructible<remove_cvref_t<_Sender>> &&
sender_to<_Sender&, __receiver_t<_Sender, _Env>>) ||
__is_ensure_started_customized<_Sender, _Env>
@@ -4079,10 +4400,8 @@
(_Env &&) __env);
}
- // BUGBUG this will never match
- template <class _SenderId, class _EnvId>
- __t<__sender<_SenderId, _EnvId>>
- operator()(__t<__sender<_SenderId, _EnvId>> __sndr) const
+ template <__ensure_started_sender _Sender>
+ _Sender operator()(_Sender __sndr) const
{
return std::move(__sndr);
}
@@ -4214,26 +4533,28 @@
};
};
-template <class _SenderId, class _ReceiverId, class _Fun, class _Let>
+template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Let>
using __receiver = stdexec::__t<__gather_completions_for<
- _Let, __t<_SenderId>, env_of_t<__t<_ReceiverId>>, __q<__decayed_tuple>,
+ _Let, __cvref_t<_CvrefSenderId>, env_of_t<__t<_ReceiverId>>,
+ __q<__decayed_tuple>,
__munique<__mbind_front_q<__receiver_, _ReceiverId, _Fun, _Let>>>>;
-template <class _SenderId, class _ReceiverId, class _Fun, class _Let>
-using __operation_base =
- typename __receiver<_SenderId, _ReceiverId, _Fun, _Let>::__operation_base_t;
+template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Let>
+using __operation_base = typename __receiver<_CvrefSenderId, _ReceiverId, _Fun,
+ _Let>::__operation_base_t;
-template <class _SenderId, class _ReceiverId, class _Fun, class _Let>
+template <class _CvrefSenderId, class _ReceiverId, class _Fun, class _Let>
struct __operation
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _Sender = stdexec::__cvref_t<_CvrefSenderId>;
- struct __t : __operation_base<_SenderId, _ReceiverId, _Fun, _Let>
+ struct __t : __operation_base<_CvrefSenderId, _ReceiverId, _Fun, _Let>
{
using __id = __operation;
using __op_base_t =
- __operation_base<_SenderId, _ReceiverId, _Fun, _Let>;
- using __receiver_t = __receiver<_SenderId, _ReceiverId, _Fun, _Let>;
+ __operation_base<_CvrefSenderId, _ReceiverId, _Fun, _Let>;
+ using __receiver_t =
+ __receiver<_CvrefSenderId, _ReceiverId, _Fun, _Let>;
friend void tag_invoke(start_t, __t& __self) noexcept
{
@@ -4261,13 +4582,12 @@
using __id = __sender;
template <class _Self, class _Receiver>
- using __operation_t = stdexec::__t<
- __operation<stdexec::__id<__copy_cvref_t<_Self, _Sender>>,
- stdexec::__id<_Receiver>, _Fun, _Set>>;
+ using __operation_t =
+ stdexec::__t<__operation<stdexec::__cvref_id<_Self, _Sender>,
+ stdexec::__id<_Receiver>, _Fun, _Set>>;
template <class _Self, class _Receiver>
- using __receiver_t =
- __receiver<stdexec::__id<__copy_cvref_t<_Self, _Sender>>,
- stdexec::__id<_Receiver>, _Fun, _Set>;
+ using __receiver_t = __receiver<stdexec::__cvref_id<_Self, _Sender>,
+ stdexec::__id<_Receiver>, _Fun, _Set>;
template <class _Sender, class _Env>
using __completions = __mapply<
@@ -4286,16 +4606,11 @@
((_Self &&) __self).__fun_};
}
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return get_env(__self.__sndr_);
}
template <__decays_to<__t> _Self, class _Env>
@@ -4327,7 +4642,7 @@
_LetTag, __completion_scheduler_for<_Sender, set_value_t>,
_Sender, _Fun>)
{
- auto __sched = get_completion_scheduler<set_value_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_value_t>(get_env(__sndr));
return tag_invoke(_LetTag{}, std::move(__sched), (_Sender &&) __sndr,
(_Fun &&) __fun);
}
@@ -4377,13 +4692,13 @@
// [execution.senders.adaptors.stopped_as_error]
namespace __stopped_as_xxx
{
-template <class _SenderId, class _ReceiverId>
+template <class _CvrefSenderId, class _ReceiverId>
struct __operation;
-template <class _SenderId, class _ReceiverId>
+template <class _CvrefSenderId, class _ReceiverId>
struct __receiver
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _Sender = stdexec::__t<_CvrefSenderId>;
using _Receiver = stdexec::__t<_ReceiverId>;
struct __t : receiver_adaptor<__t>
@@ -4422,16 +4737,16 @@
std::optional<_Value>{std::nullopt});
}
- stdexec::__t<__operation<_SenderId, _ReceiverId>>* __op_;
+ stdexec::__t<__operation<_CvrefSenderId, _ReceiverId>>* __op_;
};
};
-template <class _SenderId, class _ReceiverId>
+template <class _CvrefSenderId, class _ReceiverId>
struct __operation
{
- using _Sender = stdexec::__t<_SenderId>;
+ using _Sender = stdexec::__t<_CvrefSenderId>;
using _Receiver = stdexec::__t<_ReceiverId>;
- using __receiver_t = stdexec::__t<__receiver<_SenderId, _ReceiverId>>;
+ using __receiver_t = stdexec::__t<__receiver<_CvrefSenderId, _ReceiverId>>;
struct __t
{
@@ -4462,13 +4777,13 @@
using __id = __sender;
template <class _Self, class _Receiver>
- using __operation_t = stdexec::__t<
- __operation<stdexec::__id<__copy_cvref_t<_Self, _Sender>>,
- stdexec::__id<_Receiver>>>;
+ using __operation_t =
+ stdexec::__t<__operation<stdexec::__cvref_id<_Self, _Sender>,
+ stdexec::__id<_Receiver>>>;
template <class _Self, class _Receiver>
- using __receiver_t = stdexec::__t<
- __receiver<stdexec::__id<__copy_cvref_t<_Self, _Sender>>,
- stdexec::__id<_Receiver>>>;
+ using __receiver_t =
+ stdexec::__t<__receiver<stdexec::__cvref_id<_Self, _Sender>,
+ stdexec::__id<_Receiver>>>;
template <__decays_to<__t> _Self, receiver _Receiver>
requires __single_typed_sender<__copy_cvref_t<_Self, _Sender>,
@@ -4482,16 +4797,11 @@
return {((_Self &&) __self).__sndr_, (_Receiver &&) __rcvr};
}
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return get_env(__self.__sndr_);
}
template <class... _Tys>
@@ -4665,12 +4975,22 @@
return {&__loop_->__head_, __loop_, (_Receiver &&) __rcvr};
}
- template <class _CPO>
- friend __scheduler
- tag_invoke(get_completion_scheduler_t<_CPO>,
- const __schedule_task& __self) noexcept
+ struct __env
{
- return __scheduler{__self.__loop_};
+ run_loop* __loop_;
+
+ template <class _CPO>
+ friend __scheduler tag_invoke(get_completion_scheduler_t<_CPO>,
+ const __env& __self) noexcept
+ {
+ return __scheduler{__self.__loop_};
+ }
+ };
+
+ friend __env tag_invoke(get_env_t,
+ const __schedule_task& __self) noexcept
+ {
+ return __env{__self.__loop_};
}
explicit __schedule_task(run_loop* __loop) noexcept :
@@ -4873,7 +5193,6 @@
struct __receiver1
{
using _Scheduler = stdexec::__t<_SchedulerId>;
- using _CvrefSender = stdexec::__t<_CvrefSenderId>;
using _Receiver = stdexec::__t<_ReceiverId>;
using __receiver2_t =
stdexec::__t<__receiver2<_SchedulerId, _CvrefSenderId, _ReceiverId>>;
@@ -4926,7 +5245,7 @@
struct __operation1
{
using _Scheduler = stdexec::__t<_SchedulerId>;
- using _CvrefSender = stdexec::__t<_CvrefSenderId>;
+ using _CvrefSender = stdexec::__cvref_t<_CvrefSenderId>;
using _Receiver = stdexec::__t<_ReceiverId>;
using __receiver1_t =
stdexec::__t<__receiver1<_SchedulerId, _CvrefSenderId, _ReceiverId>>;
@@ -4991,28 +5310,16 @@
__transform<__q<decay_t>,
__mcompose<__q<completion_signatures>, __qf<_Tag>>>;
-template <class _SchedulerId, class _SenderId>
-struct __sender
+template <class _SchedulerId>
+struct __env
{
using _Scheduler = stdexec::__t<_SchedulerId>;
- using _Sender = stdexec::__t<_SenderId>;
struct __t
{
- using __id = __sender;
- _Scheduler __sched_;
- _Sender __sndr_;
+ using __id = __env;
- template <__decays_to<__t> _Self, class _Receiver>
- requires sender_to<__copy_cvref_t<_Self, _Sender>, _Receiver>
- friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr)
- -> stdexec::__t<__operation1<
- _SchedulerId, stdexec::__id<__copy_cvref_t<_Self, _Sender>>,
- stdexec::__id<_Receiver>>>
- {
- return {__self.__sched_, ((_Self &&) __self).__sndr_,
- (_Receiver &&) __rcvr};
- }
+ _Scheduler __sched_;
template <__one_of<set_value_t, set_stopped_t> _Tag>
friend _Scheduler tag_invoke(get_completion_scheduler_t<_Tag>,
@@ -5020,17 +5327,36 @@
{
return __self.__sched_;
}
+ };
+};
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+template <class _SchedulerId, class _SenderId>
+struct __sender
+{
+ using _Scheduler = stdexec::__t<_SchedulerId>;
+ using _Sender = stdexec::__t<_SenderId>;
+ using _Attrs = stdexec::__t<__env<_SchedulerId>>;
+
+ struct __t
+ {
+ using __id = __sender;
+ _Attrs __env_;
+ _Sender __sndr_;
+
+ template <__decays_to<__t> _Self, class _Receiver>
+ requires sender_to<__copy_cvref_t<_Self, _Sender>, _Receiver>
+ friend auto tag_invoke(connect_t, _Self&& __self, _Receiver __rcvr)
+ -> stdexec::__t<
+ __operation1<_SchedulerId, stdexec::__cvref_id<_Self, _Sender>,
+ stdexec::__id<_Receiver>>>
{
- return ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return {__self.__env_.__sched_, ((_Self &&) __self).__sndr_,
+ (_Receiver &&) __rcvr};
+ }
+
+ friend const _Attrs& tag_invoke(get_env_t, const __t& __self) noexcept
+ {
+ return __self.__env_;
}
template <class... _Errs>
@@ -5074,7 +5400,7 @@
-> stdexec::__t<__sender<stdexec::__id<decay_t<_Scheduler>>,
stdexec::__id<decay_t<_Sender>>>>
{
- return {(_Scheduler &&) __sched, (_Sender &&) __sndr};
+ return {{(_Scheduler &&) __sched}, (_Sender &&) __sndr};
}
};
} // namespace __schedule_from
@@ -5098,7 +5424,7 @@
transfer_t, __completion_scheduler_for<_Sender, set_value_t>,
_Sender, _Scheduler>)
{
- auto csch = get_completion_scheduler<set_value_t>(__sndr);
+ auto csch = get_completion_scheduler<set_value_t>(get_env(__sndr));
return tag_invoke(transfer_t{}, std::move(csch), (_Sender &&) __sndr,
(_Scheduler &&) __sched);
}
@@ -5240,10 +5566,10 @@
__t(_Scheduler __sched, _Sender2&& __sndr, _Receiver2&& __rcvr) :
__scheduler_((_Scheduler &&) __sched),
__sndr_((_Sender2 &&) __sndr), __rcvr_((_Receiver2 &&) __rcvr),
- __data_{
- std::in_place_index<0>, __conv{[&, this] {
- return connect(schedule(__sched), __receiver_t{{}, this});
- }}}
+ __data_{std::in_place_index<0>, __conv{[this] {
+ return connect(schedule(__scheduler_),
+ __receiver_t{{}, this});
+ }}}
{}
STDEXEC_IMMOVABLE(__t);
@@ -5294,16 +5620,11 @@
((_Self &&) __self).__sndr_, (_Receiver &&) __rcvr};
}
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return get_env(__self.__sndr_);
}
template <class...>
@@ -5470,16 +5791,11 @@
__receiver_t<_Receiver>{(_Receiver &&) __rcvr});
}
- template <tag_category<forwarding_sender_query> _Tag, class... _As>
- requires __callable<_Tag, const _Sender&, _As...>
- friend auto tag_invoke(
- _Tag __tag, const __t& __self,
- _As&&... __as) noexcept(__nothrow_callable<_Tag, const _Sender&,
- _As...>)
- -> __call_result_if_t<tag_category<_Tag, forwarding_sender_query>,
- _Tag, const _Sender&, _As...>
+ 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 ((_Tag &&) __tag)(__self.__sndr_, (_As &&) __as...);
+ return get_env(__self.__sndr_);
}
template <class _Env>
@@ -5688,6 +6004,11 @@
struct __receiver
{
using _Receiver = stdexec::__t<_ReceiverId>;
+ template <class _Tuple>
+ using __tuple_type =
+ typename std::tuple_element_t<_Index, _Tuple>::value_type;
+ using _TupleType =
+ __minvoke<__with_default<__q<__tuple_type>, __ignore>, _ValuesTuple>;
struct __t
{
@@ -5714,14 +6035,13 @@
}
}
template <class... _Values>
+ requires same_as<_ValuesTuple, __ignore> ||
+ constructible_from<_TupleType, _Values...>
friend void tag_invoke(set_value_t, __t&& __self,
_Values&&... __vals) noexcept
{
if constexpr (!same_as<_ValuesTuple, __ignore>)
{
- using _TupleType =
- typename std::tuple_element_t<_Index,
- _ValuesTuple>::value_type;
static_assert(
same_as<_TupleType, std::tuple<decay_t<_Values>...>>,
"One of the senders in this when_all() is fibbing about what types it sends");
@@ -5743,6 +6063,10 @@
__self.__op_state_->__arrive();
}
template <class _Error>
+ requires requires(_ErrorsVariant& __errors, _Error&& __err) {
+ __errors.template emplace<decay_t<_Error>>((_Error &&)
+ __err);
+ }
friend void tag_invoke(set_error_t, __t&& __self,
_Error&& __err) noexcept
{
@@ -5750,6 +6074,8 @@
__self.__op_state_->__arrive();
}
friend void tag_invoke(set_stopped_t, __t&& __self) noexcept
+ requires receiver_of<_Receiver,
+ completion_signatures<set_stopped_t()>>
{
__state_t __expected = __started;
// Transition to the "stopped" state if and only if we're in the
@@ -5817,21 +6143,32 @@
template <class _Sender, class _Index>
using __op_state = connect_result_t<_Sender, __receiver<__v<_Index>>>;
+ template <class _Tuple = __q<std::tuple>>
using __op_states_tuple =
- __minvoke<__mzip_with2<__q<__op_state>, __q<std::tuple>>,
- __types<_Senders...>, __mindex_sequence_for<_Senders...>>;
+ __minvoke<__mzip_with2<__q<__op_state>, _Tuple>, __types<_Senders...>,
+ __mindex_sequence_for<_Senders...>>;
};
template <class _Cvref, class _ReceiverId, class... _SenderIds>
+using __traits_ex =
+ __traits<__t<_ReceiverId>, __minvoke<_Cvref, __t<_SenderIds>>...>;
+
+template <class _Cvref, class _ReceiverId, class... _SenderIds>
+using __op_states_tuple_ex =
+ typename __traits_ex<_Cvref, _ReceiverId,
+ _SenderIds...>::template __op_states_tuple<>;
+
+template <class _Cvref, class _ReceiverId, class... _SenderIds>
+ requires __valid<__op_states_tuple_ex, _Cvref, _ReceiverId, _SenderIds...>
struct __operation
{
using _Receiver = stdexec::__t<_ReceiverId>;
- using _Traits =
- __traits<_Receiver, __minvoke<_Cvref, stdexec::__t<_SenderIds>>...>;
+ using _Traits = __traits_ex<_Cvref, _ReceiverId, _SenderIds...>;
using _Indices = std::index_sequence_for<_SenderIds...>;
using __operation_base_t = typename _Traits::__operation_base;
- using __op_states_tuple_t = typename _Traits::__op_states_tuple;
+ using __op_states_tuple_t =
+ __op_states_tuple_ex<_Cvref, _ReceiverId, _SenderIds...>;
template <std::size_t _Index>
using __receiver_t = typename _Traits::template __receiver<_Index>;
@@ -5937,6 +6274,11 @@
-> __completions_t<_Self, _Env>
requires true;
+ friend empty_env tag_invoke(get_env_t, const __t& __self) noexcept
+ {
+ return {};
+ }
+
std::tuple<stdexec::__t<_SenderIds>...> __sndrs_;
};
};
@@ -6106,6 +6448,11 @@
template <__none_of<no_env> _Env>
friend auto tag_invoke(get_completion_signatures_t, __sender, _Env)
-> __completions_t<_Env>;
+
+ friend empty_env tag_invoke(get_env_t, const __t& __self) noexcept
+ {
+ return {};
+ }
};
struct __read_t
@@ -6266,7 +6613,7 @@
sync_wait_t, __completion_scheduler_for<_Sender, set_value_t>,
_Sender>)
{
- auto __sched = get_completion_scheduler<set_value_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_value_t>(get_env(__sndr));
return tag_invoke(sync_wait_t{}, std::move(__sched),
(_Sender &&) __sndr);
}
@@ -6338,7 +6685,7 @@
"The type of tag_invoke(sync_wait_with_variant, get_completion_scheduler, S) "
"must be sync-wait-with-variant-type<S, sync-wait-env>");
- auto __sched = get_completion_scheduler<set_value_t>(__sndr);
+ auto __sched = get_completion_scheduler<set_value_t>(get_env(__sndr));
return tag_invoke(sync_wait_with_variant_t{}, std::move(__sched),
(_Sender &&) __sndr);
}
diff --git a/include/sdbusplus/async/stdexec/functional.hpp b/include/sdbusplus/async/stdexec/functional.hpp
index 6893e6f..c023f47 100644
--- a/include/sdbusplus/async/stdexec/functional.hpp
+++ b/include/sdbusplus/async/stdexec/functional.hpp
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "__detail/__config.hpp"
#include "__detail/__meta.hpp"
#include "concepts.hpp"
@@ -108,7 +109,9 @@
{
template <class _Tag, class... _Args>
requires tag_invocable<_Tag, _Args...>
- constexpr auto operator()(_Tag __tag, _Args&&... __args) const
+ STDEXEC_DETAIL_CUDACC_HOST_DEVICE //
+ constexpr auto
+ operator()(_Tag __tag, _Args&&... __args) const
noexcept(nothrow_tag_invocable<_Tag, _Args...>)
-> tag_invoke_result_t<_Tag, _Args...>
{
diff --git a/include/sdbusplus/async/stdexec/task.hpp b/include/sdbusplus/async/stdexec/task.hpp
index 9bd59e9..a5066cd 100644
--- a/include/sdbusplus/async/stdexec/task.hpp
+++ b/include/sdbusplus/async/stdexec/task.hpp
@@ -263,7 +263,7 @@
static __coro::coroutine_handle<>
await_suspend(__coro::coroutine_handle<__promise> __h) noexcept
{
- return __h.promise().continuation();
+ return __h.promise().continuation().handle();
}
static void await_resume() noexcept {}
};