55#ifndef CPPCORO_GENERATOR_HPP_INCLUDED
66#define CPPCORO_GENERATOR_HPP_INCLUDED
77
8+ #include < cppcoro/detail/dummy_coroutine.hpp>
9+
810#include < experimental/coroutine>
911#include < type_traits>
1012#include < utility>
@@ -41,9 +43,52 @@ namespace cppcoro
4143 return {};
4244 }
4345
44- std::experimental::suspend_always final_suspend () noexcept
46+ auto final_suspend () noexcept
4547 {
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 };
4792 }
4893
4994 void unhandled_exception () noexcept
@@ -55,13 +100,13 @@ namespace cppcoro
55100
56101 std::experimental::suspend_always yield_value (T& value) noexcept
57102 {
58- m_value = std::addressof (value);
103+ m_root-> m_value = std::addressof (value);
59104 return {};
60105 }
61106
62107 std::experimental::suspend_always yield_value (T&& value) noexcept
63108 {
64- m_value = std::addressof (value);
109+ m_root-> m_value = std::addressof (value);
65110 return {};
66111 }
67112
@@ -81,40 +126,33 @@ namespace cppcoro
81126
82127 bool await_ready () noexcept
83128 {
84- return this -> m_childPromise == nullptr ;
129+ return m_childPromise == nullptr || m_childPromise-> is_complete () ;
85130 }
86131
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+ }
89142
90143 void await_resume ()
91144 {
92- if (this -> m_childPromise != nullptr )
145+ if (m_childPromise != nullptr )
93146 {
94- this -> m_childPromise ->throw_if_exception ();
147+ m_childPromise->throw_if_exception ();
95148 }
96149 }
97150
98151 private:
99152 promise_type* m_childPromise;
100153 };
101154
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 };
118156 }
119157
120158 // Don't allow any use of 'co_await' inside the recursive_generator coroutine.
@@ -123,7 +161,7 @@ namespace cppcoro
123161
124162 void destroy () noexcept
125163 {
126- std::experimental::coroutine_handle<promise_type>:: from_promise (* this ).destroy ();
164+ handle ( ).destroy ();
127165 }
128166
129167 void throw_if_exception ()
@@ -136,35 +174,33 @@ namespace cppcoro
136174
137175 bool is_complete () noexcept
138176 {
139- return std::experimental::coroutine_handle<promise_type>:: from_promise (* this ).done ();
177+ return handle ( ).done ();
140178 }
141179
142180 T& value () noexcept
143181 {
144182 assert (this == m_root);
145183 assert (!is_complete ());
146- return *(m_parentOrLeaf-> m_value ) ;
184+ return *m_value;
147185 }
148186
149187 void pull () noexcept
150188 {
151189 assert (this == m_root);
152190 assert (!m_parentOrLeaf->is_complete ());
153-
154191 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- }
161192 }
162193
163194 private:
164195
196+ auto handle () noexcept
197+ {
198+ return std::experimental::coroutine_handle<promise_type>::from_promise (*this );
199+ }
200+
165201 void resume () noexcept
166202 {
167- std::experimental::coroutine_handle<promise_type>:: from_promise (* this ).resume ();
203+ handle ( ).resume ();
168204 }
169205
170206 T* m_value;
0 commit comments