diff --git a/docs/overview.md b/docs/overview.md
index 6b093f6b..b6a98020 100644
--- a/docs/overview.md
+++ b/docs/overview.md
@@ -640,11 +640,11 @@ The expression schedule(scheduler) creates a sender which up
The sender adaptors take one or more senders and adapt their respective behavior to complete with a corresponding result. The description uses the informal function completions-of(sender) to represent the completion signatures which sender produces. Also, completion signatures are combined using +: the result is the deduplicated set of the combined completion signatures.
-affine_on(sender) -> sender-of<completions-of(sender)>
-The expression affine_on(sender) creates
+affine(sender) -> sender-of<completions-of(sender)>
+The expression affine(sender) creates
a sender which completes on the same scheduler it was started on, even if sender changes the scheduler. The scheduler to resume on is determined using get_scheduler(get_env(rcvr)) where rcvr is the receiver the sender is connected to.
-The primary use of affine_on is implementing scheduler affinity for task.
+The primary use of affine is implementing scheduler affinity for task.
`bulk`
diff --git a/include/beman/execution/detail/affine.hpp b/include/beman/execution/detail/affine.hpp
new file mode 100644
index 00000000..7b3be2fe
--- /dev/null
+++ b/include/beman/execution/detail/affine.hpp
@@ -0,0 +1,187 @@
+// include/beman/execution/detail/affine.hpp -*-C++-*-
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_AFFINE
+#define INCLUDED_BEMAN_EXECUTION_DETAIL_AFFINE
+
+#include
+#include
+#ifdef BEMAN_HAS_IMPORT_STD
+import std;
+#else
+#include
+#include
+#include
+#endif
+#ifdef BEMAN_HAS_MODULES
+import beman.execution.detail.basic_sender;
+import beman.execution.detail.continues_on;
+import beman.execution.detail.env;
+import beman.execution.detail.forward_like;
+import beman.execution.detail.get_completion_signatures;
+import beman.execution.detail.get_start_scheduler;
+import beman.execution.detail.infallible_scheduler;
+import beman.execution.detail.make_sender;
+import beman.execution.detail.nested_sender_has_affine;
+import beman.execution.detail.schedule;
+import beman.execution.detail.scheduler;
+import beman.execution.detail.sender;
+import beman.execution.detail.sender_adaptor_closure;
+import beman.execution.detail.sender_for;
+import beman.execution.detail.set_value;
+import beman.execution.detail.store_receiver;
+import beman.execution.detail.unstoppable;
+#else
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace beman::execution::detail {
+template
+struct unstoppable_scheduler {
+ using scheduler_concept = typename Sched::scheduler_concept;
+
+ template
+ requires requires { ::std::declval().query(::std::declval(), ::std::declval()...); }
+ auto query(const Q& q, Args&&... args) const noexcept -> decltype(auto) {
+ return sched.query(q, ::std::forward(args)...);
+ }
+
+ auto schedule() const noexcept(std::is_nothrow_invocable_v<::beman::execution::schedule_t, Sched>) {
+ return ::beman::execution::unstoppable(::beman::execution::schedule(sched));
+ }
+
+ friend auto operator==(const unstoppable_scheduler& lhs, const unstoppable_scheduler& rhs) -> bool = default;
+
+ Sched sched;
+};
+
+/**
+ * @brief The affine_t struct is a sender adaptor closure that transforms a sender
+ * to complete on the scheduler obtained from the receiver's environment.
+ *
+ * This adaptor implements scheduler affinity to adapt a sender to complete on the
+ * scheduler obtained the receiver's environment. The get_start_scheduler query is used
+ * to obtain the scheduler on which the sender gets started.
+ */
+struct affine_t : ::beman::execution::sender_adaptor_closure {
+ /**
+ * @brief Adapt a sender with affine.
+ *
+ * @tparam Sender The deduced type of the sender to be transformed.
+ * @param sender The sender to be transformed.
+ * @return An adapted sender to complete on the scheduler it was started on.
+ */
+ template <::beman::execution::sender Sender>
+ auto operator()(Sender&& sender) const {
+ return ::beman::execution::detail::make_sender(
+ *this, ::beman::execution::env<>{}, ::std::forward(sender));
+ }
+
+ /**
+ * @brief Overload for creating a sender adaptor from affine.
+ *
+ * @return A sender adaptor for the affine_t.
+ */
+ auto operator()() const { return ::beman::execution::detail::make_sender_adaptor(*this); }
+
+ /**
+ * @brief affine is implemented by transforming it into a use of continues_on.
+ *
+ * The constraints ensure that the environment provides a scheduler which is
+ * infallible and, thus, can be used to guarantee completion on the correct
+ * scheduler.
+ *
+ * The implementation first tries to see if the child sender's tag has a custom
+ * affine implementation. If it does, that is used. Otherwise, the default
+ * implementation gets a scheduler from the environment and uses continues_on
+ * to adapt the sender to complete on that scheduler.
+ *
+ * @tparam Sender The type of the sender to be transformed.
+ * @tparam Env The type of the environment providing the scheduler.
+ * @param sender The sender to be transformed.
+ * @param env The environment providing the scheduler.
+ * @return A transformed sender that is affined to the scheduler.
+ */
+ template <::beman::execution::detail::sender_for Sender, typename Env>
+ static auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env& env) {
+ auto& child = sender.template get<2>();
+ if constexpr (::beman::execution::detail::nested_sender_has_affine) {
+ return ::beman::execution::detail::forward_like(child).affine();
+ } else {
+ static_assert(
+ requires {
+ {
+ ::beman::execution::get_start_scheduler(::std::declval())
+ } -> ::beman::execution::detail::infallible_scheduler;
+ },
+ "the result type of querying `get_start_scheduler` on an `Env` shall be a scheduler type whose "
+ "schedule asynchronous operation can only complete with set_value unless stop can be requested");
+ return ::beman::execution::continues_on(
+ ::beman::execution::detail::forward_like(child),
+ ::beman::execution::detail::unstoppable_scheduler{::beman::execution::get_start_scheduler(env)});
+ }
+ }
+ template
+ struct get_signatures;
+
+ template
+ struct get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::affine_t, Data, Child>,
+ Env> {
+ static consteval auto get() {
+ if constexpr (!requires {
+ {
+ ::beman::execution::get_start_scheduler(::std::declval())
+ } -> ::beman::execution::detail::infallible_scheduler;
+ }) {
+ throw ::beman::execution::detail::infallible_scheduler_error{};
+ }
+ return ::beman::execution::get_completion_signatures();
+ }
+ };
+
+ template
+ struct get_signatures<
+ ::beman::execution::detail::basic_sender<::beman::execution::detail::affine_t, Data, Child>> {
+ static consteval auto get() { return ::beman::execution::get_completion_signatures(); }
+ };
+
+ template
+ static consteval auto get_completion_signatures() {
+ return get_signatures<::std::remove_cvref_t, Env...>::get();
+ }
+};
+
+} // namespace beman::execution::detail
+
+namespace beman::execution {
+/**
+ * @brief affine is a CPO, used to adapt a sender to complete on the scheduler
+ * it got started on which is derived from get_start_scheduler on the receiver's environment.
+ */
+using affine_t = beman::execution::detail::affine_t;
+inline constexpr beman::execution::detail::affine_t affine{};
+} // namespace beman::execution
+
+// ----------------------------------------------------------------------------
+
+#include
+
+#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_AFFINE
diff --git a/include/beman/execution/detail/affine_on.hpp b/include/beman/execution/detail/affine_on.hpp
deleted file mode 100644
index b154ab57..00000000
--- a/include/beman/execution/detail/affine_on.hpp
+++ /dev/null
@@ -1,194 +0,0 @@
-// include/beman/execution/detail/affine_on.hpp -*-C++-*-
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_AFFINE_ON
-#define INCLUDED_BEMAN_EXECUTION_DETAIL_AFFINE_ON
-
-#include
-#include
-#ifdef BEMAN_HAS_IMPORT_STD
-import std;
-#else
-#include
-#include
-#include
-#endif
-#ifdef BEMAN_HAS_MODULES
-import beman.execution.detail.basic_sender;
-import beman.execution.detail.completion_signatures;
-import beman.execution.detail.completion_signatures_of_t;
-import beman.execution.detail.continues_on;
-import beman.execution.detail.env;
-import beman.execution.detail.forward_like;
-import beman.execution.detail.fwd_env;
-import beman.execution.detail.get_completion_signatures;
-import beman.execution.detail.get_scheduler;
-import beman.execution.detail.get_stop_token;
-import beman.execution.detail.make_sender;
-import beman.execution.detail.never_stop_token;
-import beman.execution.detail.nested_sender_has_affine_on;
-import beman.execution.detail.prop;
-import beman.execution.detail.schedule;
-import beman.execution.detail.schedule_from;
-import beman.execution.detail.scheduler;
-import beman.execution.detail.sender;
-import beman.execution.detail.sender_adaptor_closure;
-import beman.execution.detail.sender_for;
-import beman.execution.detail.sender_has_affine_on;
-import beman.execution.detail.set_value;
-import beman.execution.detail.store_receiver;
-import beman.execution.detail.tag_of_t;
-import beman.execution.detail.unstoppable;
-import beman.execution.detail.write_env;
-#else
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#endif
-
-// ----------------------------------------------------------------------------
-
-namespace beman::execution::detail {
-template
-struct affine_on_env {
- Ev ev_;
- auto query(const ::beman::execution::get_stop_token_t&) const noexcept -> ::beman::execution::never_stop_token {
- return ::beman::execution::never_stop_token();
- }
- template
- auto query(const Q& q) const noexcept -> decltype(q(this->ev_)) {
- return q(this->ev_);
- }
-};
-template
-affine_on_env(const Ev&) -> affine_on_env;
-
-/**
- * @brief The affine_on_t struct is a sender adaptor closure that transforms a sender
- * to complete on the scheduler obtained from the receiver's environment.
- *
- * This adaptor implements scheduler affinity to adapt a sender to complete on the
- * scheduler obtained the receiver's environment. The get_scheduler query is used
- * to obtain the scheduler on which the sender gets started.
- */
-struct affine_on_t : ::beman::execution::sender_adaptor_closure {
- /**
- * @brief Adapt a sender with affine_on.
- *
- * @tparam Sender The deduced type of the sender to be transformed.
- * @param sender The sender to be transformed.
- * @return An adapted sender to complete on the scheduler it was started on.
- */
- template <::beman::execution::sender Sender>
- auto operator()(Sender&& sender) const {
- return ::beman::execution::detail::make_sender(
- *this, ::beman::execution::env<>{}, ::std::forward(sender));
- }
-
- /**
- * @brief Overload for creating a sender adaptor from affine_on.
- *
- * @return A sender adaptor for the affine_on_t.
- */
- auto operator()() const { return ::beman::execution::detail::make_sender_adaptor(*this); }
-
- /**
- * @brief affine_on is implemented by transforming it into a use of schedule_from.
- *
- * The constraints ensure that the environment provides a scheduler which is
- * infallible and, thus, can be used to guarantee completion on the correct
- * scheduler.
- *
- * The implementation first tries to see if the child sender's tag has a custom
- * affine_on implementation. If it does, that is used. Otherwise, the default
- * implementation gets a scheduler from the environment and uses schedule_from
- * to adapt the sender to complete on that scheduler.
- *
- * @tparam Sender The type of the sender to be transformed.
- * @tparam Env The type of the environment providing the scheduler.
- * @param sender The sender to be transformed.
- * @param env The environment providing the scheduler.
- * @return A transformed sender that is affined to the scheduler.
- */
- template <::beman::execution::sender Sender, typename Env>
- requires ::beman::execution::detail::sender_for && requires(const Env& env) {
- { ::beman::execution::get_scheduler(env) } -> ::beman::execution::scheduler;
- { ::beman::execution::schedule(::beman::execution::get_scheduler(env)) } -> ::beman::execution::sender;
- }
- static auto transform_sender(::beman::execution::set_value_t, Sender&& sender, const Env& ev) {
- static_assert(requires {
- {
- ::beman::execution::get_completion_signatures()
- } //-dk:TODO ->
- //::std::same_as<::beman::execution::completion_signatures<::beman::execution::set_value_t()>>
- ;
- });
- //[[maybe_unused]] auto& [tag, data, child] = sender;
- auto& child = sender.template get<2>();
- using child_tag_t = ::beman::execution::tag_of_t<::std::remove_cvref_t>;
-
- if constexpr (::beman::execution::detail::nested_sender_has_affine_on) {
- constexpr child_tag_t t{};
- return t.affine_on(::beman::execution::detail::forward_like(child), ev);
- } else {
- return ::beman::execution::detail::store_receiver(
- ::beman::execution::detail::forward_like(child),
- [](Child&& child, const auto& ev) {
- return ::beman::execution::unstoppable(::beman::execution::continues_on(
- ::beman::execution::write_env(::std::forward(child), ev),
- ::beman::execution::get_scheduler(ev)));
- });
- }
- }
- template
- struct get_signatures;
-
- template
- struct get_signatures<
- ::beman::execution::detail::basic_sender<::beman::execution::detail::affine_on_t, Data, Child>,
- Env...> {
- using type = ::beman::execution::completion_signatures_of_t;
- };
-
- template
- static consteval auto get_completion_signatures() {
- return typename get_signatures<::std::remove_cvref_t, Env...>::type{};
- }
-};
-
-} // namespace beman::execution::detail
-
-namespace beman::execution {
-/**
- * @brief affine_on is a CPO, used to adapt a sender to complete on the scheduler
- * it got started on which is derived from get_scheduler on the receiver's environment.
- */
-using affine_on_t = beman::execution::detail::affine_on_t;
-inline constexpr affine_on_t affine_on{};
-} // namespace beman::execution
-
-// ----------------------------------------------------------------------------
-
-#include
-
-#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_AFFINE_ON
diff --git a/include/beman/execution/detail/as_awaitable.hpp b/include/beman/execution/detail/as_awaitable.hpp
index 40470efd..c55571aa 100644
--- a/include/beman/execution/detail/as_awaitable.hpp
+++ b/include/beman/execution/detail/as_awaitable.hpp
@@ -14,27 +14,68 @@ import std;
#include
#endif
#ifdef BEMAN_HAS_MODULES
-import beman.execution.detail.awaitable_sender;
+import beman.execution.detail.env_of_t;
import beman.execution.detail.get_await_completion_adaptor;
+import beman.execution.detail.get_awaiter;
import beman.execution.detail.get_env;
import beman.execution.detail.query_with_default;
import beman.execution.detail.is_awaitable;
-import beman.execution.detail.sender;
+import beman.execution.detail.is_awaiter;
import beman.execution.detail.sender_awaitable;
-import beman.execution.detail.unspecified_promise;
+import beman.execution.detail.single_sender;
+import beman.execution.detail.transform_sender;
#else
-#include
+#include
#include
+#include
#include
#include
#include
-#include
+#include
#include
-#include
+#include
+#include
#endif
// ----------------------------------------------------------------------------
+namespace beman::execution::detail {
+template
+auto adapt_for_await_completion(Sndr&& sndr) {
+ auto adaptor = ::beman::execution::detail::query_with_default(
+ ::beman::execution::get_await_completion_adaptor, ::beman::execution::get_env(sndr), ::std::identity{});
+ return adaptor(::std::forward(sndr));
+}
+
+template
+auto transform_and_adapt_for_await_completion(Expr&& expr, Promise& promise) {
+ auto sndr = ::beman::execution::transform_sender(::std::forward(expr), ::beman::execution::get_env(promise));
+ return ::beman::execution::detail::adapt_for_await_completion(::std::move(sndr));
+}
+
+template
+using await_completion_sender_t = decltype(::beman::execution::detail::transform_and_adapt_for_await_completion(
+ ::std::declval(), ::std::declval()));
+
+template
+concept await_completion_sender =
+ ::beman::execution::detail::single_sender> &&
+ requires { typename ::beman::execution::detail::await_completion_sender_t; };
+
+template
+concept has_await_completion_as_awaitable =
+ ::beman::execution::detail::await_completion_sender && requires(Promise& promise) {
+ ::std::declval<::beman::execution::detail::await_completion_sender_t>().as_awaitable(promise);
+ };
+
+template
+concept directly_awaitable = requires {
+ {
+ ::beman::execution::detail::get_awaiter(::std::declval())
+ } -> ::beman::execution::detail::is_awaiter;
+};
+} // namespace beman::execution::detail
+
namespace beman::execution {
/*!
* \brief Turn an entity, e.g., a sender, into an awaitable.
@@ -49,25 +90,23 @@ struct as_awaitable_t {
Promise>,
"as_awaitable must return an awaitable");
return ::std::forward(expr).as_awaitable(promise);
- } else if constexpr (::beman::execution::sender &&
- !::beman::execution::detail::
- is_awaitable) {
- auto adaptor =
- ::beman::execution::detail::query_with_default(::beman::execution::get_await_completion_adaptor,
- ::beman::execution::get_env(expr),
- ::std::identity{});
- using sender_tag = ::std::invoke_result_t;
- if constexpr (::beman::execution::detail::awaitable_sender) {
- return ::beman::execution::detail::sender_awaitable{
- adaptor(::std::forward(expr)), promise};
- } else if constexpr (::beman::execution::detail::awaitable_sender) {
- return ::beman::execution::detail::sender_awaitable{::std::forward(expr),
- promise};
- } else {
- return ::std::forward(expr);
- }
+ } else if constexpr (::beman::execution::detail::has_await_completion_as_awaitable) {
+ using result_t =
+ decltype(::std::declval<::beman::execution::detail::await_completion_sender_t>()
+ .as_awaitable(::std::declval()));
+ static_assert(::beman::execution::detail::is_awaitable,
+ "as_awaitable must return an awaitable");
+ auto sndr = ::beman::execution::detail::transform_and_adapt_for_await_completion(
+ ::std::forward(expr), promise);
+ return ::std::move(sndr).as_awaitable(promise);
+ } else if constexpr (::beman::execution::detail::directly_awaitable) {
+ return (static_cast(promise), ::std::forward(expr));
+ } else if constexpr (::beman::execution::detail::await_completion_sender) {
+ auto sndr = ::beman::execution::detail::transform_and_adapt_for_await_completion(
+ ::std::forward(expr), promise);
+ return ::beman::execution::detail::sender_awaitable{::std::move(sndr), promise};
} else {
- return ::std::forward(expr);
+ return (static_cast(promise), ::std::forward(expr));
}
}
};
diff --git a/include/beman/execution/detail/basic_sender.hpp b/include/beman/execution/detail/basic_sender.hpp
index 028c0b21..a013a89b 100644
--- a/include/beman/execution/detail/basic_sender.hpp
+++ b/include/beman/execution/detail/basic_sender.hpp
@@ -120,6 +120,12 @@ struct basic_sender : ::beman::execution::detail::product_type{};
}
+
+ template <::beman::execution::detail::decays_to Self>
+ requires requires { Tag().affine(::std::declval()); }
+ auto affine(this Self&& self) noexcept(noexcept(Tag().affine(::std::declval()))) -> decltype(auto) {
+ return Tag().affine(::std::forward(self));
+ }
};
} // namespace beman::execution::detail
diff --git a/include/beman/execution/detail/counting_scope_join.hpp b/include/beman/execution/detail/counting_scope_join.hpp
index a7059da3..cd8f9f68 100644
--- a/include/beman/execution/detail/counting_scope_join.hpp
+++ b/include/beman/execution/detail/counting_scope_join.hpp
@@ -19,7 +19,7 @@ import beman.execution.detail.connect;
import beman.execution.detail.counting_scope_base;
import beman.execution.detail.default_impls;
import beman.execution.detail.get_env;
-import beman.execution.detail.get_scheduler;
+import beman.execution.detail.get_start_scheduler;
import beman.execution.detail.impls_for;
import beman.execution.detail.make_sender;
import beman.execution.detail.receiver;
@@ -35,7 +35,7 @@ import beman.execution.detail.start;
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -103,15 +103,16 @@ struct beman::execution::detail::counting_scope_join_t::state : ::beman::executi
Receiver& rcvr;
};
- using op_t = decltype(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
- ::beman::execution::get_env(::std::declval()))),
- ::std::declval()));
+ using op_t =
+ decltype(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_start_scheduler(
+ ::beman::execution::get_env(::std::declval()))),
+ ::std::declval()));
::beman::execution::detail::counting_scope_base* scope;
explicit state(::beman::execution::detail::counting_scope_base* s, Receiver& r)
: scope(s),
receiver(r),
- op(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
+ op(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_start_scheduler(
::beman::execution::get_env(this->receiver))),
receiver_ref(this->receiver))) {}
virtual ~state() = default;
diff --git a/include/beman/execution/detail/get_start_scheduler.hpp b/include/beman/execution/detail/get_start_scheduler.hpp
new file mode 100644
index 00000000..3fae8532
--- /dev/null
+++ b/include/beman/execution/detail/get_start_scheduler.hpp
@@ -0,0 +1,35 @@
+// include/beman/execution/detail/get_start_scheduler.hpp -*-C++-*-
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_GET_START_SCHEDULER
+#define INCLUDED_BEMAN_EXECUTION_DETAIL_GET_START_SCHEDULER
+
+#include
+#ifdef BEMAN_HAS_IMPORT_STD
+import std;
+#else
+#include
+#endif
+#ifdef BEMAN_HAS_MODULES
+import beman.execution.detail.forwarding_query;
+#else
+#include
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace beman::execution {
+struct get_start_scheduler_t : ::beman::execution::forwarding_query_t {
+ template
+ requires requires(const get_start_scheduler_t& self, const Env& env) { env.query(self); }
+ auto operator()(const Env& env) const noexcept {
+ return env.query(*this);
+ }
+};
+
+inline constexpr get_start_scheduler_t get_start_scheduler{};
+} // namespace beman::execution
+
+// ----------------------------------------------------------------------------
+
+#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_GET_START_SCHEDULER
diff --git a/include/beman/execution/detail/infallible_scheduler.hpp b/include/beman/execution/detail/infallible_scheduler.hpp
new file mode 100644
index 00000000..2f2a387e
--- /dev/null
+++ b/include/beman/execution/detail/infallible_scheduler.hpp
@@ -0,0 +1,69 @@
+// include/beman/execution/detail/infallible_scheduler.hpp -*-C++-*-
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_INFALLIBLE_SCHEDULER
+#define INCLUDED_BEMAN_EXECUTION_DETAIL_INFALLIBLE_SCHEDULER
+
+#include
+
+#ifdef BEMAN_HAS_IMPORT_STD
+import std;
+#else
+#include
+#include
+#endif
+#ifdef BEMAN_HAS_MODULES
+import beman.execution.detail.completion_signatures;
+import beman.execution.detail.completion_signatures_of_t;
+import beman.execution.detail.scheduler;
+import beman.execution.detail.schedule_result_t;
+import beman.execution.detail.set_stopped;
+import beman.execution.detail.set_value;
+import beman.execution.detail.stop_token_of_t;
+import beman.execution.detail.unstoppable_token;
+#else
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+// ----------------------------------------------------------------------------
+
+namespace beman::execution::detail {
+
+template
+struct infallible_scheduler_error : ::std::exception {
+ auto what() const noexcept -> const char* override {
+ using _ [[maybe_unused]] = Env;
+ return "the result type of querying `get_start_scheduler` on an `Env` shall be a scheduler type whose "
+ "schedule "
+ "asynchronous operation can only complete with set_value unless stop can be requested";
+ }
+};
+
+template
+concept infallible_scheduler =
+ ::beman::execution::scheduler &&
+ (::std::same_as<
+ ::beman::execution::completion_signatures<::beman::execution::set_value_t()>,
+ ::beman::execution::completion_signatures_of_t<::beman::execution::schedule_result_t, Env>> ||
+ (!::beman::execution::unstoppable_token<::beman::execution::stop_token_of_t> &&
+ (::std::same_as<
+ ::beman::execution::completion_signatures<::beman::execution::set_value_t(),
+ ::beman::execution::set_stopped_t()>,
+ ::beman::execution::completion_signatures_of_t<::beman::execution::schedule_result_t, Env>> ||
+ ::std::same_as<
+ ::beman::execution::completion_signatures<::beman::execution::set_stopped_t(),
+ ::beman::execution::set_value_t()>,
+ ::beman::execution::completion_signatures_of_t<::beman::execution::schedule_result_t, Env>>)));
+
+} // namespace beman::execution::detail
+
+// ----------------------------------------------------------------------------
+
+#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_INFALLIBLE_SCHEDULER
diff --git a/include/beman/execution/detail/just.hpp b/include/beman/execution/detail/just.hpp
index 3a734e5a..b1fb576c 100644
--- a/include/beman/execution/detail/just.hpp
+++ b/include/beman/execution/detail/just.hpp
@@ -56,8 +56,9 @@ struct just_t {
return ::beman::execution::detail::make_sender(
*this, ::beman::execution::detail::product_type{::std::forward(arg)...});
}
+
template <::beman::execution::sender Sender>
- static auto affine_on(Sender&& sndr, const auto&) noexcept {
+ static auto affine(Sender&& sndr) noexcept {
return ::std::forward(sndr);
}
diff --git a/include/beman/execution/detail/nested_sender_has_affine_on.hpp b/include/beman/execution/detail/nested_sender_has_affine.hpp
similarity index 64%
rename from include/beman/execution/detail/nested_sender_has_affine_on.hpp
rename to include/beman/execution/detail/nested_sender_has_affine.hpp
index 6a9c123d..22abe955 100644
--- a/include/beman/execution/detail/nested_sender_has_affine_on.hpp
+++ b/include/beman/execution/detail/nested_sender_has_affine.hpp
@@ -1,25 +1,25 @@
-// include/beman/execution/detail/nested_sender_has_affine_on.hpp -*-C++-*-
+// include/beman/execution/detail/nested_sender_has_affine.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_NESTED_SENDER_HAS_AFFINE_ON
-#define INCLUDED_BEMAN_EXECUTION_DETAIL_NESTED_SENDER_HAS_AFFINE_ON
+#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_NESTED_SENDER_HAS_AFFINE
+#define INCLUDED_BEMAN_EXECUTION_DETAIL_NESTED_SENDER_HAS_AFFINE
#include
#ifdef BEMAN_HAS_MODULES
-import beman.execution.detail.sender_has_affine_on;
+import beman.execution.detail.sender_has_affine;
#else
-#include
+#include
#endif
// ----------------------------------------------------------------------------
namespace beman::execution::detail {
-template
-concept nested_sender_has_affine_on = requires(Sender&& sndr, const Env& env) {
- { sndr.template get<2>() } -> ::beman::execution::detail::sender_has_affine_on;
+template
+concept nested_sender_has_affine = requires(Sender&& sndr) {
+ { sndr.template get<2>() } -> ::beman::execution::detail::sender_has_affine;
};
} // namespace beman::execution::detail
// ----------------------------------------------------------------------------
-#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_NESTED_SENDER_HAS_AFFINE_ON
+#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_NESTED_SENDER_HAS_AFFINE
diff --git a/include/beman/execution/detail/on.hpp b/include/beman/execution/detail/on.hpp
index ee919772..d737eb75 100644
--- a/include/beman/execution/detail/on.hpp
+++ b/include/beman/execution/detail/on.hpp
@@ -20,7 +20,7 @@ import beman.execution.detail.fwd_env;
import beman.execution.detail.get_completion_scheduler;
import beman.execution.detail.get_domain;
import beman.execution.detail.get_env;
-import beman.execution.detail.get_scheduler;
+import beman.execution.detail.get_start_scheduler;
import beman.execution.detail.join_env;
import beman.execution.detail.make_sender;
import beman.execution.detail.product_type;
@@ -39,6 +39,7 @@ import beman.execution.detail.transform_sender;
#include
#include
#include
+#include
#include
#include
#include
@@ -57,11 +58,11 @@ import beman.execution.detail.transform_sender;
namespace beman::execution::detail {
struct on_t : ::beman::execution::sender_adaptor_closure {
template
- struct env_needs_get_scheduler {
+ struct env_needs_get_start_scheduler {
using sender_concept = ::beman::execution::sender_tag;
template
static constexpr auto get_completion_signatures() {
- return env_needs_get_scheduler{};
+ return env_needs_get_start_scheduler{};
}
};
@@ -74,9 +75,9 @@ struct on_t : ::beman::execution::sender_adaptor_closure {
if constexpr (::beman::execution::scheduler) {
auto sch{::beman::execution::detail::query_with_default(
- ::beman::execution::get_scheduler, env, not_a_scheduler_t{})};
+ ::beman::execution::get_start_scheduler, env, not_a_scheduler_t{})};
if constexpr (::std::same_as) {
- return env_needs_get_scheduler{};
+ return env_needs_get_start_scheduler{};
} else {
return ::beman::execution::continues_on(
::beman::execution::starts_on(::beman::execution::detail::forward_like(data),
@@ -92,7 +93,7 @@ struct on_t : ::beman::execution::sender_adaptor_closure {
env)};
if constexpr (::std::same_as) {
- return env_needs_get_scheduler{};
+ return env_needs_get_start_scheduler{};
} else {
return ::beman::execution::continues_on(
::beman::execution::detail::forward_like(closure)(::beman::execution::continues_on(
diff --git a/include/beman/execution/detail/read_env.hpp b/include/beman/execution/detail/read_env.hpp
index 5ab59ed8..67fe95b1 100644
--- a/include/beman/execution/detail/read_env.hpp
+++ b/include/beman/execution/detail/read_env.hpp
@@ -42,7 +42,7 @@ namespace beman::execution::detail {
struct read_env_t {
auto operator()(auto&& query) const { return ::beman::execution::detail::make_sender(*this, query); }
template <::beman::execution::sender Sender>
- static auto affine_on(Sender&& sndr, const auto&) noexcept {
+ static auto affine(Sender&& sndr) noexcept {
return ::std::forward(sndr);
}
diff --git a/include/beman/execution/detail/sched_env.hpp b/include/beman/execution/detail/sched_env.hpp
index 1a3d698d..2631119d 100644
--- a/include/beman/execution/detail/sched_env.hpp
+++ b/include/beman/execution/detail/sched_env.hpp
@@ -14,11 +14,11 @@ import std;
#ifdef BEMAN_HAS_MODULES
import beman.execution.detail.default_domain;
import beman.execution.detail.get_domain;
-import beman.execution.detail.get_scheduler;
+import beman.execution.detail.get_start_scheduler;
#else
#include
#include
-#include
+#include
#endif
// ----------------------------------------------------------------------------
@@ -31,10 +31,11 @@ class sched_env {
public:
template
- explicit sched_env(S sch) : sched(::std::move(sch)) {}
+ explicit sched_env(S sch) noexcept(std::is_nothrow_constructible_v) : sched(::std::move(sch)) {}
- auto query(const ::beman::execution::get_scheduler_t&) const noexcept { return this->sched; }
- auto query(const ::beman::execution::get_domain_t& q) const noexcept {
+ auto query(::beman::execution::get_start_scheduler_t) const noexcept { return this->sched; }
+
+ auto query(::beman::execution::get_domain_t q) const noexcept {
if constexpr (requires { this->sched.query(q); })
return this->sched.query(q);
else
diff --git a/include/beman/execution/detail/sender_adaptor_closure.hpp b/include/beman/execution/detail/sender_adaptor_closure.hpp
index 457fea64..924e099a 100644
--- a/include/beman/execution/detail/sender_adaptor_closure.hpp
+++ b/include/beman/execution/detail/sender_adaptor_closure.hpp
@@ -17,6 +17,7 @@ import beman.execution.detail.sender;
import beman.execution.detail.call_result_t;
import beman.execution.detail.callable;
import beman.execution.detail.class_type;
+import beman.execution.detail.forward_like;
import beman.execution.detail.nothrow_callable;
import beman.execution.detail.movable_value;
import beman.execution.detail.product_type;
@@ -26,6 +27,7 @@ import beman.execution.detail.product_type;
#include
#include
#include
+#include
#include
#include
#include
@@ -100,7 +102,7 @@ concept sender_adaptor_closure_for =
* \internal
*/
template
-using apply_cvref_t = decltype(std::forward_like(std::declval()));
+using apply_cvref_t = decltype(::beman::execution::detail::forward_like(std::declval()));
/*!
* \brief Perfect forwarding call wrapper produced by closure-closure composition via operator|.
@@ -119,7 +121,7 @@ struct composed_sender_adaptor_closure : sender_adaptor_closure, Sender> and
nothrow_callable, call_result_t, Sender>>)
-> call_result_t, call_result_t, Sender>> {
- return std::forward_like(self.outer)(std::forward_like(self.inner)(std::forward(sndr)));
+ return ::std::forward(self).outer(::std::forward(self).inner(std::forward(sndr)));
}
};
@@ -144,9 +146,9 @@ struct bound_sender_adaptor_closure : detail::product_type, Sender, apply_cvref_t...>)
-> call_result_t, Sender, apply_cvref_t...> {
- return self.apply([&](auto&&... bound_args) {
- return std::forward_like(self.adaptor)(std::forward(sndr),
- std::forward_like