C++ Library Extensions 2022.12.09
To help learn modern C++ programming
033-coroutine.hpp
Go to the documentation of this file.
1#include <exception>
2#include <iostream>
3#include <experimental/coroutine>
4
5// class awaiter needs three member functions
6template<typename Type>
7struct awaiter
8{
9private:
10 Type m_value;
11
12public:
13 awaiter(Type value):
14 m_value{value} { }
15
16 bool await_ready() noexcept
17 {
18 // if it returns false
19 // co_await suspends the coroutine
20 return false;
21 }
22
23 void await_suspend(std::experimental::coroutine_handle<>) noexcept
24 { }
25
26 Type await_resume() noexcept
27 { return this->m_value; }
28};
29
30template<typename Type>
32{
33
34private:
35 Type m_value;
36
37public:
38 awaitable(Type value):
39 m_value{ value } { }
40
41 auto operator co_await()
42 {
43 return awaiter<Type>{ this->m_value };
44 }
45};
46
47
48// this is primary class template
49// we assume SemanticReturnType is NOT type void
50template<typename SemanticReturnType>
52{
53 public:
54
55 template<typename ReturnType>
57 {
58 template<typename Type> friend class ResumableType;
59
60 public:
62
64 = std::experimental::coroutine_handle<PromiseType>;
65
66 private:
67 // semantic return value
68 ReturnType m_return_value;
69
70 public:
71
72 // this function is COMPULSORY
73 // this static member is called
74 // when C++ compiler fails to dynamically allocate
75 // ResumableType
77 {
78 return resumable_type{ nullptr };
79 }
80
81 // this function is COMPULSORY
82 // this member is used to create
83 // ResumableType by C++ compiler.
85 {
86 return
87 resumable_type{ coroutine_frame_type::from_promise(*this) };
88 }
89
90 // this function is COMPULSORY
91 // it returns a type of awaiter
92 // i will talk about this function very soon.
94 {
95 return std::experimental::suspend_always{};
96 }
97
98 // this function is also COMPULSORY
100 {
101 return std::experimental::suspend_always{};
102 }
103
104 // this function is also COMPULSORY
106 {
107 throw;
108 }
109
110 // co_await value
111 template<typename Type>
112 auto await_transform(Type&& value)
113 {
114 return awaitable<Type>{ std::forward<Type>(value) };
115 }
116
117 // co_return value
118 void return_value(ReturnType value)
119 {
120 // std::cout << "value = " << value << std::endl;
121
122 this->m_return_value = value;
123 }
124
125 // co_yield value
126 void yield_value(ReturnType value)
127 {
128 this->m_return_value = value;
129 }
130 };
131
132 // this type alias for promise_type is COMPULSORY.
134
137
138 private:
139 // this handle is a bridge between
140 // ResumableType and PromiseType
141 coroutine_frame_type m_frame_handle;
142
144 m_frame_handle{handle} { }
145
146 public:
147 ResumableType(const ResumableType& ) = delete;
148
150 m_frame_handle{rhs.m_frame_handle}
151 {
152 // we have to invalidate right hand side rhs
153 // in the move constructor
154 rhs.m_frame_handle = nullptr;
155 }
156
157 bool resume()
158 {
159 if(!this->m_frame_handle)
160 return false;
161 else
162 {
163 this->m_frame_handle.resume();
164
165 return !this->m_frame_handle.done();
166 }
167 }
168
169 SemanticReturnType get()
170 {
171 if(this->m_frame_handle)
172 {
173 auto promise =
174 this->m_frame_handle.promise();
175
176 return promise.m_return_value;
177 }
178 else
179 throw std::exception{};
180 }
181
182 void destroy()
183 {
184 if(this->m_frame_handle)
185 {
186 this->m_frame_handle.destroy();
187 this->m_frame_handle = nullptr;
188 }
189 }
190
192 {
193 this->destroy();
194 }
195
196};
197
199
200// this is specialization for type void
201template<>
202class ResumableType<void>
203{
204 public:
205
207 {
208 template<typename Type> friend class ResumableType;
209
210 public:
212
214 = std::experimental::coroutine_handle<PromiseType>;
215
216 public:
217
218 // this function is COMPULSORY
219 // this static member is called
220 // when C++ compiler fails to dynamically allocate
221 // ResumableType
223 {
224 return resumable_type{ nullptr };
225 }
226
227 // this function is COMPULSORY
228 // this member is used to create
229 // ResumableType by C++ compiler.
231 {
232 return
233 resumable_type{ coroutine_frame_type::from_promise(*this) };
234 }
235
236 // this function is COMPULSORY
237 // it returns a type of awaiter
238 // i will talk about this function very soon.
240 {
241 return std::experimental::suspend_always{};
242 }
243
244 // this function is also COMPULSORY
246 {
247 return std::experimental::suspend_always{};
248 }
249
250 // this function is also COMPULSORY
252 {
253 throw;
254 }
255
256 // co_await value
257 template<typename Type>
258 auto await_transform(Type&& value)
259 {
260 return awaitable<Type>{ std::forward<Type>(value) };
261 }
262
263 // co_return
265 { }
266 };
267
268 // this type alias for promise_type is COMPULSORY.
270
273
274 private:
275 // this handle is a bridge between
276 // ResumableType and PromiseType
277 coroutine_frame_type m_frame_handle;
278
280 m_frame_handle{handle} { }
281
282 public:
283 ResumableType(const ResumableType& ) = delete;
284
286 m_frame_handle{rhs.m_frame_handle}
287 {
288 // we have to invalidate right hand side rhs
289 // in the move constructor
290 rhs.m_frame_handle = nullptr;
291 }
292
293 bool resume()
294 {
295 if(!this->m_frame_handle)
296 return false;
297 else
298 {
299 this->m_frame_handle.resume();
300
301 return !this->m_frame_handle.done();
302 }
303 }
304
305 void destroy()
306 {
307 if(this->m_frame_handle)
308 {
309 this->m_frame_handle.destroy();
310 this->m_frame_handle = nullptr;
311 }
312 }
313
315 {
316 this->destroy();
317 }
318
319};
320
321template<typename SemanticReturnType = void>
323
324
auto await_transform(Type &&value)
void return_value(ReturnType value)
static auto get_return_object_on_allocation_failure()
std::experimental::coroutine_handle< PromiseType > coroutine_frame_type
void yield_value(ReturnType value)
std::experimental::coroutine_handle< PromiseType > coroutine_frame_type
static auto get_return_object_on_allocation_failure()
ResumableType(const ResumableType &)=delete
ResumableType(ResumableType &&rhs)
typename promise_type::coroutine_frame_type coroutine_frame_type
ResumableType(const ResumableType &)=delete
friend class PromiseType
SemanticReturnType get()
ResumableType(ResumableType &&rhs)
typename promise_type::coroutine_frame_type coroutine_frame_type
awaitable(Type value)
bool await_ready() noexcept
awaiter(Type value)
void await_suspend(std::experimental::coroutine_handle<>) noexcept
Type await_resume() noexcept