# Coroutine Generator

`Generator<T>` (`generator.h`) is a small C++20-coroutine-based generator (adapted from a public writeup, credited in the source), giving a `co_yield`-based, pull-style sequence: a coroutine function that yields values of type `T` can be driven one value at a time by calling the returned `Generator` like a function, each call resuming the coroutine until its next `co_yield` (or its return). It has no `.cpp` counterpart - everything is a template, defined inline.

It backs `AnalysisCoroutine` (`Generator<AnalysisState>`, `an.h`) and `CoreCoroutine` (`Generator<CoreState>`, `core.h`): an analysis or core's internal step sequence is written as an ordinary-looking coroutine function with `co_yield` at each step, rather than as an explicit loop with externally tracked position - whatever drives the analysis pulls one state at a time, and the "where am I in this multi-step process" bookkeeping is just the coroutine's own suspended stack frame.

## `promise_type`

The compiler-mandated hook a coroutine uses to communicate with its handle. `initial_suspend()`/`final_suspend()` both return `std::suspend_always`: a `Generator` does no work until first pulled (lazy, matching ordinary iterator semantics), and it stays suspended - not destroyed - at its final point, so the driver can still observe "done" before the coroutine's frame is torn down. `yield_value()` stores the yielded value in the promise. `unhandled_exception()` captures any exception escaping the coroutine body via `std::current_exception()`, rather than letting it propagate through the (incompatible) coroutine machinery - it is re-thrown later, on the caller's own stack, from `fill()`.

## Pulling values: `fill()`/`resume()`/`operator()`

`fill()` is the "produce a value if one isn't already buffered" step: it resumes the coroutine handle exactly once if the promise's value slot is empty, then re-throws any captured exception. `resume()` and `operator()` both call `fill()` and then move the buffered value out, marking the slot empty again - so calling either twice without an intervening `co_yield` inside the coroutine still only runs the coroutine body once per value produced, with no silent skipping or duplication.

## `done()`/`operator bool()`

`done()` also calls `fill()` first - so it can't report "not done" for a value that hasn't actually been produced yet - then asks the coroutine handle whether it is suspended at its final suspend point. `operator bool()` is the negation, letting `while (gen)`/`if (gen)` read naturally (see the worked example left in the header's own comment block).

## Ownership

`Generator` is move-only (copy constructor/assignment deleted), since it owns a unique `coroutine_handle`. The destructor - and move assignment, before taking on the new handle - destroys any handle still held, releasing the coroutine's frame.
