From ae8cbd0d04163ddbe02706d55a7225e6ecf69fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Wed, 18 Feb 2026 20:33:13 +0000 Subject: [PATCH 01/13] an experiment propagating an allocator via a sender --- examples/CMakeLists.txt | 1 + examples/task-sender.cpp | 61 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 examples/task-sender.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 03f3972..0cb4ef7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -21,6 +21,7 @@ endif() set(TODO tls-scheduler into_optional issue-start-reschedules loop) set(ALL_EXAMPLES + task-sender task_scheduler rvalue-task customize diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp new file mode 100644 index 0000000..472add1 --- /dev/null +++ b/examples/task-sender.cpp @@ -0,0 +1,61 @@ +// examples/hello.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +namespace ex = beman::execution; + +template +struct ct +{ + Task& task; + template + auto operator()(Arg&&... arg) const { + return ex::let_value(ex::read_env(ex::get_stop_token), + [&task=this->task, ...a=std::forward(arg)](auto) { + return std::invoke(task, std::move(a)...); + }); + } +}; +template +ct(Task&) -> ct; + +struct env { + using allocator_type = std::pmr::polymorphic_allocator; +}; + +auto lambda{[](int i, auto&&...)->ex::task { + auto alloc = co_await ex::read_env(ex::get_allocator); + alloc.deallocate(alloc.allocate(1), 1); + std::cout << "lambda(" << i << ")\n"; co_return; +}}; + +struct resource + : std::pmr::memory_resource +{ + void* do_allocate(std::size_t n, std::size_t) override { + std::cout << "resource::allocate(" << n << ")\n"; + return operator new(n); + } + void do_deallocate(void* p, std::size_t n, std::size_t) override { + std::cout << "resource::deallocate(" << n << ")\n"; + operator delete(p, n); + } + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override{ + return this == &other; + } + +}; + +int main() { + resource res{}; + std::pmr::polymorphic_allocator alloc(&res); + ex::sync_wait(ex::write_env(ct(lambda)(17), + ex::env{ex::prop{ex::get_allocator, alloc}})); +} From 92c8ab785a570fb69bf33e4dbebbf765dc83655b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 22 Feb 2026 18:39:18 +0000 Subject: [PATCH 02/13] demo of a sender for delayed coroutine frame allocation --- CMakeLists.txt | 6 +- examples/task-sender.cpp | 91 +++++++++++++++++++--- include/beman/task/detail/promise_type.hpp | 2 +- 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e46b7b..791a4a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,9 +28,9 @@ include(FetchContent) FetchContent_Declare( execution - # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution - GIT_REPOSITORY https://github.com/bemanproject/execution - GIT_TAG 07d53da + SOURCE_DIR ${CMAKE_SOURCE_DIR}/../execution + # GIT_REPOSITORY https://github.com/bemanproject/execution + # GIT_TAG 07d53da SYSTEM FIND_PACKAGE_ARGS 0.2.0 diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index 472add1..99f9b10 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -12,19 +12,17 @@ namespace ex = beman::execution; template -struct ct +struct defer_frame { - Task& task; + Task task; template auto operator()(Arg&&... arg) const { - return ex::let_value(ex::read_env(ex::get_stop_token), - [&task=this->task, ...a=std::forward(arg)](auto) { - return std::invoke(task, std::move(a)...); + return ex::let_value(ex::read_env(ex::get_allocator), + [&task=this->task, ...a=std::forward(arg)](auto alloc) { + return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); }); } }; -template -ct(Task&) -> ct; struct env { using allocator_type = std::pmr::polymorphic_allocator; @@ -40,11 +38,11 @@ struct resource : std::pmr::memory_resource { void* do_allocate(std::size_t n, std::size_t) override { - std::cout << "resource::allocate(" << n << ")\n"; + std::cout << " resource::allocate(" << n << ")\n"; return operator new(n); } void do_deallocate(void* p, std::size_t n, std::size_t) override { - std::cout << "resource::deallocate(" << n << ")\n"; + std::cout << " resource::deallocate(" << n << ")\n"; operator delete(p, n); } bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override{ @@ -56,6 +54,77 @@ struct resource int main() { resource res{}; std::pmr::polymorphic_allocator alloc(&res); - ex::sync_wait(ex::write_env(ct(lambda)(17), - ex::env{ex::prop{ex::get_allocator, alloc}})); + std::cout << "direct allocator use:\n"; + alloc.deallocate(alloc.allocate(1), 1); + std::cout << "write_env/just/then use:\n"; + ex::sync_wait( + ex::write_env( + ex::just(alloc) + | ex::then([](auto a) { + a.deallocate(a.allocate(1), 1); + }), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "write_env/read_env/then use:\n"; + ex::sync_wait( + ex::write_env( + ex::read_env(ex::get_allocator) + | ex::then([](auto a) { + a.deallocate(a.allocate(1), 1); + }), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "write_env/let_value/then use:\n"; + ex::sync_wait( + ex::write_env( + ex::just() + | ex::let_value([]{ + return ex::read_env(ex::get_allocator) + | ex::then([](auto a) { a.deallocate(a.allocate(1), 1); }) + ; + }), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "write_env/task<>:\n"; + ex::sync_wait( + ex::write_env( + []()->ex::task<>{ + auto a = co_await ex::read_env(ex::get_allocator); + a.deallocate(a.allocate(1), 1); + }(), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "write_env/task:\n"; + ex::sync_wait( + ex::write_env( + [](auto&&...)->ex::task{ + auto a = co_await ex::read_env(ex::get_allocator); + a.deallocate(a.allocate(1), 1); + }(std::allocator_arg, alloc), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "write_env/defer_frame>:\n"; + static constexpr defer_frame t0( + [](auto, auto, int i)->ex::task{ + std::cout << " i=" << i << "\n"; + auto a = co_await ex::read_env(ex::get_allocator); + a.deallocate(a.allocate(1), 1); + }); + ex::sync_wait( + ex::write_env( + t0(17), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "write_env/temporary defer_frame>:\n"; + ex::sync_wait( + ex::write_env( + defer_frame([](auto, auto, auto i)->ex::task{ + std::cout << " i=" << i << "\n"; + co_await std::suspend_never{}; + auto a = co_await ex::read_env(ex::get_allocator); + a.deallocate(a.allocate(1), 1); + })(42), + ex::env{ex::prop{ex::get_allocator, alloc}}) + ); + std::cout << "done\n"; } diff --git a/include/beman/task/detail/promise_type.hpp b/include/beman/task/detail/promise_type.hpp index 27467a9..7bbe297 100644 --- a/include/beman/task/detail/promise_type.hpp +++ b/include/beman/task/detail/promise_type.hpp @@ -70,7 +70,7 @@ class promise_type auto get_return_object() noexcept { return Coroutine(::beman::task::detail::handle(this)); } template <::beman::execution::sender Sender> - auto await_transform(Sender&& sender) noexcept { + auto await_transform(Sender&& sender) { if constexpr (requires { ::std::forward(sender).as_awaitable(*this); // typename ::std::remove_cvref_t::task_concept; From 89e367f75d1cd0cdbac0952f3e041137afbcc778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 8 Mar 2026 20:51:16 +0100 Subject: [PATCH 03/13] fixed some issues to match the most recent execution main --- examples/task-sender.cpp | 27 ++++++++++++++++--- include/beman/task/detail/awaiter.hpp | 2 +- .../beman/task/detail/inline_scheduler.hpp | 4 +++ include/beman/task/detail/task.hpp | 6 ++--- include/beman/task/detail/task_scheduler.hpp | 4 +++ 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index 99f9b10..e37e567 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -7,10 +7,20 @@ #include #include #include +#include #include namespace ex = beman::execution; +void* operator new(std::size_t n) { + auto p = std::malloc(n); + std::cout << "global new(" << n << ")->" << p << "\n"; + return p; +} +void operator delete(void* ptr) noexcept { + std::cout << "global operator delete()" << ptr << "\n"; +} + template struct defer_frame { @@ -22,6 +32,14 @@ struct defer_frame return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); }); } + template + auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { + return ex::let_value(ex::just(alloc), + [&task=this->task, ...a=std::forward(arg)](auto alloc) { + return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); + }); + } + auto operator()(::std::allocator_arg_t) const = delete; }; struct env { @@ -38,12 +56,13 @@ struct resource : std::pmr::memory_resource { void* do_allocate(std::size_t n, std::size_t) override { - std::cout << " resource::allocate(" << n << ")\n"; - return operator new(n); + auto p{std::malloc(n)}; + std::cout << " resource::allocate(" << n << ")->" << p << "\n"; + return p; } void do_deallocate(void* p, std::size_t n, std::size_t) override { - std::cout << " resource::deallocate(" << n << ")\n"; - operator delete(p, n); + std::cout << " resource::deallocate(" << p << ", " << n << ")\n"; + std::free(p); } bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override{ return this == &other; diff --git a/include/beman/task/detail/awaiter.hpp b/include/beman/task/detail/awaiter.hpp index 4eff758..7a010bf 100644 --- a/include/beman/task/detail/awaiter.hpp +++ b/include/beman/task/detail/awaiter.hpp @@ -55,7 +55,7 @@ class awaiter : public ::beman::task::detail::state_base { constexpr auto await_ready() const noexcept -> bool { return false; } struct env_receiver { ParentPromise* parent; - auto get_env() const noexcept { return parent->get_env(); } + auto get_env() const noexcept { return ::beman::execution::get_env(*parent); } }; auto await_suspend(::std::coroutine_handle parent) noexcept { this->state_rep.emplace(env_receiver{&parent.promise()}); diff --git a/include/beman/task/detail/inline_scheduler.hpp b/include/beman/task/detail/inline_scheduler.hpp index bcdcdf8..916db68 100644 --- a/include/beman/task/detail/inline_scheduler.hpp +++ b/include/beman/task/detail/inline_scheduler.hpp @@ -42,6 +42,10 @@ struct inline_scheduler { struct sender { using sender_concept = ::beman::execution::sender_t; using completion_signatures = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>; + template + static consteval auto get_completion_signatures() noexcept -> completion_signatures { + return {}; + } env get_env() const noexcept { return {}; } template <::beman::execution::receiver Receiver> diff --git a/include/beman/task/detail/task.hpp b/include/beman/task/detail/task.hpp index 15555c2..fcdd6a4 100644 --- a/include/beman/task/detail/task.hpp +++ b/include/beman/task/detail/task.hpp @@ -52,9 +52,9 @@ class task { ::beman::execution::completion_signatures, ::beman::execution::set_stopped_t()>, ::beman::task::detail::error_types_of_t >; - template - auto get_completion_signatures(const Ev&) const& noexcept { - return xcompletion_signatures{}; + template + static consteval auto get_completion_signatures() noexcept -> xcompletion_signatures { + return {}; } using promise_type = ::beman::task::detail::promise_type; diff --git a/include/beman/task/detail/task_scheduler.hpp b/include/beman/task/detail/task_scheduler.hpp index cc3f127..6bb83be 100644 --- a/include/beman/task/detail/task_scheduler.hpp +++ b/include/beman/task/detail/task_scheduler.hpp @@ -126,6 +126,10 @@ class task_scheduler { public: using sender_concept = ::beman::execution::sender_t; using completion_signatures = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>; + template + static consteval auto get_completion_signatures() noexcept -> completion_signatures { + return {}; + } template <::beman::execution::scheduler S> explicit sender(S&& s) : inner_sender(static_cast*>(nullptr), std::forward(s)) {} From a3c57d54e6e93c55538723931e78237bc0cd9146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 15 Mar 2026 17:03:45 +0000 Subject: [PATCH 04/13] added a demo of defering coroutine frame creation --- examples/odd-completions.cpp | 24 +++++++++++++++++++++ examples/task-sender.cpp | 42 +++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 examples/odd-completions.cpp diff --git a/examples/odd-completions.cpp b/examples/odd-completions.cpp new file mode 100644 index 0000000..6ac1373 --- /dev/null +++ b/examples/odd-completions.cpp @@ -0,0 +1,24 @@ +// examples/hello.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +namespace ex = beman::execution; + +int main() { + return std::get<0>(ex::sync_wait([]() -> ex::task { + std::cout << "Hello, world!\n"; + co_return co_await ex::just(0); + }()) + .value_or(std::tuple(-1))); +ex::sync_wait([](int value) -> ex::task { + switch (value) { + default: co_return value; + case -1: co_yield ex::with_error(std::make_exception_ptr(value)); + case 2: throw value; + case 0: co_await ex::just_stopped(); + } +}(0)); +} diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index e37e567..f30be7d 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -21,8 +21,30 @@ void operator delete(void* ptr) noexcept { std::cout << "global operator delete()" << ptr << "\n"; } -template +template struct defer_frame +{ + Mem mem; + Self self; + template + auto operator()(Arg&&... arg) const { + return ex::let_value(ex::read_env(ex::get_allocator), + [mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); + } + template + auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { + return ex::let_value(ex::just(alloc), + [&mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); + } + auto operator()(::std::allocator_arg_t) const = delete; +}; + +template +struct defer_frame { Task task; template @@ -52,6 +74,24 @@ auto lambda{[](int i, auto&&...)->ex::task { std::cout << "lambda(" << i << ")\n"; co_return; }}; +class example { + ex::task member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int); + ex::task const_member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int) const; + +public: + auto member(int i) { return defer_frame(&example::member_, this); } + auto const_member(int i) { return defer_frame(&example::const_member_, this); } +}; + +inline ex::task example::member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int i) { + std::cout << "example::member(" << i << ")\n"; + co_return; +} +inline ex::task example::const_member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int i) const { + std::cout << "example::const member(" << i << ")\n"; + co_return; +} + struct resource : std::pmr::memory_resource { From 1a5b363cd987f316ecd368613daa42781a99d4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 01:36:32 +0000 Subject: [PATCH 05/13] adding an allocation example --- examples/CMakeLists.txt | 1 + examples/alloc-1.cpp | 140 +++++++++++++++++++++++++++++++++++++++ examples/task-sender.cpp | 4 +- 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 examples/alloc-1.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0cb4ef7..f5b8f53 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -32,6 +32,7 @@ set(ALL_EXAMPLES if(NOT MSVC) list( APPEND ALL_EXAMPLES + alloc-1 bulk c++now-allocator c++now-cancel diff --git a/examples/alloc-1.cpp b/examples/alloc-1.cpp new file mode 100644 index 0000000..3849515 --- /dev/null +++ b/examples/alloc-1.cpp @@ -0,0 +1,140 @@ +// examples/hello.cpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ex = beman::execution; + +// ---------------------------------------------------------------------------- +// --- defer_frame turns yields a sender calling a coroutine upon start() --- + +template +struct defer_frame +{ + Mem mem; + Self self; + template + auto operator()(Arg&&... arg) const { + return ex::let_value(ex::read_env(ex::get_allocator), + [mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); + } + template + auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { + return ex::let_value(ex::just(alloc), + [&mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); + } + auto operator()(::std::allocator_arg_t) const = delete; +}; + +template +struct defer_frame +{ + Task task; + template + auto operator()(Arg&&... arg) const { + return ex::let_value(ex::read_env(ex::get_allocator), + [task=this->task, ...a=std::forward(arg)](auto alloc) { + return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); + }); + } + template + auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { + return ex::let_value(ex::just(alloc), + [&task=this->task, ...a=std::forward(arg)](auto alloc) { + return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); + }); + } + auto operator()(::std::allocator_arg_t) const = delete; +}; + +// ---------------------------------------------------------------------------- + +void* operator new(std::size_t n) { + auto p = std::malloc(n); + std::cout << " global new(" << n << ")->" << p << "\n"; + return p; +} +void operator delete(void* ptr) noexcept { + std::cout << " global operator delete()" << ptr << "\n"; +} + +struct resource + : std::pmr::memory_resource +{ + void* do_allocate(std::size_t n, std::size_t) override { + auto p{std::malloc(n)}; + std::cout << " resource::allocate(" << n << ")->" << p << "\n"; + return p; + } + void do_deallocate(void* p, std::size_t n, std::size_t) override { + std::cout << " resource::deallocate(" << p << ", " << n << ")\n"; + std::free(p); + } + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override{ + return this == &other; + } + +}; + +// ---------------------------------------------------------------------------- + +using allocator_type = std::pmr::polymorphic_allocator; +struct alloc_env { + using allocator_type = ::allocator_type; +}; +template +using a_task = ex::task; + +a_task hidden_async_fun(std::allocator_arg_t, ::allocator_type, int value) { + co_return value; +} +auto async_fun(int value) { + return defer_frame(&hidden_async_fun)(value); +} + +int main() { + std::cout << std::unitbuf; + resource res{}; + allocator_type alloc(&res); + + std::cout << "not setting up an allocator:\n"; + ex::sync_wait( + []()->a_task<>{ + auto result{co_await async_fun(17)}; + std::cout << " result=" << result << "\n"; + }() + ); + + std::cout << "setting up an allocator:\n"; + ex::sync_wait( + ex::write_env( + []()->a_task<>{ + auto result{co_await async_fun(17)}; + std::cout << " result=" << result << "\n"; + }(), + ex::env{ex::prop{ex::get_allocator, alloc}} + ) + ); + + std::cout << "setting up an allocator and using defer_frame:\n"; + ex::sync_wait( + ex::write_env( + defer_frame([](auto, auto)->a_task<>{ + auto result{co_await async_fun(17)}; + std::cout << " result=" << result << "\n"; + })(), + ex::env{ex::prop{ex::get_allocator, alloc}} + ) + ); +} diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index f30be7d..f9d11a0 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -79,8 +79,8 @@ class example { ex::task const_member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int) const; public: - auto member(int i) { return defer_frame(&example::member_, this); } - auto const_member(int i) { return defer_frame(&example::const_member_, this); } + auto member(int i) { return defer_frame(&example::member_, this)(i); } + auto const_member(int i) { return defer_frame(&example::const_member_, this)(i); } }; inline ex::task example::member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int i) { From 6a8bb7f954bbe9502713d02164a65f9014d19501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 01:47:11 +0000 Subject: [PATCH 06/13] worked around using a possibly older version of execution --- include/beman/task/detail/awaiter.hpp | 2 +- include/beman/task/detail/task.hpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/beman/task/detail/awaiter.hpp b/include/beman/task/detail/awaiter.hpp index 7a010bf..4eff758 100644 --- a/include/beman/task/detail/awaiter.hpp +++ b/include/beman/task/detail/awaiter.hpp @@ -55,7 +55,7 @@ class awaiter : public ::beman::task::detail::state_base { constexpr auto await_ready() const noexcept -> bool { return false; } struct env_receiver { ParentPromise* parent; - auto get_env() const noexcept { return ::beman::execution::get_env(*parent); } + auto get_env() const noexcept { return parent->get_env(); } }; auto await_suspend(::std::coroutine_handle parent) noexcept { this->state_rep.emplace(env_receiver{&parent.promise()}); diff --git a/include/beman/task/detail/task.hpp b/include/beman/task/detail/task.hpp index fcdd6a4..2fa9032 100644 --- a/include/beman/task/detail/task.hpp +++ b/include/beman/task/detail/task.hpp @@ -48,12 +48,16 @@ class task { public: using task_concept = int; using sender_concept = ::beman::execution::sender_t; - using xcompletion_signatures = ::beman::execution::detail::meta::combine< + using completion_signatures = ::beman::execution::detail::meta::combine< ::beman::execution::completion_signatures, ::beman::execution::set_stopped_t()>, ::beman::task::detail::error_types_of_t >; + template + auto get_completion_signatures(const Ev&) const& noexcept -> completion_signatures { + return {}; + } template - static consteval auto get_completion_signatures() noexcept -> xcompletion_signatures { + static consteval auto get_completion_signatures() noexcept -> completion_signatures { return {}; } From b1c78a1195dd1e16a6a06a2bb0d7ac19e412dda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:10:16 +0000 Subject: [PATCH 07/13] fix problem if allocator types don't match --- include/beman/task/detail/state.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/beman/task/detail/state.hpp b/include/beman/task/detail/state.hpp index 567fac0..56dc81a 100644 --- a/include/beman/task/detail/state.hpp +++ b/include/beman/task/detail/state.hpp @@ -48,8 +48,8 @@ struct state : ::beman::task::detail::state_base, ::beman::task::detail::s return std::noop_coroutine(); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver)); }) - return ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver)); + if constexpr (requires { allocator_type(::beman::execution::get_allocator(::beman::execution::get_env(this->receiver))); }) + return allocator_type(::beman::execution::get_allocator(::beman::execution::get_env(this->receiver))); else return allocator_type{}; } From c86bfdec8ea196972b1b29bcd15e210fb21d6c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:11:10 +0000 Subject: [PATCH 08/13] clang format --- examples/alloc-1.cpp | 89 +++++++----------- examples/odd-completions.cpp | 20 ++-- examples/task-sender.cpp | 138 ++++++++++------------------ include/beman/task/detail/state.hpp | 5 +- include/beman/task/detail/task.hpp | 2 +- 5 files changed, 101 insertions(+), 153 deletions(-) diff --git a/examples/alloc-1.cpp b/examples/alloc-1.cpp index 3849515..91e04ce 100644 --- a/examples/alloc-1.cpp +++ b/examples/alloc-1.cpp @@ -16,42 +16,39 @@ namespace ex = beman::execution; // --- defer_frame turns yields a sender calling a coroutine upon start() --- template -struct defer_frame -{ - Mem mem; +struct defer_frame { + Mem mem; Self self; template auto operator()(Arg&&... arg) const { return ex::let_value(ex::read_env(ex::get_allocator), - [mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { - return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); - }); + [mem = this->mem, self = this->self, ... a = std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); } template auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { return ex::let_value(ex::just(alloc), - [&mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { - return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); - }); + [&mem = this->mem, self = this->self, ... a = std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); } auto operator()(::std::allocator_arg_t) const = delete; }; template -struct defer_frame -{ +struct defer_frame { Task task; template auto operator()(Arg&&... arg) const { return ex::let_value(ex::read_env(ex::get_allocator), - [task=this->task, ...a=std::forward(arg)](auto alloc) { - return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); - }); + [task = this->task, ... a = std::forward(arg)](auto alloc) { + return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); + }); } template auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { - return ex::let_value(ex::just(alloc), - [&task=this->task, ...a=std::forward(arg)](auto alloc) { + return ex::let_value(ex::just(alloc), [&task = this->task, ... a = std::forward(arg)](auto alloc) { return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); }); } @@ -65,13 +62,9 @@ void* operator new(std::size_t n) { std::cout << " global new(" << n << ")->" << p << "\n"; return p; } -void operator delete(void* ptr) noexcept { - std::cout << " global operator delete()" << ptr << "\n"; -} +void operator delete(void* ptr) noexcept { std::cout << " global operator delete()" << ptr << "\n"; } -struct resource - : std::pmr::memory_resource -{ +struct resource : std::pmr::memory_resource { void* do_allocate(std::size_t n, std::size_t) override { auto p{std::malloc(n)}; std::cout << " resource::allocate(" << n << ")->" << p << "\n"; @@ -81,10 +74,7 @@ struct resource std::cout << " resource::deallocate(" << p << ", " << n << ")\n"; std::free(p); } - bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override{ - return this == &other; - } - + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; } }; // ---------------------------------------------------------------------------- @@ -96,12 +86,8 @@ struct alloc_env { template using a_task = ex::task; -a_task hidden_async_fun(std::allocator_arg_t, ::allocator_type, int value) { - co_return value; -} -auto async_fun(int value) { - return defer_frame(&hidden_async_fun)(value); -} +a_task hidden_async_fun(std::allocator_arg_t, ::allocator_type, int value) { co_return value; } +auto async_fun(int value) { return defer_frame(&hidden_async_fun)(value); } int main() { std::cout << std::unitbuf; @@ -109,32 +95,23 @@ int main() { allocator_type alloc(&res); std::cout << "not setting up an allocator:\n"; - ex::sync_wait( - []()->a_task<>{ - auto result{co_await async_fun(17)}; - std::cout << " result=" << result << "\n"; - }() - ); + ex::sync_wait([]() -> a_task<> { + auto result{co_await async_fun(17)}; + std::cout << " result=" << result << "\n"; + }()); std::cout << "setting up an allocator:\n"; - ex::sync_wait( - ex::write_env( - []()->a_task<>{ - auto result{co_await async_fun(17)}; - std::cout << " result=" << result << "\n"; - }(), - ex::env{ex::prop{ex::get_allocator, alloc}} - ) - ); + ex::sync_wait(ex::write_env( + []() -> a_task<> { + auto result{co_await async_fun(17)}; + std::cout << " result=" << result << "\n"; + }(), + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "setting up an allocator and using defer_frame:\n"; - ex::sync_wait( - ex::write_env( - defer_frame([](auto, auto)->a_task<>{ - auto result{co_await async_fun(17)}; - std::cout << " result=" << result << "\n"; - })(), - ex::env{ex::prop{ex::get_allocator, alloc}} - ) - ); + ex::sync_wait(ex::write_env(defer_frame([](auto, auto) -> a_task<> { + auto result{co_await async_fun(17)}; + std::cout << " result=" << result << "\n"; + })(), + ex::env{ex::prop{ex::get_allocator, alloc}})); } diff --git a/examples/odd-completions.cpp b/examples/odd-completions.cpp index 6ac1373..efa196a 100644 --- a/examples/odd-completions.cpp +++ b/examples/odd-completions.cpp @@ -13,12 +13,16 @@ int main() { co_return co_await ex::just(0); }()) .value_or(std::tuple(-1))); -ex::sync_wait([](int value) -> ex::task { - switch (value) { - default: co_return value; - case -1: co_yield ex::with_error(std::make_exception_ptr(value)); - case 2: throw value; - case 0: co_await ex::just_stopped(); - } -}(0)); + ex::sync_wait([](int value) -> ex::task { + switch (value) { + default: + co_return value; + case -1: + co_yield ex::with_error(std::make_exception_ptr(value)); + case 2: + throw value; + case 0: + co_await ex::just_stopped(); + } + }(0)); } diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index f9d11a0..b8be9f1 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -17,47 +17,42 @@ void* operator new(std::size_t n) { std::cout << "global new(" << n << ")->" << p << "\n"; return p; } -void operator delete(void* ptr) noexcept { - std::cout << "global operator delete()" << ptr << "\n"; -} +void operator delete(void* ptr) noexcept { std::cout << "global operator delete()" << ptr << "\n"; } template -struct defer_frame -{ - Mem mem; +struct defer_frame { + Mem mem; Self self; template auto operator()(Arg&&... arg) const { return ex::let_value(ex::read_env(ex::get_allocator), - [mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { - return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); - }); + [mem = this->mem, self = this->self, ... a = std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); } template auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { return ex::let_value(ex::just(alloc), - [&mem=this->mem, self=this->self, ...a=std::forward(arg)](auto alloc) { - return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); - }); + [&mem = this->mem, self = this->self, ... a = std::forward(arg)](auto alloc) { + return std::invoke(mem, self, std::allocator_arg, alloc, std::move(a)...); + }); } auto operator()(::std::allocator_arg_t) const = delete; }; template -struct defer_frame -{ +struct defer_frame { Task task; template auto operator()(Arg&&... arg) const { return ex::let_value(ex::read_env(ex::get_allocator), - [&task=this->task, ...a=std::forward(arg)](auto alloc) { - return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); - }); + [&task = this->task, ... a = std::forward(arg)](auto alloc) { + return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); + }); } template auto operator()(::std::allocator_arg_t, Alloc alloc, Arg&&... arg) const { - return ex::let_value(ex::just(alloc), - [&task=this->task, ...a=std::forward(arg)](auto alloc) { + return ex::let_value(ex::just(alloc), [&task = this->task, ... a = std::forward(arg)](auto alloc) { return std::invoke(task, std::allocator_arg, alloc, std::move(a)...); }); } @@ -68,17 +63,18 @@ struct env { using allocator_type = std::pmr::polymorphic_allocator; }; -auto lambda{[](int i, auto&&...)->ex::task { +auto lambda{[](int i, auto&&...) -> ex::task { auto alloc = co_await ex::read_env(ex::get_allocator); alloc.deallocate(alloc.allocate(1), 1); - std::cout << "lambda(" << i << ")\n"; co_return; + std::cout << "lambda(" << i << ")\n"; + co_return; }}; class example { ex::task member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int); ex::task const_member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int) const; -public: + public: auto member(int i) { return defer_frame(&example::member_, this)(i); } auto const_member(int i) { return defer_frame(&example::const_member_, this)(i); } }; @@ -87,14 +83,13 @@ inline ex::task example::member_(std::allocator_arg_t, std::pmr::poly std::cout << "example::member(" << i << ")\n"; co_return; } -inline ex::task example::const_member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int i) const { +inline ex::task +example::const_member_(std::allocator_arg_t, std::pmr::polymorphic_allocator, int i) const { std::cout << "example::const member(" << i << ")\n"; co_return; } -struct resource - : std::pmr::memory_resource -{ +struct resource : std::pmr::memory_resource { void* do_allocate(std::size_t n, std::size_t) override { auto p{std::malloc(n)}; std::cout << " resource::allocate(" << n << ")->" << p << "\n"; @@ -104,86 +99,55 @@ struct resource std::cout << " resource::deallocate(" << p << ", " << n << ")\n"; std::free(p); } - bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override{ - return this == &other; - } - + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; } }; int main() { - resource res{}; + resource res{}; std::pmr::polymorphic_allocator alloc(&res); std::cout << "direct allocator use:\n"; alloc.deallocate(alloc.allocate(1), 1); std::cout << "write_env/just/then use:\n"; - ex::sync_wait( - ex::write_env( - ex::just(alloc) - | ex::then([](auto a) { - a.deallocate(a.allocate(1), 1); - }), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + ex::sync_wait(ex::write_env(ex::just(alloc) | ex::then([](auto a) { a.deallocate(a.allocate(1), 1); }), + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "write_env/read_env/then use:\n"; ex::sync_wait( - ex::write_env( - ex::read_env(ex::get_allocator) - | ex::then([](auto a) { - a.deallocate(a.allocate(1), 1); - }), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + ex::write_env(ex::read_env(ex::get_allocator) | ex::then([](auto a) { a.deallocate(a.allocate(1), 1); }), + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "write_env/let_value/then use:\n"; - ex::sync_wait( - ex::write_env( - ex::just() - | ex::let_value([]{ - return ex::read_env(ex::get_allocator) - | ex::then([](auto a) { a.deallocate(a.allocate(1), 1); }) - ; - }), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + ex::sync_wait(ex::write_env(ex::just() | ex::let_value([] { + return ex::read_env(ex::get_allocator) | + ex::then([](auto a) { a.deallocate(a.allocate(1), 1); }); + }), + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "write_env/task<>:\n"; - ex::sync_wait( - ex::write_env( - []()->ex::task<>{ + ex::sync_wait(ex::write_env( + []() -> ex::task<> { auto a = co_await ex::read_env(ex::get_allocator); a.deallocate(a.allocate(1), 1); }(), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "write_env/task:\n"; - ex::sync_wait( - ex::write_env( - [](auto&&...)->ex::task{ + ex::sync_wait(ex::write_env( + [](auto&&...) -> ex::task { auto a = co_await ex::read_env(ex::get_allocator); a.deallocate(a.allocate(1), 1); }(std::allocator_arg, alloc), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "write_env/defer_frame>:\n"; - static constexpr defer_frame t0( - [](auto, auto, int i)->ex::task{ - std::cout << " i=" << i << "\n"; - auto a = co_await ex::read_env(ex::get_allocator); - a.deallocate(a.allocate(1), 1); - }); - ex::sync_wait( - ex::write_env( - t0(17), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + static constexpr defer_frame t0([](auto, auto, int i) -> ex::task { + std::cout << " i=" << i << "\n"; + auto a = co_await ex::read_env(ex::get_allocator); + a.deallocate(a.allocate(1), 1); + }); + ex::sync_wait(ex::write_env(t0(17), ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "write_env/temporary defer_frame>:\n"; - ex::sync_wait( - ex::write_env( - defer_frame([](auto, auto, auto i)->ex::task{ - std::cout << " i=" << i << "\n"; - co_await std::suspend_never{}; - auto a = co_await ex::read_env(ex::get_allocator); - a.deallocate(a.allocate(1), 1); - })(42), - ex::env{ex::prop{ex::get_allocator, alloc}}) - ); + ex::sync_wait(ex::write_env(defer_frame([](auto, auto, auto i) -> ex::task { + std::cout << " i=" << i << "\n"; + co_await std::suspend_never{}; + auto a = co_await ex::read_env(ex::get_allocator); + a.deallocate(a.allocate(1), 1); + })(42), + ex::env{ex::prop{ex::get_allocator, alloc}})); std::cout << "done\n"; } diff --git a/include/beman/task/detail/state.hpp b/include/beman/task/detail/state.hpp index 56dc81a..204d823 100644 --- a/include/beman/task/detail/state.hpp +++ b/include/beman/task/detail/state.hpp @@ -48,7 +48,10 @@ struct state : ::beman::task::detail::state_base, ::beman::task::detail::s return std::noop_coroutine(); } auto do_get_allocator() -> allocator_type override { - if constexpr (requires { allocator_type(::beman::execution::get_allocator(::beman::execution::get_env(this->receiver))); }) + if constexpr (requires { + allocator_type( + ::beman::execution::get_allocator(::beman::execution::get_env(this->receiver))); + }) return allocator_type(::beman::execution::get_allocator(::beman::execution::get_env(this->receiver))); else return allocator_type{}; diff --git a/include/beman/task/detail/task.hpp b/include/beman/task/detail/task.hpp index 2fa9032..7d8dec5 100644 --- a/include/beman/task/detail/task.hpp +++ b/include/beman/task/detail/task.hpp @@ -48,7 +48,7 @@ class task { public: using task_concept = int; using sender_concept = ::beman::execution::sender_t; - using completion_signatures = ::beman::execution::detail::meta::combine< + using completion_signatures = ::beman::execution::detail::meta::combine< ::beman::execution::completion_signatures, ::beman::execution::set_stopped_t()>, ::beman::task::detail::error_types_of_t >; From 9c651f9eff0386a99b2653a54a485550686f07f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:13:33 +0000 Subject: [PATCH 09/13] fix formatting issue --- include/beman/task/detail/task.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/beman/task/detail/task.hpp b/include/beman/task/detail/task.hpp index 7d8dec5..5d23b7d 100644 --- a/include/beman/task/detail/task.hpp +++ b/include/beman/task/detail/task.hpp @@ -46,9 +46,9 @@ class task { using stop_token_type = decltype(std::declval().get_token()); public: - using task_concept = int; - using sender_concept = ::beman::execution::sender_t; - using completion_signatures = ::beman::execution::detail::meta::combine< + using task_concept = int; + using sender_concept = ::beman::execution::sender_t; + using completion_signatures = ::beman::execution::detail::meta::combine< ::beman::execution::completion_signatures, ::beman::execution::set_stopped_t()>, ::beman::task::detail::error_types_of_t >; From 7f90c9cd626747208d14372aae553a91d89a8108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:23:23 +0000 Subject: [PATCH 10/13] fixed missing operator delete --- examples/alloc-1.cpp | 7 +++++-- examples/task-sender.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/alloc-1.cpp b/examples/alloc-1.cpp index 91e04ce..4879093 100644 --- a/examples/alloc-1.cpp +++ b/examples/alloc-1.cpp @@ -1,4 +1,4 @@ -// examples/hello.cpp -*-C++-*- +// examples/alloc-1.cpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include @@ -62,7 +62,10 @@ void* operator new(std::size_t n) { std::cout << " global new(" << n << ")->" << p << "\n"; return p; } -void operator delete(void* ptr) noexcept { std::cout << " global operator delete()" << ptr << "\n"; } +void operator delete(void* ptr) noexcept { std::cout << " global operator delete(" << ptr << ")\n"; } +void operator delete(void* ptr, std::size_t size) noexcept { + std::cout << " global operator delete(" << ptr << ", " << size << ")\n"; +} struct resource : std::pmr::memory_resource { void* do_allocate(std::size_t n, std::size_t) override { diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index b8be9f1..9d752c1 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -1,4 +1,4 @@ -// examples/hello.cpp -*-C++-*- +// examples/task_sender.hpp -*-C++-*- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include @@ -17,7 +17,10 @@ void* operator new(std::size_t n) { std::cout << "global new(" << n << ")->" << p << "\n"; return p; } -void operator delete(void* ptr) noexcept { std::cout << "global operator delete()" << ptr << "\n"; } +void operator delete(void* ptr) noexcept { std::cout << "global operator delete(" << ptr << ")\n"; } +void operator delete(void* ptr, std::size_t size) noexcept { + std::cout << "global operator delete(" << ptr << ", " << size << ")\n"; +} template struct defer_frame { From e71e2347ce9456b20ebe1529a8fce090f3fbdfe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:30:24 +0000 Subject: [PATCH 11/13] fix memory leak in example --- examples/alloc-1.cpp | 6 +++++- examples/task-sender.cpp | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/alloc-1.cpp b/examples/alloc-1.cpp index 4879093..129c2a3 100644 --- a/examples/alloc-1.cpp +++ b/examples/alloc-1.cpp @@ -62,9 +62,13 @@ void* operator new(std::size_t n) { std::cout << " global new(" << n << ")->" << p << "\n"; return p; } -void operator delete(void* ptr) noexcept { std::cout << " global operator delete(" << ptr << ")\n"; } +void operator delete(void* ptr) noexcept { + std::cout << " global operator delete(" << ptr << ")\n"; + std::free(ptr); +} void operator delete(void* ptr, std::size_t size) noexcept { std::cout << " global operator delete(" << ptr << ", " << size << ")\n"; + std::free(ptr); } struct resource : std::pmr::memory_resource { diff --git a/examples/task-sender.cpp b/examples/task-sender.cpp index 9d752c1..f763bed 100644 --- a/examples/task-sender.cpp +++ b/examples/task-sender.cpp @@ -17,9 +17,13 @@ void* operator new(std::size_t n) { std::cout << "global new(" << n << ")->" << p << "\n"; return p; } -void operator delete(void* ptr) noexcept { std::cout << "global operator delete(" << ptr << ")\n"; } +void operator delete(void* ptr) noexcept { + std::cout << " global operator delete(" << ptr << ")\n"; + std::free(ptr); +} void operator delete(void* ptr, std::size_t size) noexcept { - std::cout << "global operator delete(" << ptr << ", " << size << ")\n"; + std::cout << " global operator delete(" << ptr << ", " << size << ")\n"; + std::free(ptr); } template From 3ab8250d3263444b5e1f6fa2fe19997de12e6f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:36:40 +0000 Subject: [PATCH 12/13] remove task-sender from compiled examples for now --- examples/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 84e8f1c..e33aea8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -21,7 +21,6 @@ endif() set(TODO tls-scheduler into_optional issue-start-reschedules loop) set(ALL_EXAMPLES - task-sender task_scheduler rvalue-task customize From 107abb32af53d7ed1039b5bbaea8f57e28d70927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Mon, 23 Mar 2026 03:37:25 +0000 Subject: [PATCH 13/13] restore task-sender for non-MSVC --- examples/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e33aea8..de068e5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -31,6 +31,7 @@ set(ALL_EXAMPLES if(NOT MSVC) list( APPEND ALL_EXAMPLES + task-sender alloc-1 bulk c++now-allocator