33template <
typename T,
typename V=
void>
36 using ret_t = std::conditional_t<std::is_void_v<V>, std::monostate,
V>;
40 std::optional<T> _value = std::nullopt;
41 std::optional<ret_t> _ret = std::nullopt;
42 std::coroutine_handle<promise_type> _handle;
49 return Generator<T>{std::coroutine_handle<promise_type>::from_promise(*
this)};
52 std::suspend_never initial_suspend() {
return {}; }
53 std::suspend_always final_suspend()
noexcept {
return {}; }
56 _ret.emplace(std::monostate{});
60 std::suspend_always yield_value(
U&& value) {
61 _value.emplace(std::forward<U>(value));
65 void unhandled_exception() {}
67 bool has_value()
const {
return _value.has_value(); }
69 const T& value()
const {
return *_value; }
70 T& value() {
return *_value; }
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); }
76 operator bool()
const {
return has_value(); }
82 _handle(
other._handle)
88 if (_handle) _handle.destroy();
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;
102 bool _maybe_finish() {
103 if (_handle and _handle.done()) {
104 _ret.emplace(_handle.promise().move_return_value());
116 if (
not _handle)
return false;
117 if (_maybe_finish())
return false;
119 if (_maybe_finish())
return false;
131 const T&
operator*()
const {
return _handle.promise().value(); }
136 const T*
operator->()
const {
return &_handle.promise().value(); }
146 size_t count()
const {
return _count; }
158 std::coroutine_handle<promise_type> _handle;
159 std::optional<ret_t> _ret;
178 std::optional<G> generator = std::nullopt;
180 using Value =
decltype(*std::declval<G>());
194 if (
not generator)
return false;
196 return (
bool) *generator;
200 if (generator) ++(*generator);
204 auto operator*()
const {
return **generator; }
205 auto operator->()
const {
return (*generator).operator->(); }
206 auto operator*() {
return **generator; }
207 auto operator->() {
return (*generator).operator->(); }
209 bool is_valid()
const {
210 if (
not generator)
return false;
211 return (
bool) *generator;
214 operator bool()
const {
return is_valid(); }
229 bool yielded =
false;
235 bool next() { yielded =
true;
return false; }
239 const T& operator*()
const {
return item; }
240 T& operator*() {
return item; }
241 const T* operator->()
const {
return &item; }
242 T* operator->() {
return &item; }
244 bool is_valid()
const {
return not yielded; }
245 operator bool()
const {
return is_valid(); }
A generator that yields exactly one item, then exhausts.
A C++20 coroutine-based generator that lazily yields values of type T.
bool next()
Advance to the next yielded value. Returns true if a new value is available.
ret_t & get_return_value()
Access the coroutine's return value (only valid after is_finished() is true).
bool is_valid() const
Returns true if the generator has more values to produce.
bool is_finished() const
Returns true if the coroutine has finished (reached co_return).
const ret_t & get_return_value() const
Access the coroutine's return value (only valid after is_finished() is true).
T * operator->()
Access the most recently yielded value via pointer.
const T & operator*() const
Access the most recently yielded value.
Generator & operator++()
Advance to the next value (same as next()).
const T * operator->() const
Access the most recently yielded value via pointer.
size_t count() const
The number of values yielded so far.
T & operator*()
Access the most recently yielded value.
A system for maintaining parent-child relationships on entities.
A wrapper around an optional Generator.
and
Transform a traversal inductively, threading parent context through successors.