From ac0c51ccd00cdff1dc33b866d453e27015e79f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 11 Jan 2026 22:45:11 +0000 Subject: [PATCH 1/4] started to add wording to the affinity paper --- docs/P3941-affinity.md | 66 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/docs/P3941-affinity.md b/docs/P3941-affinity.md index ea07814..db3c9d4 100644 --- a/docs/P3941-affinity.md +++ b/docs/P3941-affinity.md @@ -495,6 +495,68 @@ resolution in this issue is incomplete). The name `affine_on` isn't great. It may be worth giving the algorithm a better name. -# Wording Changes: TODO +# Wording Changes + +Change [exec.affine.on] to use only one parameter, require an +infallible scheduler from the receiver, and add a default implementation: + +[1]{.pnum} +`affine_on` adapts a sender into one that completes on a [specified +scheduler]{.rm}[receiver's scheduler]{.add}. If the algorithm +determines that the adapted sender already completes on the correct +scheduler it can avoid any scheduling operation. + +[2]{.pnum} +The name `affine_on` denotes a pipeable sender adaptor object. For +[a ]{.add} subexpression[s sch and]{.rm} `sndr`, if [`decltype((sch))` +does not satisfy scheduler, or]{.rm} `decltype((sndr))` does not +satisfy sender, affine_on(sndr[, sch]{.rm}) is ill-formed. + +[3]{.pnum} +Otherwise, the expression affine_on(sndr[, sch]{.rm}) +is expression-equivalent to: +transform_sender(_get-domain-early_(sndr), _make-sender_(affine_on, +[sch]{.rm}[env<>()]{.add}, sndr)) except that `sndr` +is evaluated only once. + +[4]{.pnum} +The exposition-only class template _impls-for_ +([exec.snd.expos]) is specialized for `affine_on_t` as follows: -To be done. +```c++ +namespace std::execution { + template<> + struct impls-for : default-impls { + static constexpr auto get-attrs = + [](const auto&@[ data]{.rm}]@, const auto& child) noexcept -> decltype(auto) { + return @[_JOIN-ENV_(_SCHED-ATTRS_(data),_FWD-ENV_(]{.rm}@get_env(child)@[))]{.rm}@; + }; + }; +} +``` + +[5]{.pnum} +Let _out_sndr_ be a subexpression denoting a sender +returned from affine_on(sndr[, sch]{.rm}) or one equal +to such, and let _OutSndr_ be the type +decltype((_out_sndr_)). Let _out_rcvr_ +be a subexpression denoting a receiver that has an environment of +type `Env` such that sender_in<_OutSndr_, Env> +is `true`. [Let _sch_ be the result of the expression +get_scheduler(get_env(_out_rcvr_)). If the completion +signatures of schedule(_sch_) contain a different +completion signature than `set_value_t()` when using an environment +where `get_stop_token()` returns an `unstoppable_token`, the +expression connect(out_sndr, out_rcvr) is +ill-formed.]{.add} Let `op` be an lvalue referring to the operation +state that results from connecting _out_sndr_ to +_out_rcvr_. Calling start(_op_) will +start `sndr` on the current execution agent and execute completion +operations on _out_rcvr_ on an execution agent of the +execution resource associated with [`sch`]{.rm}[_sch_]{.add}. +If the current execution resource is the same as the execution +resource associated with [`sch`]{.rm}[_sch_]{.add}, +the completion operation on _out_rcvr_ may be called +before start(_op_) completes. [If scheduling onto `sch` +fails, an error completion on _out_rcvr_ shall be +executed on an unspecified execution agent.]{.rm} \ No newline at end of file From eab6932a7935b05b8c4e82e1223ba97dbd33cb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 13 Jan 2026 23:22:23 +0000 Subject: [PATCH 2/4] added more of the wording --- docs/P3941-affinity.md | 200 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 2 deletions(-) diff --git a/docs/P3941-affinity.md b/docs/P3941-affinity.md index db3c9d4..536ab61 100644 --- a/docs/P3941-affinity.md +++ b/docs/P3941-affinity.md @@ -497,8 +497,11 @@ algorithm a better name. # Wording Changes +::: ednote Change [exec.affine.on] to use only one parameter, require an -infallible scheduler from the receiver, and add a default implementation: +infallible scheduler from the receiver, and add a default implementation +which allows customization of `affine_on` for child senders: +::: [1]{.pnum} `affine_on` adapts a sender into one that completes on a [specified @@ -535,6 +538,35 @@ namespace std::execution { } ``` +:::{.add} +[?]{.pnum} +Let `sndr` and `ev` be subexpressions such that `Sndr` is +`decltype((sndr))`. If sender-for<Sndr, +affine_on_t> is `false`, then the expression +`affine_on.transform_sender(sndr, ev)` is ill-formed; otherwise, +if otherwise, +it is equal to: + +``` +auto&[_, _, child] = sndr; +using child_tag_t = tag_of_t>; +if constexpr (requires(const child_tag_t& t){ t.affine_on(child, env); }) + return t.affine_on(child, env); +else + return write_env( + schedule_from(get_scheduler(get_env(ev)), write_env(std::move(child), ev)), + JOIN-ENV(env{prop{get_stop_token, never_stop_token()}}, ev) + ); +``` + +[Note 1: This causes the `affine_on(sndr)` sender to become +`schedule_from(sch, sndr)` when it is connected with a receiver +`rcvr` whose execution domain does not customize `affine_on`, +for which `get_scheduler(get_env(rcvr))` is `sch`, and `affine_on` +isn't specialized for the child sender. +end note] +::: + [5]{.pnum} Let _out_sndr_ be a subexpression denoting a sender returned from affine_on(sndr[, sch]{.rm}) or one equal @@ -559,4 +591,168 @@ resource associated with [`sch`]{.rm}[_sch_]{.add}, the completion operation on _out_rcvr_ may be called before start(_op_) completes. [If scheduling onto `sch` fails, an error completion on _out_rcvr_ shall be -executed on an unspecified execution agent.]{.rm} \ No newline at end of file +executed on an unspecified execution agent.]{.rm} + +::: ednote +Remove `change_coroutine_scheduler` from [execution.syn]: +::: + +``` +namespace std::execution { + ... + // [exec.task.scheduler], task scheduler + class task_scheduler; + + template + struct with_error { + using type = remove_cvref_t; + type error; + }; + template + with_error(E) -> with_error; +``` +::: rm +``` + template + struct change_coroutine_scheduler { + using type = remove_cvref_t; + type scheduler; + }; + template + change_coroutine_scheduler(Sch) -> change_coroutine_scheduler; +``` +::: +``` + // [exec.task], class template task + template + class task; + ... +} +``` + +::: ednote +Adjust the use of `affine_on` and remove `change_coroutine_scheduler` from [task.promise]: +::: + +``` +namespace std::execution { + template + class task::promise_type { + public: + ... + + template + auto await_transform(A&& a); +``` +::: rm +``` + template + auto await_transform(change_coroutine_scheduler sch); +``` +::: +``` + + @_unspecified_@ get_env() const noexcept; + + ... + } +}; +``` +... + +``` +template + auto await_transform(Sender&& sndr) noexcept; +``` +[9]{.pnum} +_Returns_: If `same_as` is `true` returns `as_awaitable(​std​::​​forward(sndr), *this);` otherwise returns `as_awaitable(affine_on(​std​::​​forward(sndr)@[, SCHED(*this)]{.rm}@), *this)`. + +::: rm +``` +template + auto await_transform(change_coroutine_scheduler sch) noexcept; +``` +[10]{.pnum} +_Effects_: Equivalent to: +``` +return await_transform(just(exchange(SCHED(*this), scheduler_type(sch.scheduler))), *this); +``` +::: + +``` +void unhandled_exception(); +``` +[11]{.pnum} +_Effects_: If the signature `set_error_t(exception_ptr)` is not an element of `error_types`, calls `terminate()` ([except.terminate]). Otherwise, stores `current_exception()` into _errors_. + +... + +::: ednote +In [exec.task.scheduler] change the constructor of `task_scheduler` to require that the scheduler passed +is infallible +::: + +``` +template> + requires(!same_as>) && scheduler +explicit task_scheduler(Sch&& sch, Allocator alloc = {}); +``` + +::: add +[?]{.pnum} +_Mandates_: Let `e` be an environment and let `E` be `decltype(e)`. +If `unstoppable_token` is `true`, then +the type `completion_signatures_of_t` +only includes `set_value_t()`, otherwise it may additionally include +`set_stopped_t()`. +::: + +[2]{.pnum} +_Effects_: Initialize sch_ with `allocate_shared>(alloc,​ std​::​forward​(sch))`. + +[3]{.pnum} +_Recommended practice_: Implementations should avoid the use of +dynamically allocated memory for small scheduler objects. + +[4]{.pnum} +_Remarks_: Any allocations performed by construction of +_ts-sender_ or _state_ objects resulting +from calls on `*this` are performed using a copy of `alloc`. + +::: ednote +In [exec.task.scheduler] change the ts-sender completion signatures +to indicate that `task_scheduler` is infallible: +::: + +[8]{.pnum} +``` +namespace std::execution { + class task_scheduler::@_ts-sender_@ { // @_exposition only_@ + public: + using sender_concept = sender_t; + + template + @_state_@ connect(Rcvr&& rcvr) &&; + }; +} +``` + +ts-sender is an exposition-only class that +models `sender` ([exec.snd]) and for which +completion_signatures_of_t<ts-sender[, E]{.add}> +denotes[:]{.rm}[ `completion_signatures` if `unstoppable_token()))>` is `true`, and +otherwise `completion_signatures`.]{.add} + +::: rm +``` +completion_signatures< + set_value_t(), + set_error_t(error_code), + set_error_t(exception_ptr), + set_stopped_t()> +``` +::: + + +TODO: +- make run_loop::scheduler infallible \ No newline at end of file From 19b21fcf86b798eeb7e0f1032db7e51385c1538e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Wed, 14 Jan 2026 21:40:55 +0000 Subject: [PATCH 3/4] added wording to the affinity paper --- docs/P3941-affinity.md | 56 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/docs/P3941-affinity.md b/docs/P3941-affinity.md index 536ab61..b43e5ed 100644 --- a/docs/P3941-affinity.md +++ b/docs/P3941-affinity.md @@ -1,7 +1,7 @@ --- title: Scheduler Affinity -document: P3941R0 -date: 2025-12-14 +document: P3941R1 +date: 2026-01-14 audience: - Concurrency Working Group (SG1) - Library Evolution Working Group (LEWG) @@ -31,6 +31,10 @@ meet its objective at run-time. # Change History +## R1 + +- added wording + ## R0 Initial Revision # Overview of Changes @@ -544,8 +548,7 @@ Let `sndr` and `ev` be subexpressions such that `Sndr` is `decltype((sndr))`. If sender-for<Sndr, affine_on_t> is `false`, then the expression `affine_on.transform_sender(sndr, ev)` is ill-formed; otherwise, -if otherwise, -it is equal to: +if otherwise, it is equal to: ``` auto&[_, _, child] = sndr; @@ -565,6 +568,14 @@ else for which `get_scheduler(get_env(rcvr))` is `sch`, and `affine_on` isn't specialized for the child sender. end note] + +[?]{.pnum} +_Recommended Practice_: Implementations should provide `affine_on` +member functions for senders which are known to resume on the +scheduler where they were started. Example senders for which that +is the case are `just`, `just_error`, `just_stopped`, `read_env`, +and `write_env`. + ::: [5]{.pnum} @@ -753,6 +764,39 @@ completion_signatures< ``` ::: +::: ednote +In [exec.run.loop.types] change the paragraph defining the completion signatures: +::: + +... + +``` +class run-loop-sender; +``` + +[5]{.pnum} +run-loop-sender is an exposition-only type that satisfies `sender`. +[Let `E` be the type of an environment. If `unstoppable_token()))>` is `true`, +then ]{.add} completion_signatures_of_t<run-loop-sender[, E]{.add}> is + +::: rm +``` + completion_signatures` +``` +::: + +::: add +``` + completion_signatures +``` +Otherwise it is +``` + completion_signatures +``` +::: + +[6]{.pnum} An instance of run-loop-sender remains +valid until the end of the lifetime of its associated `run_loop` +instance. -TODO: -- make run_loop::scheduler infallible \ No newline at end of file +... \ No newline at end of file From b50a349aa5975f590d3f48ab39a124568de2d167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Thu, 15 Jan 2026 23:36:54 +0000 Subject: [PATCH 4/4] update to use the latest execution --- CMakeLists.txt | 2 +- examples/bulk.cpp | 2 +- examples/c++now-errors.cpp | 4 +- examples/dangling-references.cpp | 8 +- examples/issue-start-reschedules.cpp | 2 +- examples/rvalue-task.cpp | 2 +- include/beman/task/detail/affine_on.hpp | 184 --------------------- include/beman/task/detail/promise_type.hpp | 4 +- include/beman/task/task.hpp | 4 - tests/beman/task/CMakeLists.txt | 1 - tests/beman/task/affine_on.test.cpp | 113 ------------- 11 files changed, 12 insertions(+), 314 deletions(-) delete mode 100644 include/beman/task/detail/affine_on.hpp delete mode 100644 tests/beman/task/affine_on.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a1c58ec..88211db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ FetchContent_Declare( execution # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution GIT_REPOSITORY https://github.com/bemanproject/execution - GIT_TAG 7451ece + GIT_TAG 7d2a2b0 ) FetchContent_MakeAvailable(execution) diff --git a/examples/bulk.cpp b/examples/bulk.cpp index b5f0c16..338e400 100644 --- a/examples/bulk.cpp +++ b/examples/bulk.cpp @@ -25,5 +25,5 @@ int main() { ex::sync_wait(ex::write_env(ex::bulk(ex::just(), 16u, work{}), env{})); ex::sync_wait( - ex::write_env([]() -> ex::task { co_await ex::bulk(ex::just(), 16u, work{}); }(), env{})); + ex::write_env([]() -> ex::task> { co_await ex::bulk(ex::just(), 16u, work{}); }(), env{})); } diff --git a/examples/c++now-errors.cpp b/examples/c++now-errors.cpp index c07d40f..f4fb468 100644 --- a/examples/c++now-errors.cpp +++ b/examples/c++now-errors.cpp @@ -36,8 +36,8 @@ using identity_or_none_t = typename identity_or_none::type; #if 202202 <= __cpp_lib_expected template auto as_expected(Sender&& sndr) { - using value_type = ex::value_types_of_t; - using error_type = ex::error_types_of_t; + using value_type = ex::value_types_of_t, std::tuple, identity_or_none_t>; + using error_type = ex::error_types_of_t, identity_or_none_t>; using result_type = std::expected; return std::forward(sndr) | diff --git a/examples/dangling-references.cpp b/examples/dangling-references.cpp index e844623..501ba67 100644 --- a/examples/dangling-references.cpp +++ b/examples/dangling-references.cpp @@ -12,8 +12,8 @@ namespace ex = beman::execution; // ---------------------------------------------------------------------------- namespace { -ex::task do_work(std::string) { /* work */ co_return 0; }; -ex::task execute_all() { +ex::task> do_work(std::string) { /* work */ co_return 0; }; +ex::task> execute_all() { co_await ex::when_all(do_work("arguments 1"), do_work("arguments 2")); co_return; } @@ -27,8 +27,8 @@ int main() { ex::sync_wait([]() -> ex::task, error_env> { co_return ex::with_error{42}; }()); ex::sync_wait(execute_all()); - ex::sync_wait([]() -> ex::task { - auto t = [](const int /* this would be added: &*/ v) -> ex::task { co_return v; }(42); + ex::sync_wait([]() -> ex::task> { + auto t = [](const int /* this would be added: &*/ v) -> ex::task> { co_return v; }(42); [[maybe_unused]] auto v = co_await std::move(t); }()); } diff --git a/examples/issue-start-reschedules.cpp b/examples/issue-start-reschedules.cpp index 89d721a..4d2a1e9 100644 --- a/examples/issue-start-reschedules.cpp +++ b/examples/issue-start-reschedules.cpp @@ -13,7 +13,7 @@ ex::task<> test(auto sched) { std::cout << "init =" << std::this_thread::get_id() << "\n"; co_await ex::starts_on(sched, ex::just()); // static_assert(std::same_as); + // ex::env<>{}))>); co_await ex::just(); std::cout << "final=" << std::this_thread::get_id() << "\n"; } diff --git a/examples/rvalue-task.cpp b/examples/rvalue-task.cpp index ed80988..a7fbc79 100644 --- a/examples/rvalue-task.cpp +++ b/examples/rvalue-task.cpp @@ -32,7 +32,7 @@ void test(T&& task) { } // namespace int main() { - auto task = []() -> ex::task { co_return; }(); + auto task = []() -> ex::task> { co_return; }(); test(std::move(task)); // test(task); } diff --git a/include/beman/task/detail/affine_on.hpp b/include/beman/task/detail/affine_on.hpp deleted file mode 100644 index 14de6d2..0000000 --- a/include/beman/task/detail/affine_on.hpp +++ /dev/null @@ -1,184 +0,0 @@ -// include/beman/task/detail/affine_on.hpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_AFFINE_ON -#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_AFFINE_ON - -#include -#include -#include -#include -#include -#include -#include - -// ---------------------------------------------------------------------------- - -namespace beman::task::detail { -struct affine_on_t { - template <::beman::execution::sender Sender> - struct sender; - - template <::beman::execution::sender Sender> - auto operator()(Sender&& sndr) const { - using result_t = sender<::std::remove_cvref_t>; - static_assert(::beman::execution::sender); - return result_t(::std::forward(sndr)); - } -}; - -template <::beman::execution::sender Sender> -struct affine_on_t::sender : ::beman::execution::detail::product_type<::beman::task::detail::affine_on_t, Sender> { - using sender_concept = ::beman::execution::sender_t; - - template - static constexpr bool elide_schedule = - ::std::same_as<::beman::task::detail::inline_scheduler, ::std::remove_cvref_t>; - - template - auto get_completion_signatures(const Env& env) const& noexcept { - return ::beman::execution::get_completion_signatures(::std::remove_cvref_t(this->template get<1>()), - env); - } - template - auto get_completion_signatures(const Env& env) && noexcept { - return ::beman::execution::get_completion_signatures( - ::std::remove_cvref_t(::std::move(this->template get<1>())), env); - } - - template <::beman::execution::receiver Receiver> - struct state { - template - struct to_tuple_t; - template - struct to_tuple_t { - using type = ::std::tuple...>; - }; - template - struct to_variant_t; - template - struct to_variant_t<::beman::execution::completion_signatures> { - using type = ::beman::execution::detail::meta::unique<::std::variant::type...>>; - }; - - using operation_state_concept = ::beman::execution::operation_state_t; - using completion_signatures = decltype(::beman::execution::get_completion_signatures( - ::std::declval(), ::beman::execution::get_env(::std::declval()))); - using value_type = typename to_variant_t::type; - - struct schedule_receiver { - using receiver_concept = ::beman::execution::receiver_t; - state* s; - auto set_value() noexcept -> void { - static_assert(::beman::execution::receiver); - std::visit( - [this](auto&& v) -> void { - std::apply( - [this](auto tag, auto&&... a) { tag(std::move(this->s->receiver), ::std::move(a)...); }, - v); - }, - s->value); - } - auto get_env() const noexcept -> ::beman::execution::empty_env { /*-dk:TODO */ return {}; } - }; - - struct work_receiver { - using receiver_concept = ::beman::execution::receiver_t; - state* s; - template - auto set_value(T&&... args) noexcept -> void { - static_assert(::beman::execution::receiver); - this->s->value - .template emplace<::std::tuple<::beman::execution::set_value_t, ::std::remove_cvref_t...>>( - ::beman::execution::set_value, ::std::forward(args)...); - this->s->sched_op_.start(); - } - template - auto set_error(E&& error) noexcept -> void { - static_assert(::beman::execution::receiver); - this->s->value - .template emplace<::std::tuple<::beman::execution::set_error_t, ::std::remove_cvref_t>>( - ::beman::execution::set_error, ::std::forward(error)); - this->s->sched_op_.start(); - } - auto set_stopped(auto&&...) noexcept -> void { - static_assert(::beman::execution::receiver); - this->s->value.template emplace<::std::tuple<::beman::execution::set_stopped_t>>( - ::beman::execution::set_stopped); - this->s->sched_op_.start(); - } - auto get_env() const noexcept -> decltype(::beman::execution::get_env(::std::declval())) { - return ::beman::execution::get_env(this->s->receiver); - } - }; - using scheduler_t = - decltype(::beman::execution::get_scheduler(::beman::execution::get_env(::std::declval()))); - using schedule_op = decltype(::beman::execution::connect( - ::beman::execution::schedule(::std::declval()), ::std::declval())); - using work_op = - decltype(::beman::execution::connect(::std::declval(), ::std::declval())); - - ::std::remove_cvref_t receiver; - value_type value; - schedule_op sched_op_; - work_op work_op_; - - template - explicit state(S&& s, R&& r) - : receiver(::std::forward(r)), - sched_op_(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler( - ::beman::execution::get_env(this->receiver))), - schedule_receiver{this})), - work_op_(::beman::execution::connect(::std::forward(s), work_receiver{this})) { - static_assert(::beman::execution::operation_state); - if constexpr (not ::std::same_as< - ::beman::execution::completion_signatures<::beman::execution::set_value_t()>, - decltype(::beman::execution::get_completion_signatures( - ::beman::execution::schedule( - ::beman::execution::get_scheduler(::beman::execution::get_env(this->receiver))), - ::beman::execution::get_env(this->receiver)))>) { - static_assert(std::same_asreceiver)))>); - } - static_assert(::std::same_as<::beman::execution::completion_signatures<::beman::execution::set_value_t()>, - decltype(::beman::execution::get_completion_signatures( - ::beman::execution::schedule(::beman::execution::get_scheduler( - ::beman::execution::get_env(this->receiver))), - ::beman::execution::get_env(this->receiver)))>); - } - auto start() & noexcept -> void { ::beman::execution::start(this->work_op_); } - }; - - template - sender(S&& s) - : ::beman::execution::detail::product_type<::beman::task::detail::affine_on_t, Sender>{ - {{::beman::task::detail::affine_on_t{}}, {Sender(::std::forward(s))}}} {} - - template <::beman::execution::receiver Receiver> - auto connect(Receiver&& receiver) && { - static_assert(::std::same_as<::beman::execution::completion_signatures<::beman::execution::set_value_t()>, - decltype(::beman::execution::get_completion_signatures( - ::beman::execution::schedule( - ::beman::execution::get_scheduler(::beman::execution::get_env(receiver))), - ::beman::execution::get_env(receiver)))>, - "affine_on requires that the receiver's scheduler is infallible"); - if constexpr (elide_schedule) { - return ::beman::execution::connect(::std::move(this->template get<1>()), - ::std::forward(receiver)); - } else { - return state(::std::move(this->template get<1>()), ::std::forward(receiver)); - } - } -}; -} // namespace beman::task::detail - -namespace beman::task { -using affine_on_t = ::beman::task::detail::affine_on_t; -inline constexpr ::beman::task::detail::affine_on_t affine_on{}; -} // namespace beman::task - -// ---------------------------------------------------------------------------- - -#endif diff --git a/include/beman/task/detail/promise_type.hpp b/include/beman/task/detail/promise_type.hpp index cde9088..27467a9 100644 --- a/include/beman/task/detail/promise_type.hpp +++ b/include/beman/task/detail/promise_type.hpp @@ -5,7 +5,6 @@ #define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_PROMISE_TYPE #include -#include #include #include #include @@ -81,7 +80,8 @@ class promise_type ::beman::execution::read_env_t>) { return ::beman::execution::as_awaitable(::std::forward(sender), *this); } else { - return ::beman::execution::as_awaitable(::beman::task::affine_on(::std::forward(sender)), *this); + return ::beman::execution::as_awaitable(::beman::execution::affine_on(::std::forward(sender)), + *this); } } auto await_transform(::beman::task::detail::change_coroutine_scheduler c) { diff --git a/include/beman/task/task.hpp b/include/beman/task/task.hpp index c23ef98..262d327 100644 --- a/include/beman/task/task.hpp +++ b/include/beman/task/task.hpp @@ -4,7 +4,6 @@ #ifndef INCLUDED_INCLUDE_BEMAN_TASK_TASK #define INCLUDED_INCLUDE_BEMAN_TASK_TASK -#include #include #include #include @@ -16,7 +15,6 @@ // ---------------------------------------------------------------------------- namespace beman::task { -using affine_on_t = ::beman::task::detail::affine_on_t; template using allocator_of_t = ::beman::task::detail::allocator_of_t; template @@ -34,8 +32,6 @@ using ::beman::task::detail::with_error; } // namespace beman::task namespace beman::execution { -using affine_on_t = ::beman::task::detail::affine_on_t; -using ::beman::task::affine_on; template using allocator_of_t = ::beman::task::detail::allocator_of_t; template diff --git a/tests/beman/task/CMakeLists.txt b/tests/beman/task/CMakeLists.txt index 1d69bbe..4f6b901 100644 --- a/tests/beman/task/CMakeLists.txt +++ b/tests/beman/task/CMakeLists.txt @@ -4,7 +4,6 @@ list( APPEND task_tests msvc-asan-issue - affine_on allocator_of allocator_support completion diff --git a/tests/beman/task/affine_on.test.cpp b/tests/beman/task/affine_on.test.cpp deleted file mode 100644 index 8161b32..0000000 --- a/tests/beman/task/affine_on.test.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// tests/beman/task/affine_on.test.cpp -*-C++-*- -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#include -#include -#ifdef NDEBUG -#undef NDEBUG -#endif -#include - -namespace ex = beman::execution; - -// ---------------------------------------------------------------------------- - -namespace { -template -struct receiver { - using receiver_concept = ex::receiver_t; - - std::remove_cvref_t scheduler; - auto get_env() const noexcept { return ex::detail::make_env(ex::get_scheduler, scheduler); } - auto set_value(auto&&...) && noexcept -> void {} -}; - -template -receiver(Scheduler&& sched) -> receiver; - -template -struct test_scheduler { - using scheduler_concept = ex::scheduler_t; - struct sender { - using sender_concept = ex::sender_t; - template - auto get_completion_signatures(Env&& env) const noexcept { - if constexpr (ex::unstoppable_token) - return ex::completion_signatures{}; - else - return ex::completion_signatures{}; - } - struct env { - template - auto query(ex::get_completion_scheduler_t) const noexcept -> test_scheduler { - return {}; - } - }; - auto get_env() const noexcept { return env{}; } - - template - struct op_state { - using operation_state_concept = ex::operation_state_t; - std::remove_cvref_t rcvr; - void start() & noexcept { - static_assert(ex::operation_state); - ex::set_value(std::move(this->rcvr)); - } - }; - template - auto connect(Rcvr&& rcvr) noexcept { - static_assert(ex::sender); - return op_state{std::forward(rcvr)}; - } - }; - - auto schedule() noexcept -> sender { - static_assert(ex::scheduler>); - return {}; - } - auto operator==(const test_scheduler&) const -> bool = default; -}; -static_assert(ex::scheduler>); - -static_assert(ex::receiver>); -static_assert(ex::receiver>>); - -template -auto test_affine_on_accepted_scheduler(Receiver rcvr) { - if constexpr (requires { ex::connect(beman::task::affine_on(ex::just()), std::move(rcvr)); }) { - auto state(ex::connect(beman::task::affine_on(ex::just()), std::move(rcvr))); - ex::start(state); - } -} - -auto test_affine_on_accepted_scheduler() { - test_affine_on_accepted_scheduler(receiver{beman::task::detail::inline_scheduler{}}); - test_affine_on_accepted_scheduler(receiver{test_scheduler<>{}}); - // test_affine_on_accepted_scheduler(receiver{test_scheduler{}}); -} - -} // namespace - -int main() { - beman::task::detail::single_thread_context context; - - auto main_id{std::this_thread::get_id()}; - auto [thread_id]{ - ex::sync_wait(ex::schedule(context.get_scheduler()) | ex::then([] { return std::this_thread::get_id(); })) - .value_or(std::tuple{std::thread::id{}})}; - - assert(main_id != thread_id); - - [[maybe_unused]] auto s(beman::task::affine_on(ex::just(42))); - static_assert(ex::sender); - [[maybe_unused]] auto st(ex::connect(std::move(s), receiver{context.get_scheduler()})); - ex::sync_wait( - beman::task::affine_on(ex::starts_on(context.get_scheduler(), ex::just(42)) | ex::then([thread_id](int value) { - assert(thread_id == std::this_thread::get_id()); - assert(value == 42); - })) | - ex::then([thread_id]() { assert(thread_id != std::this_thread::get_id()); })); - test_affine_on_accepted_scheduler(); -}