|
JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
|
Coroutine-based generator supporting both yielding and receiving values. More...
#include <jh/asynchronous/generator.h>
Classes | |
| struct | iterator |
| struct | promise_type |
Public Types | |
| using | value_type = T |
| Type alias for the value type produced by the generator. | |
| using | send_type = U |
Public Member Functions | |
| generator (const generator &)=delete | |
| Deleted copy constructor. | |
| generator & | operator= (const generator &)=delete |
| Deleted copy assignment operator. | |
| generator (generator &&other) noexcept | |
| Move constructor. | |
| generator & | operator= (generator &&other) noexcept |
| Move assignment operator. | |
| generator (std::coroutine_handle< promise_type > h) | |
Constructs a generator directly from its coroutine handle. | |
| ~generator () | |
| Destroys the coroutine handle if it exists. | |
| bool | next () |
| Advances the generator to the next value. | |
| bool | done () const noexcept |
| Checks if the generator has completed execution. | |
| bool | send (send_type value) |
| Sends a value to the generator and resumes execution. | |
| bool | send_ite (send_type value) |
| Advances the generator and sends a value in one step. | |
| std::optional< value_type > | value () const noexcept |
| Retrieves the currently yielded value. | |
| std::optional< send_type > | last_sent_value () const noexcept |
| Retrieves the last value sent to the generator. | |
| void | stop () |
| Stops the generator and destroys the coroutine. | |
| iterator | begin () |
| Returns an iterator for ranged-for loops. | |
| iterator | begin () const =delete |
Deleted const overload of begin(). | |
Static Public Member Functions | |
| static iterator | end () |
| Returns a sentinel iterator representing the end of the generator sequence. | |
Public Attributes | |
| std::coroutine_handle< promise_type > | co_ro |
| Handle to the coroutine. | |
Coroutine-based generator supporting both yielding and receiving values.
This class implements a coroutine-driven sequence producer, conceptually equivalent to Python's Generator[T, U, None]. It provides a clear and type-safe interface for two-way coroutine communication:
co_yield. co_await, corresponding to send(). A generator is a consumable object — each call to next() or send() advances its internal coroutine state. Once advanced, previously yielded values cannot be revisited.
Values produced by co_yield are retrieved via .value(), which returns std::optional<T>. Before the first next() call or after completion, this optional contains std::nullopt.
When consuming generator outputs:
.value().value() when you are certain a value exists (i.e. immediately after a successful next()). .value().has_value() before dereferencing if unsure. jh::async::to_vector() or jh::async::to_deque(). jh::to_range(), instead of passing a generator instance directly. | T | The yielded value type (produced by co_yield). Must be copy-constructible since it is stored within std::optional<T>. Prefer trivially copyable or POD-like types for best performance:
|
| U | The input type sent to the generator (via send() or send_ite()). Corresponds to values received by co_await inside the coroutine. Defaults to typed::monostate, making the generator a pure output sequence. |
std::unique_ptr<T>) are not supported by default because the implementation relies on std::optional<T>. To support them, implement a custom buffering or ownership model. | using jh::async::generator< T, U >::value_type = T |
Type alias for the value type produced by the generator.
Type alias for the value type sent to the generator.
|
delete |
Deleted copy constructor.
Since generator<T, U> manages a coroutine handle (std::coroutine_handle<promise_type>), copying the generator would lead to double ownership issues.
To prevent accidental copies, the copy constructor is explicitly deleted.
|
inlinenoexcept |
Move constructor.
Transfers ownership of the coroutine handle from other to this.
other generator is set to nullptr to prevent double destruction. | other | The generator to move from. |
|
inlineexplicit |
Constructs a generator directly from its coroutine handle.
This constructor is the linkage point between the coroutine's promise_type and its corresponding jh::async::generator<T, U> object. It is invoked automatically by the compiler when a coroutine function returning a generator is defined and called.
This enables Python-like semantics for defining and using coroutine generators:
jh::async::generator<T, U> Func(Args...) { scope_with_co_yield(); } — defines a coroutine generator. Func(args...) — directly obtains a generator instance, without explicitly handling std::coroutine_handle. jh::to_range([...] { Func(args...); }) — wraps the generator-producing function into a reusable, re-entrant range. Thus, jh::async::generator<T, U> aligns closely with Python's Generator[T, U, None] semantics, making coroutine-based data pipelines natural and concise in C++.
| h | The coroutine handle to be managed by this generator. |
|
inline |
Returns an iterator for ranged-for loops.
Enables use of the generator in a C++ range-based loop: for (auto x : gen). This overload is available only when U == typed::monostate, meaning the generator does not expect any input values.
Each iteration step advances the coroutine and consumes its internal state. Unlike standard ranges, a generator cannot be treated as a view or re-iterated, because iteration directly resumes and mutates the underlying coroutine frame.
A const version of begin() is intentionally deleted because invoking iteration on a constant generator would violate logical immutability: advancing the coroutine inherently modifies its promise object and execution context.
|
delete |
Deleted const overload of begin().
Generator iteration is a stateful and consuming operation. Allowing a const overload would incorrectly imply immutability, even though every iteration step mutates the coroutine's suspended frame.
This deletion enforces the invariant that jh::async::generator<T, U> may only be iterated when held as a mutable instance.
|
inlinenodiscardnoexcept |
Checks if the generator has completed execution.
true if the generator has finished, false otherwise.
|
inlinestatic |
Returns a sentinel iterator representing the end of the generator sequence.
This function provides the canonical past-the-end sentinel for use in range-based iteration. Unlike begin(), calling end() never resumes or interacts with the underlying coroutine; it simply returns a default-constructed iterator object used to mark the termination of iteration.
Because it performs no coroutine access, end() is idempotent — it can be safely invoked multiple times without affecting the generator state.
This overload is available only when U == typed::monostate, meaning the generator is purely output-driven and does not require input through send().
|
inlinenoexcept |
Retrieves the last value sent to the generator.
send() or send_ite().This accessor returns the most recent value (U) that was sent into the coroutine through send() or send_ite(). The stored value is preserved until the next input or coroutine resumption. If no input has been sent yet, the returned std::optional is empty.
The returned value is a copy of the last sent element. This guarantees safety after coroutine resumption. If pointer semantics or shared ownership are required, use copyable reference-counted types such as std::shared_ptr instead of move-only handles.
When U == typed::monostate, the generator does not consume inputs at all. In such cases, this accessor has no semantic meaning and always yields an empty std::optional.
|
inline |
Advances the generator to the next value.
true if a new value is available, false if the coroutine has finished.
|
delete |
Deleted copy assignment operator.
Like the copy constructor, the copy assignment operator is deleted to ensure that the coroutine handle is not duplicated, which would lead to undefined behavior.
|
inlinenoexcept |
Move assignment operator.
other generator is set to nullptr to prevent double destruction. | other | The generator to move from. |
this generator after assignment.
|
inline |
Sends a value to the generator and resumes execution.
| value | The value to send. |
true if the coroutine is still active, false otherwise.U == typed::monostate, this function becomes a no-op. Since there is no co_await to receive input, the call does not advance the coroutine or affect its state. Use next() or send_ite() instead to progress the generator.
|
inline |
Advances the generator and sends a value in one step.
This function combines next() and send(), eliminating the need for a separate next() call. It first advances the generator, and if successful, sends the provided value.
| value | The value to send to the generator. |
true if the generator successfully advances and accepts the value, false if the generator has finished.U == typed::monostate, this behaves identically to next(), since no input is transmitted and the send stage is inert.
|
inlinenoexcept |
Retrieves the currently yielded value.
std::shared_ptr<T> or any equivalent reference-counted handle type.std::unique_ptr<T> and other move-only types are not supported because the generator requires T to be copy-constructible for std::optional<T> storage.