[#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

[#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>>

