entttree 0.1.0
Hierarchical entity management for EnTT
Loading...
Searching...
No Matches
generator.h
Go to the documentation of this file.
1
6#pragma once
7
8#include <coroutine>
9#include <optional>
10#include <variant>
11
12namespace entttree {
13
33template <typename T, typename V=void>
34struct Generator {
35
36 using ret_t = std::conditional_t<std::is_void_v<V>, std::monostate, V>;
37
38 struct promise_type {
39 private:
40 std::optional<T> _value = std::nullopt;
41 std::optional<ret_t> _ret = std::nullopt;
42 std::coroutine_handle<promise_type> _handle;
43
44 friend struct Generator<T>;
45
46 public:
47
48 Generator<T> get_return_object() {
49 return Generator<T>{std::coroutine_handle<promise_type>::from_promise(*this)};
50 }
51
52 std::suspend_never initial_suspend() { return {}; }
53 std::suspend_always final_suspend() noexcept { return {}; }
54
55 void return_void() {
56 _ret.emplace(std::monostate{});
57 }
58
59 template <typename U>
60 std::suspend_always yield_value(U&& value) {
61 _value.emplace(std::forward<U>(value));
62 return {};
63 }
64
65 void unhandled_exception() {}
66
67 bool has_value() const { return _value.has_value(); }
68
69 const T& value() const { return *_value; }
70 T& value() { return *_value; }
71
72 ret_t& get_return_value() { return *_ret; }
73 const ret_t& get_return_value() const { return *_ret; }
74 ret_t move_return_value() { return std::move(*_ret); }
75
76 operator bool() const { return has_value(); }
77
78 }; // promise_type
79
80 Generator(const Generator&) = delete;
82 _handle(other._handle)
83 {
84 other._handle = {};
85 }
86
87 ~Generator() {
88 if (_handle) _handle.destroy();
89 }
90
91 Generator& operator=(const Generator&) = delete;
92 Generator& operator=(Generator&& other) {
93 if (this == &other) return *this;
94 if (_handle) _handle.destroy();
95 _handle = other._handle;
96 other._handle = {};
97 return *this;
98 }
99
100private:
101
102 bool _maybe_finish() {
103 if (_handle and _handle.done()) {
104 _ret.emplace(_handle.promise().move_return_value());
105 _handle.destroy();
106 _handle = {};
107 return true;
108 }
109 return false;
110 }
111
112public:
113
115 bool next() {
116 if (not _handle) return false;
117 if (_maybe_finish()) return false;
118 _handle.resume();
119 if (_maybe_finish()) return false;
120 _count += 1;
121 return true;
122 }
123
126 next();
127 return *this;
128 }
129
131 const T& operator*() const { return _handle.promise().value(); }
133 T& operator*() { return _handle.promise().value(); }
134
136 const T* operator->() const { return &_handle.promise().value(); }
138 T* operator->() { return &_handle.promise().value(); }
139
141 bool is_valid() const { return _handle and not _handle.done(); }
143 operator bool() const { return is_valid(); }
144
146 size_t count() const { return _count; }
147
149 bool is_finished() const { return _ret.has_value(); }
150
152 ret_t& get_return_value() { return *_ret; }
154 const ret_t& get_return_value() const { return *_ret; }
155
156private:
157
158 std::coroutine_handle<promise_type> _handle;
159 std::optional<ret_t> _ret;
160 size_t _count = 0;
161
162 Generator(std::coroutine_handle<promise_type> handle) : _handle(handle) {}
163
164};
165
166
176template <typename G>
178 std::optional<G> generator = std::nullopt;
179
180 using Value = decltype(*std::declval<G>());
181
182 MaybeGenerator() = default;
183
184 MaybeGenerator(G&& gen): generator(std::move(gen)) {}
185 MaybeGenerator(const G& gen): generator(gen) {}
186
187 MaybeGenerator(const MaybeGenerator&) = default;
188 MaybeGenerator(MaybeGenerator&&) = default;
189
190 MaybeGenerator& operator=(const MaybeGenerator&) = default;
191 MaybeGenerator& operator=(MaybeGenerator&&) = default;
192
193 bool next() {
194 if (not generator) return false;
195 ++(*generator);
196 return (bool) *generator;
197 }
198
199 MaybeGenerator& operator++() {
200 if (generator) ++(*generator);
201 return *this;
202 }
203
204 auto operator*() const { return **generator; }
205 auto operator->() const { return (*generator).operator->(); }
206 auto operator*() { return **generator; }
207 auto operator->() { return (*generator).operator->(); }
208
209 bool is_valid() const {
210 if (not generator) return false;
211 return (bool) *generator;
212 }
213
214 operator bool() const { return is_valid(); }
215};
216
217
226template <typename T>
228 T item;
229 bool yielded = false;
230
231 FixedItemGenerator(): yielded(true) {}
232 FixedItemGenerator(T&& item): item(std::move(item)) {}
233 FixedItemGenerator(const T& item): item(item) {}
234
235 bool next() { yielded = true; return false; }
236
237 FixedItemGenerator& operator++() { next(); return *this; }
238
239 const T& operator*() const { return item; }
240 T& operator*() { return item; }
241 const T* operator->() const { return &item; }
242 T* operator->() { return &item; }
243
244 bool is_valid() const { return not yielded; }
245 operator bool() const { return is_valid(); }
246};
247
248
249} // namespace entttree
A generator that yields exactly one item, then exhausts.
Definition generator.h:227
A C++20 coroutine-based generator that lazily yields values of type T.
Definition generator.h:34
bool next()
Advance to the next yielded value. Returns true if a new value is available.
Definition generator.h:115
ret_t & get_return_value()
Access the coroutine's return value (only valid after is_finished() is true).
Definition generator.h:152
bool is_valid() const
Returns true if the generator has more values to produce.
Definition generator.h:141
bool is_finished() const
Returns true if the coroutine has finished (reached co_return).
Definition generator.h:149
const ret_t & get_return_value() const
Access the coroutine's return value (only valid after is_finished() is true).
Definition generator.h:154
T * operator->()
Access the most recently yielded value via pointer.
Definition generator.h:138
const T & operator*() const
Access the most recently yielded value.
Definition generator.h:131
Generator & operator++()
Advance to the next value (same as next()).
Definition generator.h:125
const T * operator->() const
Access the most recently yielded value via pointer.
Definition generator.h:136
size_t count() const
The number of values yielded so far.
Definition generator.h:146
T & operator*()
Access the most recently yielded value.
Definition generator.h:133
A system for maintaining parent-child relationships on entities.
Definition hierarchy.h:37
A wrapper around an optional Generator.
Definition generator.h:177
and
Transform a traversal inductively, threading parent context through successors.
Definition traverse.h:542