Py2Cpp 1.6.5
Loading...
Searching...
No Matches
recursive_gen.hpp
Go to the documentation of this file.
1
9#pragma once
10
11#include <cassert>
12#include <coroutine>
13#include <exception>
14#include <iterator>
15#include <utility>
16
17namespace py {
18
30 template <typename T> class [[nodiscard]] RecursiveGenerator {
31 public:
32 class promise_type final {
33 public:
34 promise_type() noexcept
35 : m_value(nullptr), m_exception(nullptr), m_root(this), m_parentOrLeaf(this) {}
36
37 promise_type(const promise_type&) = delete;
41 ~promise_type() = default;
42
44 return RecursiveGenerator{std::coroutine_handle<promise_type>::from_promise(*this)};
45 }
46
47 std::suspend_always initial_suspend() noexcept { return {}; }
48 std::suspend_always final_suspend() noexcept { return {}; }
49 void return_void() noexcept {}
50
51 void unhandled_exception() noexcept { m_exception = std::current_exception(); }
52
53 std::suspend_always yield_value(T& value) noexcept {
54 m_value = std::addressof(value);
55 return {};
56 }
57
58 std::suspend_always yield_value(T&& value) noexcept {
59 m_value = std::addressof(value);
60 return {};
61 }
62
63 auto yield_value(RecursiveGenerator&& generator) noexcept {
64 return yield_value(generator);
65 }
66
67 auto yield_value(RecursiveGenerator& generator) noexcept {
68 struct awaitable {
69 awaitable(promise_type* childPromise) : m_childPromise(childPromise) {}
70
71 bool await_ready() noexcept { return this->m_childPromise == nullptr; }
72
73 void await_suspend(std::coroutine_handle<promise_type> /*unused*/) noexcept {}
74
75 void await_resume() {
76 if (this->m_childPromise != nullptr) {
77 this->m_childPromise->throw_if_exception();
78 }
79 }
80
81 private:
82 promise_type* m_childPromise;
83 };
84
85 if (generator.m_promise != nullptr) {
86 m_root->m_parentOrLeaf = generator.m_promise;
87 generator.m_promise->m_root = m_root;
88 generator.m_promise->m_parentOrLeaf = this;
89 generator.m_promise->resume();
90
91 if (!generator.m_promise->is_complete()) {
92 return awaitable{generator.m_promise};
93 }
94
95 m_root->m_parentOrLeaf = this;
96 }
97
98 return awaitable{nullptr};
99 }
100
101 template <typename U> std::suspend_never await_transform(U&&) = delete;
102
103 void destroy() noexcept {
104 std::coroutine_handle<promise_type>::from_promise(*this).destroy();
105 }
106
108 if (m_exception != nullptr) {
109 std::rethrow_exception(m_exception);
110 }
111 }
112
113 bool is_complete() noexcept {
114 return std::coroutine_handle<promise_type>::from_promise(*this).done();
115 }
116
117 T& value() noexcept {
118 assert(this == m_root);
119 assert(!is_complete());
120 return *m_parentOrLeaf->m_value;
121 }
122
123 void pull() noexcept {
124 assert(!m_parentOrLeaf->is_complete());
125
126 m_parentOrLeaf->resume();
127
128 while (m_parentOrLeaf != this && m_parentOrLeaf->is_complete()) {
129 m_parentOrLeaf = m_parentOrLeaf->m_parentOrLeaf;
130 m_parentOrLeaf->resume();
131 }
132 }
133
134 private:
135 void resume() noexcept {
136 std::coroutine_handle<promise_type>::from_promise(*this).resume();
137 }
138
139 T* m_value;
140 std::exception_ptr m_exception;
141 promise_type* m_root;
142 promise_type* m_parentOrLeaf;
143 };
144
145 RecursiveGenerator() noexcept : m_promise(nullptr) {}
146
148 : m_promise(std::exchange(other.m_promise, nullptr)) {}
149
151 if (this != &other) {
152 if (m_promise != nullptr) {
153 m_promise->destroy();
154 }
155 m_promise = std::exchange(other.m_promise, nullptr);
156 }
157 return *this;
158 }
159
162
164 if (m_promise != nullptr) {
165 m_promise->destroy();
166 }
167 }
168
169 class iterator {
170 public:
171 using iterator_category = std::input_iterator_tag;
172 using difference_type = std::ptrdiff_t;
173 using value_type = std::remove_reference_t<T>;
174 using reference = std::conditional_t<std::is_reference_v<T>, T, T&>;
175 using pointer = std::add_pointer_t<T>;
176
177 iterator() noexcept : m_promise(nullptr) {}
178
179 explicit iterator(promise_type* promise) noexcept : m_promise(promise) {}
180
181 bool operator==(const iterator& other) const noexcept {
182 return m_promise == other.m_promise;
183 }
184
185 bool operator!=(const iterator& other) const noexcept {
186 return m_promise != other.m_promise;
187 }
188
190 assert(m_promise != nullptr);
191
192 m_promise->pull();
193 if (m_promise->is_complete()) {
194 auto* temp = m_promise;
195 m_promise = nullptr;
196 temp->throw_if_exception();
197 }
198
199 return *this;
200 }
201
202 void operator++(int) { (void)operator++(); }
203
204 reference operator*() const noexcept {
205 assert(m_promise != nullptr);
206 return static_cast<reference>(m_promise->value());
207 }
208
209 pointer operator->() const noexcept { return std::addressof(operator*()); }
210
211 private:
212 promise_type* m_promise;
213 };
214
216 if (m_promise != nullptr) {
217 m_promise->pull();
218 if (!m_promise->is_complete()) {
219 return iterator(m_promise);
220 }
221
222 m_promise->throw_if_exception();
223 }
224
225 return iterator(nullptr);
226 }
227
228 iterator end() noexcept { return iterator(nullptr); }
229
230 void swap(RecursiveGenerator& other) noexcept { std::swap(m_promise, other.m_promise); }
231
232 private:
233 friend class promise_type;
234
235 explicit RecursiveGenerator(std::coroutine_handle<promise_type> h) noexcept
236 : m_promise(&h.promise()) {}
237
238 promise_type* m_promise;
239 };
240
241 template <typename T> void swap(RecursiveGenerator<T>& a, RecursiveGenerator<T>& b) noexcept {
242 a.swap(b);
243 }
244
245} // namespace py
Definition recursive_gen.hpp:169
iterator() noexcept
Definition recursive_gen.hpp:177
bool operator==(const iterator &other) const noexcept
Definition recursive_gen.hpp:181
iterator(promise_type *promise) noexcept
Definition recursive_gen.hpp:179
bool operator!=(const iterator &other) const noexcept
Definition recursive_gen.hpp:185
std::add_pointer_t< T > pointer
Definition recursive_gen.hpp:175
std::ptrdiff_t difference_type
Definition recursive_gen.hpp:172
reference operator*() const noexcept
Definition recursive_gen.hpp:204
iterator & operator++()
Definition recursive_gen.hpp:189
std::input_iterator_tag iterator_category
Definition recursive_gen.hpp:171
std::conditional_t< std::is_reference_v< T >, T, T & > reference
Definition recursive_gen.hpp:174
pointer operator->() const noexcept
Definition recursive_gen.hpp:209
std::remove_reference_t< T > value_type
Definition recursive_gen.hpp:173
void operator++(int)
Definition recursive_gen.hpp:202
Definition recursive_gen.hpp:32
std::suspend_always yield_value(T &value) noexcept
Definition recursive_gen.hpp:53
std::suspend_always yield_value(T &&value) noexcept
Definition recursive_gen.hpp:58
promise_type & operator=(const promise_type &)=delete
void pull() noexcept
Definition recursive_gen.hpp:123
bool is_complete() noexcept
Definition recursive_gen.hpp:113
promise_type(const promise_type &)=delete
RecursiveGenerator get_return_object() noexcept
Definition recursive_gen.hpp:43
std::suspend_always final_suspend() noexcept
Definition recursive_gen.hpp:48
void unhandled_exception() noexcept
Definition recursive_gen.hpp:51
std::suspend_never await_transform(U &&)=delete
void return_void() noexcept
Definition recursive_gen.hpp:49
promise_type() noexcept
Definition recursive_gen.hpp:34
void destroy() noexcept
Definition recursive_gen.hpp:103
std::suspend_always initial_suspend() noexcept
Definition recursive_gen.hpp:47
void throw_if_exception()
Definition recursive_gen.hpp:107
promise_type(promise_type &&)=delete
T & value() noexcept
Definition recursive_gen.hpp:117
auto yield_value(RecursiveGenerator &generator) noexcept
Definition recursive_gen.hpp:67
promise_type & operator=(promise_type &&)=delete
auto yield_value(RecursiveGenerator &&generator) noexcept
Definition recursive_gen.hpp:63
Recursive generator using C++20 coroutines with symmetric transfer.
Definition recursive_gen.hpp:30
RecursiveGenerator & operator=(RecursiveGenerator &&other) noexcept
Definition recursive_gen.hpp:150
RecursiveGenerator() noexcept
Definition recursive_gen.hpp:145
RecursiveGenerator(RecursiveGenerator &&other) noexcept
Definition recursive_gen.hpp:147
iterator begin()
Definition recursive_gen.hpp:215
~RecursiveGenerator()
Definition recursive_gen.hpp:163
RecursiveGenerator & operator=(const RecursiveGenerator &)=delete
void swap(RecursiveGenerator &other) noexcept
Definition recursive_gen.hpp:230
iterator end() noexcept
Definition recursive_gen.hpp:228
RecursiveGenerator(const RecursiveGenerator &)=delete
Python-like utilities and data structures for C++.
Definition dict.hpp:18
void swap(RecursiveGenerator< T > &a, RecursiveGenerator< T > &b) noexcept
Definition recursive_gen.hpp:241