From 8447e06f18569608c1e75ddf83b679f31daa015a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 5 Aug 2025 22:09:51 +0100 Subject: [PATCH 1/7] removed dependency on net and trying to improve the docs --- CMakeLists.txt | 9 --------- docs/examples.md | 6 +++--- examples/CMakeLists.txt | 2 -- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02a315e..8098d75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,15 +39,6 @@ FetchContent_Declare( GIT_TAG 330be95 ) FetchContent_MakeAvailable(execution) -FetchContent_Declare( - net - # SOURCE_DIR /net - GIT_REPOSITORY https://github.com/bemanproject/net - GIT_TAG ea1fd8f -) -if(NOT WIN32) - FetchContent_MakeAvailable(net) -endif() add_subdirectory(src/beman/task) diff --git a/docs/examples.md b/docs/examples.md index ec7787e..0855698 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -4,13 +4,13 @@
-[`c++now-affinity.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-affinity.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/8qEG5x7sz): demo scheduler affinity +`c++now-affinity.cpp` +: demo scheduler affinity The example program [`c++now-affinity.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-affinity.cpp) -[![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/8qEG5x7sz) uses -[`demo::thread_loop`](../examples/demo-thread_loop.hpp) to demonstrate +uses [`demo::thread_loop`](../examples/demo-thread_loop.hpp) to demonstrate the behavior of _scheduler affinity_: the idea is that scheduler affinity causes the coroutine to resume on the same scheduler as the one the coroutine was started on. The program implements three diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ba10af6..ce0f30f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -19,7 +19,6 @@ set(ALL_EXAMPLES co_await-result co_await-task container - environment error escaped-exception friendly @@ -48,7 +47,6 @@ foreach(example ${ALL_EXAMPLES}) target_link_libraries( beman.task.examples.${example} beman::task - beman::net ) endif() add_test( From 5d5ff710bf9c4fc387c5c59756675e8742e3ade5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 5 Aug 2025 22:22:25 +0100 Subject: [PATCH 2/7] adding a bit more documentation --- docs/examples.md | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 0855698..a5091f2 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -5,7 +5,8 @@
`c++now-affinity.cpp` -: demo scheduler affinity +: +demo scheduler affinity The example program @@ -56,7 +57,30 @@ the `inline_scheduler` doesn't do any actual scheduling.
-- [`c++now-allocator.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-allocator.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/719v7en6a) +
+ +`c++now-allocator.cpp` +: +demo allocator use + + +This demo shows how to configure `task`'s environment argument to +use a different allocator than the default `std::allocator`. +To do so it defines an environment type `with_allocator` which +defines a nested type alias `allocator_type` to be +`std::pmr::polymorphic_allocator`. + +The coroutine `coro` shows how to use `read_env` to extract the +used allocator object to potentially use it for any allocation +purposes within the coroutine. There are two uses of `coro`, the +first one using the default which just uses +`std::pmr::polymorphic_allocator()` to allocate memory. +The second use explicitly specifies the memory resource +`std::pmr::new_delete_resource()` to initialized the use +`std::pmr::polymorphic_allocator`. + +
+ - [`c++now-basic.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-basic.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/7Pn5TEhfK) - [`c++now-cancel.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-cancel.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/vx4PqYvE6) - [`c++now-errors.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-errors.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/95Mhr5MGn) From b733d96f5166e6f84620f9f9fb1f506633e0b702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 5 Aug 2025 22:39:23 +0100 Subject: [PATCH 3/7] added a description of the basic coroutine example --- docs/examples.md | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index a5091f2..508dbb1 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -4,8 +4,8 @@
-`c++now-affinity.cpp` -: +c++now-affinity.cpp +: demo scheduler affinity @@ -59,8 +59,8 @@ the `inline_scheduler` doesn't do any actual scheduling.
-`c++now-allocator.cpp` -: +c++now-allocator.cpp +: demo allocator use @@ -81,7 +81,28 @@ The second use explicitly specifies the memory resource
-- [`c++now-basic.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-basic.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/7Pn5TEhfK) +
+ +c++now-basic.cpp +: +demo basic task use + + +The example +c++now-basic.cpp +shows some basic use of a `task`: + +1. The coroutine `basic` just `co_await`s the awaiter `std::suspend_never{}` which immediately completes. + This use demonstrates that any awaiter can be `co_await`ed by a `task<...>`. +2. The coroutine `await_sender` demonstrates the results of `co_await`ing various senders. It uses variations of + `just*` to show the different results: + - `co_await`ing a sender completing with `set_value_t()`, e.g., `just()`, produces an expression with type `void`. + - `co_await`ing a sender completing with `set_value_t(T)`, e.g., `just(1)`, produces an expression with type `T`. + - `co_await`ing a sender completing with set_value_t(T0, ..., Tn), e.g., `just(1, true)`, produces an expression with type tuple<T0, ..., Tn>`. + - `co_await`ing a sender completing with `set_error_t(E)`, e.g., `just_error(1)`, results in an exception of type `E` being thrown. + - `co_await`ing a sender completing with `set_stopped_t()`, e.g., `just_stopped()`, results in the corouting never getting resumed although all local objects are properly destroyed. + + - [`c++now-cancel.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-cancel.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/vx4PqYvE6) - [`c++now-errors.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-errors.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/95Mhr5MGn) - [`c++now-query.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-query.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/dPboEeqfv) From 63571eed482746fe6176c35b7de03c3587a9bdf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 5 Aug 2025 22:46:23 +0100 Subject: [PATCH 4/7] fixed a few formatting issues [hopefully] and added doc for the cancel example --- docs/examples.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 508dbb1..21b5216 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -98,12 +98,24 @@ shows some basic use of a `task`: `just*` to show the different results: - `co_await`ing a sender completing with `set_value_t()`, e.g., `just()`, produces an expression with type `void`. - `co_await`ing a sender completing with `set_value_t(T)`, e.g., `just(1)`, produces an expression with type `T`. - - `co_await`ing a sender completing with set_value_t(T0, ..., Tn), e.g., `just(1, true)`, produces an expression with type tuple<T0, ..., Tn>`. + - `co_await`ing a sender completing with set_value_t(T0, ..., Tn), e.g., `just(1, true)`, produces an expression with type tuple<T0, ..., Tn>`. - `co_await`ing a sender completing with `set_error_t(E)`, e.g., `just_error(1)`, results in an exception of type `E` being thrown. - `co_await`ing a sender completing with `set_stopped_t()`, e.g., `just_stopped()`, results in the corouting never getting resumed although all local objects are properly destroyed. - +
+ +
+ +c++now-cancel.cpp +: +demo how a `task` can actively cancel the work + + +The example +c++now-basic.cpp +shows a coroutine `co_await`ing `just_stopped()` which results in the coroutine getting cancelled. The coroutine will +complete with `set_stopped()`. +
-- [`c++now-cancel.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-cancel.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/vx4PqYvE6) - [`c++now-errors.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-errors.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/95Mhr5MGn) - [`c++now-query.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-query.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/dPboEeqfv) - [`c++now-result-types.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-result-types.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/aWfc8T8he) From 849b3666e95b07004e2b7cab5dfa891dc270078f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 5 Aug 2025 23:10:56 +0100 Subject: [PATCH 5/7] added documentation for the errors example --- docs/examples.md | 32 ++++++++++++++++++++++++++------ examples/CMakeLists.txt | 9 +-------- examples/c++now-errors.cpp | 4 ++-- examples/demo-thread_loop.hpp | 3 --- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 21b5216..3a3da6b 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -85,7 +85,7 @@ The second use explicitly specifies the memory resource c++now-basic.cpp : -demo basic task use +demo basic task use The example @@ -98,7 +98,7 @@ shows some basic use of a `task`: `just*` to show the different results: - `co_await`ing a sender completing with `set_value_t()`, e.g., `just()`, produces an expression with type `void`. - `co_await`ing a sender completing with `set_value_t(T)`, e.g., `just(1)`, produces an expression with type `T`. - - `co_await`ing a sender completing with set_value_t(T0, ..., Tn), e.g., `just(1, true)`, produces an expression with type tuple<T0, ..., Tn>`. + - `co_await`ing a sender completing with set_value_t(T0, ..., Tn), e.g., `just(1, true)`, produces an expression with type tuple<T0, ..., Tn>. - `co_await`ing a sender completing with `set_error_t(E)`, e.g., `just_error(1)`, results in an exception of type `E` being thrown. - `co_await`ing a sender completing with `set_stopped_t()`, e.g., `just_stopped()`, results in the corouting never getting resumed although all local objects are properly destroyed.
@@ -107,16 +107,36 @@ shows some basic use of a `task`: c++now-cancel.cpp : -demo how a `task` can actively cancel the work +demo how a task can actively cancel the work The example -c++now-basic.cpp +c++now-cancel.cpp shows a coroutine `co_await`ing `just_stopped()` which results in the coroutine getting cancelled. The coroutine will complete with `set_stopped()`.
-- [`c++now-errors.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-errors.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/95Mhr5MGn) +
+ +c++now-errors.cpp +: +demo how to handle errors within task + + +The example +c++now-errors.cpp +shows examples of how to handle errors within a coroutine: + +- The coroutine `error_result` simply `co_await`s a sender producing an error (`just_error(17)`). When + a `co_await`ed sender completes with `set_error_t(T)` an exception of type `T` is thrown and the error + needs to be handled with a `try`/`catch` block. Otherwise the coroutine itself completes with `set_error_t(exception_ptr)` + where the `exception_ptr` hold the thrown exception object. +- The coroutine `expected` uses a sender algorithm `as_expected` which is implemented at the top of the example + to turn the result of the `co_await`ed sender into an object of type `expected`, avoiding an exception + from being thrown. + +
+ - [`c++now-query.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-query.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/dPboEeqfv) - [`c++now-result-types.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-result-types.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/aWfc8T8he) - [`c++now-return.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-return.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/f5YE5W4Ta) @@ -127,7 +147,7 @@ complete with `set_stopped()`.
-[`demo::thread_loop`](../examples/demo-thread_loop.hpp) is a `run_loop` whose `run()` is called from a `std::thread`. +demo::thread_loop(../examples/demo-thread_loop.hpp) is a run_loop whose run() is called from a std::thread. Technically [`demo::thread_loop`](../examples/demo-thread_loop.hpp) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ce0f30f..bace0f1 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -41,14 +41,7 @@ message("Examples to be built: ${ALL_EXAMPLES}") foreach(example ${ALL_EXAMPLES}) add_executable(beman.task.examples.${example}) target_sources(beman.task.examples.${example} PRIVATE ${example}.cpp) - if(WIN32) - target_link_libraries(beman.task.examples.${example} beman::task) - else() - target_link_libraries( - beman.task.examples.${example} - beman::task - ) - endif() + target_link_libraries(beman.task.examples.${example} beman::task) add_test( NAME beman.task.examples.${example} COMMAND $ diff --git a/examples/c++now-errors.cpp b/examples/c++now-errors.cpp index 5e72b16..7f0e4c9 100644 --- a/examples/c++now-errors.cpp +++ b/examples/c++now-errors.cpp @@ -68,9 +68,9 @@ ex::task<> error_result() { #if 202202 <= __cpp_lib_expected ex::task<> expected() { - [[maybe_unused]] auto e = co_await as_expected(ex::just(17)); + auto e = co_await as_expected(ex::just(17)); print_expected("expected with value=", e); - [[maybe_unused]] auto u = co_await as_expected(ex::just_error(17)); + auto u = co_await as_expected(ex::just_error(17)); print_expected("expected without value=", u); } #endif diff --git a/examples/demo-thread_loop.hpp b/examples/demo-thread_loop.hpp index 5194dd3..bedbe9d 100644 --- a/examples/demo-thread_loop.hpp +++ b/examples/demo-thread_loop.hpp @@ -7,10 +7,7 @@ // ---------------------------------------------------------------------------- #include -#include -#include #include -#include #include namespace demo { From 3be2b1ed042c8f0a0135d2a56e80e7aee76203b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 5 Aug 2025 23:23:05 +0100 Subject: [PATCH 6/7] added another example description --- docs/examples.md | 21 +++++++++++++++++++-- examples/c++now-errors.cpp | 2 +- examples/c++now-query.cpp | 7 +++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 3a3da6b..199e681 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -137,7 +137,24 @@ shows examples of how to handle errors within a coroutine:
-- [`c++now-query.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-query.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/dPboEeqfv) +
+ +c++now-query.cpp +: +demo passing a custom envrionment into a task + + +The example +c++now-query.cpp +shows how to define and use a custom environment element. + +1. The coroutine `with_env` uses a simple environment named `context` which just defines a custom query for `get_value` + to obtain a value. The value itself gets initialized from the environment of the receiver used with the `task`. +2. The coroutine `with_fancy_env` uses an environment which embed a an object depending the type of the environment + of the receiver used with the `task`. While the type accessed from within the `task` needs to be type-erased, + the actually stored value can depend on the environment of the upstream receiver. +
+ - [`c++now-result-types.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-result-types.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/aWfc8T8he) - [`c++now-return.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-return.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/f5YE5W4Ta) - [`c++now-stop_token.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-stop_token.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/TxYe3jEs7) @@ -147,7 +164,7 @@ shows examples of how to handle errors within a coroutine:
-demo::thread_loop(../examples/demo-thread_loop.hpp) is a run_loop whose run() is called from a std::thread. +demo::thread_loop is a run_loop whose run() is called from a std::thread. Technically [`demo::thread_loop`](../examples/demo-thread_loop.hpp) diff --git a/examples/c++now-errors.cpp b/examples/c++now-errors.cpp index 7f0e4c9..c07d40f 100644 --- a/examples/c++now-errors.cpp +++ b/examples/c++now-errors.cpp @@ -70,7 +70,7 @@ ex::task<> error_result() { ex::task<> expected() { auto e = co_await as_expected(ex::just(17)); print_expected("expected with value=", e); - auto u = co_await as_expected(ex::just_error(17)); + auto u = co_await as_expected(ex::just_error(17)); print_expected("expected without value=", u); } #endif diff --git a/examples/c++now-query.cpp b/examples/c++now-query.cpp index 1a73f88..369786b 100644 --- a/examples/c++now-query.cpp +++ b/examples/c++now-query.cpp @@ -27,7 +27,10 @@ struct context { int query(const get_value_t&) const { return this->value; } }; -ex::task with_env() { [[maybe_unused]] decltype(auto) v = co_await ex::read_env(get_value); } +ex::task with_env() { + decltype(auto) v = co_await ex::read_env(get_value); + std::cout << "with_env: v=" << v << "\n"; +} struct fancy { struct env_base { @@ -52,7 +55,7 @@ struct fancy { }; ex::task with_fancy_env() { - [[maybe_unused]] decltype(auto) v = co_await ex::read_env(get_value); + decltype(auto) v = co_await ex::read_env(get_value); std::cout << "v=" << v << "\n"; } } // namespace From 880de016e16e95d09c63cf0b9ff14ae79eb8c555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Wed, 6 Aug 2025 20:23:44 +0100 Subject: [PATCH 7/7] added documentation for the remaining C++Now examples --- docs/examples.md | 72 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 199e681..ac394c6 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -155,10 +155,74 @@ shows how to define and use a custom environment element. the actually stored value can depend on the environment of the upstream receiver.
-- [`c++now-result-types.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-result-types.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/aWfc8T8he) -- [`c++now-return.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-return.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/f5YE5W4Ta) -- [`c++now-stop_token.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-stop_token.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/TxYe3jEs7) -- [`c++now-with_error.cpp`](https://github.com/bemanproject/task/blob/main/examples/c%2B%2Bnow-with_error.cpp) [![Compiler Explorer](compiler-explorer.ico)](https://godbolt.org/z/6oqox6zf8) +
+ +c++now-result-types.cpp +: +demo the result type of co_await expressions. + + +The example +c++now-result-types.cpp +shows the result types of successful senders using variatons of `just`: + +- `co_await just()` doesn't produce a value, i.e., the type of the expression is `void`. +- `co_await just(1)` produces an `int`. +- `co_await just(1, true)` produces a `tuple`. + +
+ +
+ +c++now-return.cpp +: +shows the different normal values returned + + +The example +c++now-return.cpp +shows various ways of returning normally (without an error) for a `task`. Some of the coroutines are set up to produce +specific error results although none of them are actually use: + +- `default_return` shows that the default return type for `task<>` is `void`. +- `void_return` explicitly specifies a `void` return type. +- `int_return` specifies the return type as `int` and returns an `int` value. +- `error_return` specifies the return type as `int` and also specifies custom error results. +- `no_error_return` specifies the return type as `int` and also specifies that the coroutine can't produce any error. +
+ +
+ +c++now-stop_token.cpp +: +demo how to get and use a stop token in a `task` + + +The example +c++now-stop_token.cpp +shows how to get a stop token in side a `task` and how to use it to cancel active work. It doesn't actually complete +with a `set_stopped()` but completes with `set_value()`. + +- In the coroutine `co_await read_env(get_stop_token)` is used to get a stop token. +- In the loop the value of `token.stop_requested()` is checked to determine if the loop should continue. +- In `main` an `inplace_stop_source` is used to have something which can be stopped. +- When running the coroutine `stopping` on a separate thread, the environment is changed using `write_env` to use stop token from `main`'s stop source in the environment. +- After sleeping for a bit, `source.request_stop()` is called to trigger cancellation of the coroutine. +
+ +
+ +c++now-with_error.cpp +: +demo exiting a task with an error + + +The example +c++now-with_error.cpp +shows how a coroutine can be exited reporting an error without throwing an exception. To do so, the coroutine +uses `co_yield with_error(e)`. By default the `task` only declares `set_error_t(exception_ptr)`. To return +other errors, an environment declarating a suitable `set_error_t(E)` completion using the `error_types` alias is used. +
## Tools Used By The Examples