2
0
mirror of https://github.com/boostorg/cobalt.git synced 2026-01-19 16:12:15 +00:00
Files
cobalt/doc/reference/generators.adoc
Klemens Morgenstern b807c700dc doc typo fixes
2026-01-11 07:27:47 +08:00

195 lines
4.4 KiB
Plaintext

[#generator]
== cobalt/generator.hpp
A generator is an eager coroutine that can `co_await` and `co_yield` values to the caller.
[source,cpp]
----
cobalt::generator<int> example()
{
printf("In coro 1\n");
co_yield 2;
printf("In coro 3\n");
co_return 4;
}
cobalt::main co_main(int argc, char * argv[])
{
printf("In main 0\n");
auto f = example(); // call and let it run until the first co_yield
printf("In main 1\n");
printf("In main %d\n", co_await f);
printf("In main %d\n", co_await f);
return 0;
}
----
Which will generate the following output
In main 0
In coro 1
In main 1
In main 2
In coro 3
In main 4
ifdef::generate-diagram[]
[mermaid, target=generators1]
----
sequenceDiagram
participant main;
Note left of main: "In main 0"
main->>+example: example()
Note right of example: "In coro 1"
example-->>main: co_yield 2
Note left of main: "In main 2"
main-->>+example: co_await f
Note right of example: "In coro 3"
example->>main: co_return 3
Note left of main: "In main 4"
----
endif::[]
ifndef::generate-diagram[]
image::generators1.png[]
endif::[]
Values can be pushed into the generator, when `Push` (the second template parameter) is set to non-void:
[source,cpp]
----
cobalt::generator<int, int> example()
{
printf("In coro 1\n");
int i = co_yield 2;
printf("In coro %d\n", i);
co_return 4;
}
cobalt::main co_main(int argc, char * argv[])
{
printf("In main 0\n");
auto f = example(); // call and let it run until the first co_yield
printf("In main %d\n", co_await f(3)); // <1>
co_return 0;
}
----
<1> The pushed value gets passed through `operator()` to the result of `co_yield`.
Which will generate the following output
In main 0
In coro 1
In main 2
In coro 3
[#initial]
=== Lazy
A generator can be turned lazy by awaiting initial.
This `co_await` expression will produce the `Push` value.
This means the generator will wait until it's awaited for the first time,
and then process the newly pushed value and resume at the next co_yield.
[source,cpp]
----
cobalt::generator<int, int> example()
{
int v = co_await cobalt::this_coro::initial;
printf("In coro %d\n", v);
co_yield 2;
printf("In coro %d\n", v);
co_return 4;
}
cobalt::main co_main(int argc, char * argv[])
{
printf("In main 0\n");
auto f = example(); // call and let it run until the first co_yield
printf("In main 1\n"); // < this is now before the co_await initial
printf("In main %d\n", co_await f(1));
printf("In main %d\n", co_await f(3));
return 0;
}
----
Which will generate the following output
In main 0
In main 1
In coro 1
In main 2
In coro 3
In main 4
ifdef::generate-diagram[]
[mermaid, target=generators2]
----
sequenceDiagram
participant main;
Note left of main: "In main 0"
main->>+example: example()
Note right of example: "In coro 1"
example-->>main: co_yield 2
Note left of main: "In main 2"
main-->>+example: co_await f
Note right of example: "In coro 3"
example->>main: co_return 3
Note left of main: "In main 4"
----
endif::[]
ifndef::generate-diagram[]
image::generators2.png[]
endif::[]
[#generator-executor]
=== Executor
The executor is taken from the `thread_local` <<this_thread, get_executor>> function, unless a `asio::executor_arg` is used
in any position followed by the executor argument.
[source, cpp]
----
cobalt::generator<int> my_gen(asio::executor_arg_t, asio::io_context::executor_type exec_to_use);
----
[#generator-allocator]
=== Memory Resource
The memory resource is taken from the `thread_local` <<this_thread, get_default_resource>> function,
unless a `std::allocator_arg` is used in any position followed by a `polymorphic_allocator` argument.
[source, cpp]
----
cobalt::generator<int> my_gen(std::allocator_arg_t, pmr::polymorphic_allocator<void> alloc);
----
[#generator-outline]
=== Outline
[source,cpp,subs=+quotes]
----
include::../../include/boost/cobalt/generator.hpp[tag=outline]
----
<1> This allows code like `while (gen) co_await gen;`
<2> Supports <<interrupt_await>>
<3> A cancelled generator maybe be resumable
NOTE: The destruction of an eager generator will be deferred, a lazy will be destroyed immediately.
[#generator-promise]
=== Promise
The generator promise has the following properties.
- <<promise_memory_resource_base>>
- <<promise_cancellation_base>>
- <<promise_throw_if_cancelled_base>>
- <<enable_awaitables>>
- <<enable_await_allocator>>
- <<enable_await_executor>>