Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
generator.hpp
Go to the documentation of this file.
1#pragma once
2
3// Generator<T>: pull-based C++ coroutine (C++20 and C++23).
4//
5// Generator<int> fib(int n) {
6// int a = 0, b = 1;
7// for (int i = 0; i < n; ++i) {
8// co_yield a;
9// int t = a + b; a = b; b = t;
10// }
11// }
12//
13// for (int x : fib(10)) std::cout << x << ' ';
14//
15// The generator is lazy — values are produced one at a time on demand.
16//
17// ⚠️ CRITICAL: do NOT make the body a lambda that captures by reference.
18// Coroutine frames live on the heap, but the lambda object expires at the
19// call expression, leaving dangling references. Use a free function, a
20// member function, or pass state through parameters.
21
22#include <coroutine>
23#include <exception>
24#include <iterator>
25#include <utility>
26
27namespace aria::async {
28
29template<typename T>
30class Generator {
31public:
32 struct promise_type {
34 std::exception_ptr exception;
35
37 return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
38 }
39 std::suspend_always initial_suspend() noexcept { return {}; }
40 std::suspend_always final_suspend() noexcept { return {}; }
41
42 std::suspend_always yield_value(T value) {
43 current_value = std::move(value);
44 return {};
45 }
46 void return_void() noexcept {}
47 void unhandled_exception() noexcept { exception = std::current_exception(); }
48
49 // Disallow co_await inside a Generator
50 template<typename U>
51 std::suspend_never await_transform(U&&) = delete;
52 };
53
54 using handle_type = std::coroutine_handle<promise_type>;
55
56 Generator() = default;
57 explicit Generator(handle_type h) noexcept : h_(h) {}
58
59 Generator(const Generator&) = delete;
60 Generator& operator=(const Generator&) = delete;
61 Generator(Generator&& o) noexcept : h_(std::exchange(o.h_, {})) {}
62 Generator& operator=(Generator&& o) noexcept {
63 if (this != &o) {
64 if (h_) h_.destroy();
65 h_ = std::exchange(o.h_, {});
66 }
67 return *this;
68 }
69 ~Generator() { if (h_) h_.destroy(); }
70
71 // ── Iterator API (range-for compatible) ──────────────────────
72 class Iterator {
73 handle_type h_;
74 public:
75 using iterator_category = std::input_iterator_tag;
76 using value_type = T;
77 using difference_type = std::ptrdiff_t;
78 using reference = const T&;
79 using pointer = const T*;
80
81 Iterator() noexcept = default;
82 explicit Iterator(handle_type h) noexcept : h_(h) {}
83
85 h_.resume();
86 if (h_.done()) {
87 if (auto e = h_.promise().exception) std::rethrow_exception(e);
88 h_ = nullptr;
89 }
90 return *this;
91 }
92 void operator++(int) { ++*this; }
93
94 const T& operator*() const noexcept { return h_.promise().current_value; }
95 const T* operator->() const noexcept { return &h_.promise().current_value; }
96
97 bool operator==(std::default_sentinel_t) const noexcept { return !h_ || h_.done(); }
98 };
99
101 if (!h_) return Iterator{};
102 h_.resume();
103 if (h_.done()) {
104 if (auto e = h_.promise().exception) std::rethrow_exception(e);
105 return Iterator{};
106 }
107 return Iterator{h_};
108 }
109 std::default_sentinel_t end() noexcept { return {}; }
110
111private:
112 handle_type h_{};
113};
114
115} // namespace aria::async
Definition generator.hpp:72
T value_type
Definition generator.hpp:76
void operator++(int)
Definition generator.hpp:92
const T * operator->() const noexcept
Definition generator.hpp:95
const T & operator*() const noexcept
Definition generator.hpp:94
const T * pointer
Definition generator.hpp:79
const T & reference
Definition generator.hpp:78
Iterator & operator++()
Definition generator.hpp:84
std::ptrdiff_t difference_type
Definition generator.hpp:77
std::input_iterator_tag iterator_category
Definition generator.hpp:75
bool operator==(std::default_sentinel_t) const noexcept
Definition generator.hpp:97
Iterator begin()
Definition generator.hpp:100
std::default_sentinel_t end() noexcept
Definition generator.hpp:109
Generator & operator=(Generator &&o) noexcept
Definition generator.hpp:62
Generator(const Generator &)=delete
std::coroutine_handle< promise_type > handle_type
Definition generator.hpp:54
Generator(handle_type h) noexcept
Definition generator.hpp:57
Generator(Generator &&o) noexcept
Definition generator.hpp:61
~Generator()
Definition generator.hpp:69
Generator & operator=(const Generator &)=delete
Definition async_command.hpp:118
Definition generator.hpp:32
void return_void() noexcept
Definition generator.hpp:46
T current_value
Definition generator.hpp:33
std::exception_ptr exception
Definition generator.hpp:34
Generator get_return_object() noexcept
Definition generator.hpp:36
std::suspend_always final_suspend() noexcept
Definition generator.hpp:40
std::suspend_always yield_value(T value)
Definition generator.hpp:42
void unhandled_exception() noexcept
Definition generator.hpp:47
std::suspend_never await_transform(U &&)=delete
std::suspend_always initial_suspend() noexcept
Definition generator.hpp:39