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