1
- // itlib-generator v1.01
1
+ // itlib-generator v1.02
2
2
//
3
3
// Simple coroutine generator class for C++20 and later
4
4
//
28
28
//
29
29
// VERSION HISTORY
30
30
//
31
+ // 1.02 (2024-07-18) Store exception to work around clang's ridiculous
32
+ // and overly complicated handling of coroutines
31
33
// 1.01 (2024-07-18) Add missing header for newer, more stringent compilers
32
34
// 1.00 (2024-07-17) Initial release
33
35
//
76
78
#pragma once
77
79
#include < coroutine>
78
80
#include < type_traits>
81
+ #include < exception>
79
82
#include < optional>
80
83
#include < utility>
81
84
@@ -107,6 +110,7 @@ class generator {
107
110
108
111
struct promise_type {
109
112
generator_value<T> m_val;
113
+ std::exception_ptr m_exception;
110
114
111
115
promise_type () noexcept = default ;
112
116
@@ -126,7 +130,9 @@ class generator {
126
130
return {};
127
131
}
128
132
void return_void () noexcept {}
129
- void unhandled_exception () { throw ; }
133
+ void unhandled_exception () noexcept {
134
+ m_exception = std::current_exception ();
135
+ }
130
136
131
137
value_ret_t val () & noexcept {
132
138
return *m_val;
@@ -171,8 +177,7 @@ class generator {
171
177
172
178
generator_value<T> next () {
173
179
if (done ()) return {};
174
- m_handle.promise ().clear_value ();
175
- m_handle.resume ();
180
+ safe_resume (m_handle);
176
181
return std::move (m_handle.promise ().m_val );
177
182
}
178
183
@@ -193,8 +198,7 @@ class generator {
193
198
}
194
199
195
200
pseudo_iterator& operator ++() {
196
- m_handle.promise ().clear_value ();
197
- m_handle.resume ();
201
+ safe_resume (m_handle);
198
202
return *this ;
199
203
}
200
204
@@ -208,7 +212,7 @@ class generator {
208
212
};
209
213
210
214
pseudo_iterator begin () {
211
- m_handle. resume ( );
215
+ safe_resume (m_handle );
212
216
return pseudo_iterator{m_handle};
213
217
}
214
218
@@ -217,6 +221,15 @@ class generator {
217
221
}
218
222
219
223
private:
224
+ static void safe_resume (handle_t & h) {
225
+ auto & p = h.promise ();
226
+ p.clear_value ();
227
+ h.resume ();
228
+ if (p.m_exception ) {
229
+ std::rethrow_exception (p.m_exception );
230
+ }
231
+ }
232
+
220
233
handle_t m_handle;
221
234
explicit generator (handle_t handle) noexcept : m_handle(handle) {}
222
235
};
0 commit comments