1 | // <coroutine> -*- C++ -*- |
2 | |
3 | // Copyright (C) 2019-2021 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file include/coroutine |
26 | * This is a Standard C++ Library header. |
27 | */ |
28 | |
29 | #ifndef _GLIBCXX_COROUTINE |
30 | #define _GLIBCXX_COROUTINE 1 |
31 | |
32 | #pragma GCC system_header |
33 | |
34 | // It is very likely that earlier versions would work, but they are untested. |
35 | #if __cplusplus >= 201402L |
36 | |
37 | #include <bits/c++config.h> |
38 | |
39 | /** |
40 | * @defgroup coroutines Coroutines |
41 | * |
42 | * Components for supporting coroutine implementations. |
43 | */ |
44 | |
45 | #if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L |
46 | # include <compare> |
47 | # define _COROUTINES_USE_SPACESHIP 1 |
48 | #else |
49 | # include <bits/stl_function.h> // for std::less |
50 | # define _COROUTINES_USE_SPACESHIP 0 |
51 | #endif |
52 | |
53 | namespace std _GLIBCXX_VISIBILITY (default) |
54 | { |
55 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
56 | |
57 | #if __cpp_impl_coroutine |
58 | |
59 | #define __cpp_lib_coroutine 201902L |
60 | |
61 | inline namespace __n4861 { |
62 | |
63 | // 17.12.2 coroutine traits |
64 | /// [coroutine.traits] |
65 | /// [coroutine.traits.primary] |
66 | /// If _Result::promise_type is valid and denotes a type then the traits |
67 | /// have a single publicly accessible member, otherwise they are empty. |
68 | template <typename _Result, typename = void> |
69 | struct __coroutine_traits_impl {}; |
70 | |
71 | template <typename _Result> |
72 | struct __coroutine_traits_impl<_Result, |
73 | __void_t<typename _Result::promise_type>> |
74 | { |
75 | using promise_type = typename _Result::promise_type; |
76 | }; |
77 | |
78 | template <typename _Result, typename...> |
79 | struct coroutine_traits : __coroutine_traits_impl<_Result> {}; |
80 | |
81 | // 17.12.3 Class template coroutine_handle |
82 | /// [coroutine.handle] |
83 | template <typename _Promise = void> |
84 | struct coroutine_handle; |
85 | |
86 | template <> struct |
87 | coroutine_handle<void> |
88 | { |
89 | public: |
90 | // [coroutine.handle.con], construct/reset |
91 | constexpr coroutine_handle() noexcept : _M_fr_ptr(0) {} |
92 | |
93 | constexpr coroutine_handle(std::nullptr_t __h) noexcept |
94 | : _M_fr_ptr(__h) |
95 | {} |
96 | |
97 | coroutine_handle& operator=(std::nullptr_t) noexcept |
98 | { |
99 | _M_fr_ptr = nullptr; |
100 | return *this; |
101 | } |
102 | |
103 | public: |
104 | // [coroutine.handle.export.import], export/import |
105 | constexpr void* address() const noexcept { return _M_fr_ptr; } |
106 | |
107 | constexpr static coroutine_handle from_address(void* __a) noexcept |
108 | { |
109 | coroutine_handle __self; |
110 | __self._M_fr_ptr = __a; |
111 | return __self; |
112 | } |
113 | |
114 | public: |
115 | // [coroutine.handle.observers], observers |
116 | constexpr explicit operator bool() const noexcept |
117 | { |
118 | return bool(_M_fr_ptr); |
119 | } |
120 | |
121 | bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); } |
122 | |
123 | // [coroutine.handle.resumption], resumption |
124 | void operator()() const { resume(); } |
125 | |
126 | void resume() const { __builtin_coro_resume(_M_fr_ptr); } |
127 | |
128 | void destroy() const { __builtin_coro_destroy(_M_fr_ptr); } |
129 | |
130 | protected: |
131 | void* _M_fr_ptr; |
132 | }; |
133 | |
134 | // [coroutine.handle.compare], comparison operators |
135 | |
136 | constexpr bool |
137 | operator==(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
138 | { |
139 | return __a.address() == __b.address(); |
140 | } |
141 | |
142 | #if _COROUTINES_USE_SPACESHIP |
143 | constexpr strong_ordering |
144 | operator<=>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
145 | { |
146 | return std::compare_three_way()(__a.address(), __b.address()); |
147 | } |
148 | #else |
149 | // These are to enable operation with std=c++14,17. |
150 | constexpr bool |
151 | operator!=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
152 | { |
153 | return !(__a == __b); |
154 | } |
155 | |
156 | constexpr bool |
157 | operator<(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
158 | { |
159 | return less<void*>()(__a.address(), __b.address()); |
160 | } |
161 | |
162 | constexpr bool |
163 | operator>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
164 | { |
165 | return __b < __a; |
166 | } |
167 | |
168 | constexpr bool |
169 | operator<=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
170 | { |
171 | return !(__a > __b); |
172 | } |
173 | |
174 | constexpr bool |
175 | operator>=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept |
176 | { |
177 | return !(__a < __b); |
178 | } |
179 | #endif |
180 | |
181 | template <typename _Promise> |
182 | struct coroutine_handle |
183 | { |
184 | // [coroutine.handle.con], construct/reset |
185 | |
186 | constexpr coroutine_handle() noexcept { } |
187 | |
188 | constexpr coroutine_handle(nullptr_t) noexcept { } |
189 | |
190 | static coroutine_handle |
191 | from_promise(_Promise& __p) |
192 | { |
193 | coroutine_handle __self; |
194 | __self._M_fr_ptr |
195 | = __builtin_coro_promise((char*) &__p, __alignof(_Promise), true); |
196 | return __self; |
197 | } |
198 | |
199 | coroutine_handle& operator=(nullptr_t) noexcept |
200 | { |
201 | _M_fr_ptr = nullptr; |
202 | return *this; |
203 | } |
204 | |
205 | // [coroutine.handle.export.import], export/import |
206 | |
207 | constexpr void* address() const noexcept { return _M_fr_ptr; } |
208 | |
209 | constexpr static coroutine_handle from_address(void* __a) noexcept |
210 | { |
211 | coroutine_handle __self; |
212 | __self._M_fr_ptr = __a; |
213 | return __self; |
214 | } |
215 | |
216 | // [coroutine.handle.conv], conversion |
217 | constexpr operator coroutine_handle<>() const noexcept |
218 | { return coroutine_handle<>::from_address(address()); } |
219 | |
220 | // [coroutine.handle.observers], observers |
221 | constexpr explicit operator bool() const noexcept |
222 | { |
223 | return bool(_M_fr_ptr); |
224 | } |
225 | |
226 | bool done() const noexcept { return __builtin_coro_done(_M_fr_ptr); } |
227 | |
228 | // [coroutine.handle.resumption], resumption |
229 | void operator()() const { resume(); } |
230 | |
231 | void resume() const { __builtin_coro_resume(_M_fr_ptr); } |
232 | |
233 | void destroy() const { __builtin_coro_destroy(_M_fr_ptr); } |
234 | |
235 | // [coroutine.handle.promise], promise access |
236 | _Promise& promise() const |
237 | { |
238 | void* __t |
239 | = __builtin_coro_promise (_M_fr_ptr, __alignof(_Promise), false); |
240 | return *static_cast<_Promise*>(__t); |
241 | } |
242 | |
243 | private: |
244 | void* _M_fr_ptr = nullptr; |
245 | }; |
246 | |
247 | /// [coroutine.noop] |
248 | struct noop_coroutine_promise |
249 | { |
250 | }; |
251 | |
252 | // 17.12.4.1 Class noop_coroutine_promise |
253 | /// [coroutine.promise.noop] |
254 | template <> |
255 | struct coroutine_handle<noop_coroutine_promise> |
256 | { |
257 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
258 | // 3460. Unimplementable noop_coroutine_handle guarantees |
259 | // [coroutine.handle.noop.conv], conversion |
260 | constexpr operator coroutine_handle<>() const noexcept |
261 | { return coroutine_handle<>::from_address(address()); } |
262 | |
263 | // [coroutine.handle.noop.observers], observers |
264 | constexpr explicit operator bool() const noexcept { return true; } |
265 | |
266 | constexpr bool done() const noexcept { return false; } |
267 | |
268 | // [coroutine.handle.noop.resumption], resumption |
269 | void operator()() const noexcept {} |
270 | |
271 | void resume() const noexcept {} |
272 | |
273 | void destroy() const noexcept {} |
274 | |
275 | // [coroutine.handle.noop.promise], promise access |
276 | noop_coroutine_promise& promise() const noexcept |
277 | { return _S_fr.__p; } |
278 | |
279 | // [coroutine.handle.noop.address], address |
280 | constexpr void* address() const noexcept { return _M_fr_ptr; } |
281 | |
282 | private: |
283 | friend coroutine_handle noop_coroutine() noexcept; |
284 | |
285 | struct __frame |
286 | { |
287 | static void __dummy_resume_destroy() { } |
288 | |
289 | void (*__r)() = __dummy_resume_destroy; |
290 | void (*__d)() = __dummy_resume_destroy; |
291 | struct noop_coroutine_promise __p; |
292 | }; |
293 | |
294 | static __frame _S_fr; |
295 | |
296 | explicit coroutine_handle() noexcept = default; |
297 | |
298 | void* _M_fr_ptr = &_S_fr; |
299 | }; |
300 | |
301 | using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; |
302 | |
303 | inline noop_coroutine_handle::__frame |
304 | noop_coroutine_handle::_S_fr{}; |
305 | |
306 | inline noop_coroutine_handle noop_coroutine() noexcept |
307 | { |
308 | return noop_coroutine_handle(); |
309 | } |
310 | |
311 | // 17.12.5 Trivial awaitables |
312 | /// [coroutine.trivial.awaitables] |
313 | struct suspend_always |
314 | { |
315 | constexpr bool await_ready() const noexcept { return false; } |
316 | |
317 | constexpr void await_suspend(coroutine_handle<>) const noexcept {} |
318 | |
319 | constexpr void await_resume() const noexcept {} |
320 | }; |
321 | |
322 | struct suspend_never |
323 | { |
324 | constexpr bool await_ready() const noexcept { return true; } |
325 | |
326 | constexpr void await_suspend(coroutine_handle<>) const noexcept {} |
327 | |
328 | constexpr void await_resume() const noexcept {} |
329 | }; |
330 | |
331 | } // namespace __n4861 |
332 | |
333 | #else |
334 | #error "the coroutine header requires -fcoroutines" |
335 | #endif |
336 | |
337 | _GLIBCXX_END_NAMESPACE_VERSION |
338 | } // namespace std |
339 | |
340 | #endif // C++14 (we are allowing use from at least this) |
341 | |
342 | #endif // _GLIBCXX_COROUTINE |
343 | |