mirror of
https://github.com/boostorg/cobalt.git
synced 2026-01-19 04:02:16 +00:00
195 lines
4.4 KiB
Plaintext
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>>
|
|
|