C++ Library Extensions 2022.12.09
To help learn modern C++ programming
032-coroutine.hpp
Go to the documentation of this file.
1#include <iostream>
2#include <type_traits>
3#include <experimental/coroutine>
4
5/*
6
7 Suppose we purchased a new book. And this book has
8 20 chapters. In my case,
9
10 I usually read the Preface, then I read the back cover.
11
12 To understand Chapter 1, you need to understand
13 from chapter 2 through chapter 20.
14
15 Again, to understand chapter 2, you need to understand
16 from chapter 1, and chapter 3 through chapter 20.
17
18 Don't ever try to understand chapter 1 completely.
19 Also never try to understand chapter 2 completely before
20 you read all the chapters.
21
22 My usual strategy is...
23
24 I read from chapter 1 to chapter 20 very fast. I don't
25 get bogged down on a specific chapter. I think the chapter
26 seems difficult, I still read but I read fast and skip
27 a few sections. I try to read as much of the chapter
28 but I don't get bogged down a specific section.
29
30 Usually at the first round of reading, read your book
31 as quickly as fast. After reading from chapter 1 through
32 chapter 20, then come back to chapter 1 again.
33
34 Repeat this method to read the book several times.
35
36 By the time, you read the book 2 or 3 times, you can get
37 the big picture of the book. Then you delve into more
38 specific chapters and sections. This time, try to understand
39 all the nitty-gritty details.
40
41 My point is... don't get bogged down, don't try
42 to understand all at once. Repeat and think again.
43 Always get the big picture, the details become crystal
44 clear.
45
46 I bet corountine will be quite challenging for most of us.
47 But still don't get bogged down. Keep reading and keep watching
48 my videos. In future sessions, I will elaborate all the
49 details one by one.
50 */
51
52template<typename SemanticReturnType> class ResumableType;
53template<typename SemanticReturnType> class PromiseType;
54
55template<typename SemanticReturnType>
57{
58 template<typename Type> friend class ResumableType;
59
60 public:
61
62 // this is not compulsory but for our own use
64
66 = std::experimental::coroutine_handle<PromiseType>;
67
68 private:
69 // the result of operation will be stored
70 // in this member variable
71 SemanticReturnType m_semantic_return_value;
72
73 public:
74
75 // this member function is compulsory
76 // C++ compiler uses this function to create
77 // ResumableType<SemanticReturnType> object
78 // for our coroutine
80 {
81 return resumable_type{ promise_handle_type::from_promise(*this) };
82 }
83
84 // this is static member function
85 // this function is also compulsory
87 {
88 return resumable_type{nullptr};
89 }
90
91 // this is also COMPULSORY
93 {
94 std::terminate();
95 }
96
97 // this function is also compuslory
99 {
100 return std::experimental::suspend_always{};
101 }
102
103 // this function is also compulsory
105 {
106 return std::experimental::suspend_always{};
107 }
108
109 // for co_return value
110 auto return_value(SemanticReturnType value)
111 {
112 // store the result a+b to our member variable
113 this->m_semantic_return_value = value;
114
115 return std::experimental::suspend_always{};
116 }
117
118 // for co_yield value
119 auto yield_value(SemanticReturnType value)
120 {
121 // store the result a+b to our member variable
122 this->m_semantic_return_value = value;
123
124 return std::experimental::suspend_always{};
125 }
126
127};
128
129template<typename SemanticReturnType>
130class ResumableType
131{
132 template<typename Type> friend class PromiseType;
133
134 public:
135
136 // compulsory - this type alias is MUST-HAVE
137 // the C++ compiler needs to know
138 // promise_type, otherwise coroutine does not work.
139 // this promise_type declares to the Compiler that
140 // our promise type is PromiseType<SemanticReturnType>
142
143 // this is not compulsory, but it is very handy for our use
145 = std::experimental::coroutine_handle<promise_type>;
146
147 private:
148 // this member bridges between
149 // ResumableType and PromiseType
150 promise_handle_type m_promise_handle;
151
152 // this is not publicly accessible
154 m_promise_handle{handle} { }
155
156 public:
157 // disable copy constructor
158 // ResumableType is not copyable
159 ResumableType(const ResumableType&) = delete;
160
161 // move constructor
163 {
164 this->m_promise_handle = rhs.m_promise_handle;
165
166 // invalidate right hand side
167 rhs.m_promise_handle = nullptr;
168 }
169
170 SemanticReturnType get()
171 {
172 // PromiseType<SemanticReturnType>
173 auto promise =
174 this->m_promise_handle.promise();
175
176 return promise.m_semantic_return_value;
177 }
178
179 // we resume our suspended coroutine
180 // if m_promise_handle is invalid, then return false
181 // otherwise, resume coroutine, and return true if not yet done.
182 bool resume()
183 {
184 if(this->m_promise_handle)
185 {
186 this->m_promise_handle.resume();
187
188 return !this->m_promise_handle.done();
189 }
190 else
191 return false;
192 }
193
194 SemanticReturnType next()
195 {
196 this->resume();
197 return this->get();
198 }
199
201 {
202 if(this->m_promise_handle)
203 this->m_promise_handle.destroy();
204 }
205};
static auto get_return_object_on_allocation_failure()
auto initial_suspend()
auto get_return_object()
auto return_value(SemanticReturnType value)
void unhandled_exception()
friend class ResumableType
auto final_suspend()
std::experimental::coroutine_handle< PromiseType > promise_handle_type
auto yield_value(SemanticReturnType value)
SemanticReturnType next()
ResumableType(const ResumableType &)=delete
SemanticReturnType get()
ResumableType(ResumableType &&rhs)
std::experimental::coroutine_handle< promise_type > promise_handle_type