5
5
#ifndef CPPCORO_GENERATOR_HPP_INCLUDED
6
6
#define CPPCORO_GENERATOR_HPP_INCLUDED
7
7
8
+ #include < cppcoro/detail/dummy_coroutine.hpp>
9
+
8
10
#include < experimental/coroutine>
9
11
#include < type_traits>
10
12
#include < utility>
@@ -41,9 +43,52 @@ namespace cppcoro
41
43
return {};
42
44
}
43
45
44
- std::experimental::suspend_always final_suspend () noexcept
46
+ auto final_suspend () noexcept
45
47
{
46
- return {};
48
+ class awaitable
49
+ {
50
+ public:
51
+
52
+ awaitable (promise_type* promise) noexcept
53
+ : m_promise(promise)
54
+ {}
55
+
56
+ constexpr bool await_ready () noexcept { return false ; }
57
+
58
+ std::experimental::coroutine_handle<> await_suspend (
59
+ std::experimental::coroutine_handle<> coroutine)
60
+ {
61
+ // If we are the root generator then just suspend without
62
+ // resuming anything else to return control back to operator++().
63
+ // Otherwise, we resume the parent generator.
64
+ auto * const root = m_promise->m_root ;
65
+ if (m_promise == root)
66
+ {
67
+ return detail::dummy_coroutine::handle ();
68
+ }
69
+
70
+ // Set the leaf of the root generator to be the parent generator
71
+ // we're about to resume.
72
+ auto * parent = m_promise->m_parentOrLeaf ;
73
+ root->m_parentOrLeaf = parent;
74
+
75
+ // Reset our root/leaf to be self-contained.
76
+ m_promise->m_root = m_promise;
77
+ m_promise->m_parentOrLeaf = m_promise;
78
+
79
+ // Resume the parent now that we're suspended.
80
+ return parent->handle ();
81
+ }
82
+
83
+ void await_resume () noexcept {}
84
+
85
+ private:
86
+
87
+ promise_type* m_promise;
88
+
89
+ };
90
+
91
+ return awaitable{ this };
47
92
}
48
93
49
94
void unhandled_exception () noexcept
@@ -55,13 +100,13 @@ namespace cppcoro
55
100
56
101
std::experimental::suspend_always yield_value (T& value) noexcept
57
102
{
58
- m_value = std::addressof (value);
103
+ m_root-> m_value = std::addressof (value);
59
104
return {};
60
105
}
61
106
62
107
std::experimental::suspend_always yield_value (T&& value) noexcept
63
108
{
64
- m_value = std::addressof (value);
109
+ m_root-> m_value = std::addressof (value);
65
110
return {};
66
111
}
67
112
@@ -81,40 +126,33 @@ namespace cppcoro
81
126
82
127
bool await_ready () noexcept
83
128
{
84
- return this -> m_childPromise == nullptr ;
129
+ return m_childPromise == nullptr || m_childPromise-> is_complete () ;
85
130
}
86
131
87
- void await_suspend (std::experimental::coroutine_handle<promise_type>) noexcept
88
- {}
132
+ std::experimental::coroutine_handle<> await_suspend (
133
+ std::experimental::coroutine_handle<promise_type> parentHandle) noexcept
134
+ {
135
+ auto & parentPromise = parentHandle.promise ();
136
+ auto * rootPromise = parentPromise.m_root ;
137
+ m_childPromise->m_root = rootPromise;
138
+ m_childPromise->m_parentOrLeaf = &parentPromise;
139
+ rootPromise->m_parentOrLeaf = m_childPromise;
140
+ return m_childPromise->handle ();
141
+ }
89
142
90
143
void await_resume ()
91
144
{
92
- if (this -> m_childPromise != nullptr )
145
+ if (m_childPromise != nullptr )
93
146
{
94
- this -> m_childPromise ->throw_if_exception ();
147
+ m_childPromise->throw_if_exception ();
95
148
}
96
149
}
97
150
98
151
private:
99
152
promise_type* m_childPromise;
100
153
};
101
154
102
- if (generator.m_promise != nullptr )
103
- {
104
- m_root->m_parentOrLeaf = generator.m_promise ;
105
- generator.m_promise ->m_root = m_root;
106
- generator.m_promise ->m_parentOrLeaf = this ;
107
- generator.m_promise ->resume ();
108
-
109
- if (!generator.m_promise ->is_complete ())
110
- {
111
- return awaitable{ generator.m_promise };
112
- }
113
-
114
- m_root->m_parentOrLeaf = this ;
115
- }
116
-
117
- return awaitable{ nullptr };
155
+ return awaitable{ generator.m_promise };
118
156
}
119
157
120
158
// Don't allow any use of 'co_await' inside the recursive_generator coroutine.
@@ -123,7 +161,7 @@ namespace cppcoro
123
161
124
162
void destroy () noexcept
125
163
{
126
- std::experimental::coroutine_handle<promise_type>:: from_promise (* this ).destroy ();
164
+ handle ( ).destroy ();
127
165
}
128
166
129
167
void throw_if_exception ()
@@ -136,35 +174,33 @@ namespace cppcoro
136
174
137
175
bool is_complete () noexcept
138
176
{
139
- return std::experimental::coroutine_handle<promise_type>:: from_promise (* this ).done ();
177
+ return handle ( ).done ();
140
178
}
141
179
142
180
T& value () noexcept
143
181
{
144
182
assert (this == m_root);
145
183
assert (!is_complete ());
146
- return *(m_parentOrLeaf-> m_value ) ;
184
+ return *m_value;
147
185
}
148
186
149
187
void pull () noexcept
150
188
{
151
189
assert (this == m_root);
152
190
assert (!m_parentOrLeaf->is_complete ());
153
-
154
191
m_parentOrLeaf->resume ();
155
-
156
- while (m_parentOrLeaf != this && m_parentOrLeaf->is_complete ())
157
- {
158
- m_parentOrLeaf = m_parentOrLeaf->m_parentOrLeaf ;
159
- m_parentOrLeaf->resume ();
160
- }
161
192
}
162
193
163
194
private:
164
195
196
+ auto handle () noexcept
197
+ {
198
+ return std::experimental::coroutine_handle<promise_type>::from_promise (*this );
199
+ }
200
+
165
201
void resume () noexcept
166
202
{
167
- std::experimental::coroutine_handle<promise_type>:: from_promise (* this ).resume ();
203
+ handle ( ).resume ();
168
204
}
169
205
170
206
T* m_value;
0 commit comments