]>
Commit | Line | Data |
---|---|---|
49789fd0 IS |
1 | // <coroutine> -*- C++ -*- |
2 | ||
7adcbafe | 3 | // Copyright (C) 2019-2022 Free Software Foundation, Inc. |
49789fd0 IS |
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 | { | |
dcf69ac5 | 55 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
49789fd0 | 56 | |
ee26baf4 | 57 | #if __cpp_impl_coroutine |
dcf69ac5 IS |
58 | |
59 | #define __cpp_lib_coroutine 201902L | |
60 | ||
61 | inline namespace __n4861 { | |
49789fd0 IS |
62 | |
63 | // 17.12.2 coroutine traits | |
64 | /// [coroutine.traits] | |
65 | /// [coroutine.traits.primary] | |
b9c91b7f IS |
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>> | |
49789fd0 | 74 | { |
b9c91b7f | 75 | using promise_type = typename _Result::promise_type; |
49789fd0 IS |
76 | }; |
77 | ||
b9c91b7f IS |
78 | template <typename _Result, typename...> |
79 | struct coroutine_traits : __coroutine_traits_impl<_Result> {}; | |
80 | ||
49789fd0 IS |
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: | |
2c2278f3 | 90 | // [coroutine.handle.con], construct/reset |
49789fd0 IS |
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: | |
2c2278f3 | 104 | // [coroutine.handle.export.import], export/import |
49789fd0 IS |
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: | |
2c2278f3 | 115 | // [coroutine.handle.observers], observers |
49789fd0 IS |
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 | ||
2c2278f3 | 123 | // [coroutine.handle.resumption], resumption |
49789fd0 IS |
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 | ||
2c2278f3 JW |
134 | // [coroutine.handle.compare], comparison operators |
135 | ||
136 | constexpr bool | |
137 | operator==(coroutine_handle<> __a, coroutine_handle<> __b) noexcept | |
49789fd0 IS |
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 | |
2c2278f3 JW |
145 | { |
146 | return std::compare_three_way()(__a.address(), __b.address()); | |
147 | } | |
49789fd0 IS |
148 | #else |
149 | // These are to enable operation with std=c++14,17. | |
2c2278f3 JW |
150 | constexpr bool |
151 | operator!=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept | |
49789fd0 IS |
152 | { |
153 | return !(__a == __b); | |
154 | } | |
155 | ||
2c2278f3 JW |
156 | constexpr bool |
157 | operator<(coroutine_handle<> __a, coroutine_handle<> __b) noexcept | |
49789fd0 IS |
158 | { |
159 | return less<void*>()(__a.address(), __b.address()); | |
160 | } | |
161 | ||
2c2278f3 JW |
162 | constexpr bool |
163 | operator>(coroutine_handle<> __a, coroutine_handle<> __b) noexcept | |
49789fd0 IS |
164 | { |
165 | return __b < __a; | |
166 | } | |
167 | ||
2c2278f3 JW |
168 | constexpr bool |
169 | operator<=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept | |
49789fd0 IS |
170 | { |
171 | return !(__a > __b); | |
172 | } | |
173 | ||
2c2278f3 JW |
174 | constexpr bool |
175 | operator>=(coroutine_handle<> __a, coroutine_handle<> __b) noexcept | |
49789fd0 IS |
176 | { |
177 | return !(__a < __b); | |
178 | } | |
179 | #endif | |
180 | ||
181 | template <typename _Promise> | |
2c2278f3 | 182 | struct coroutine_handle |
49789fd0 | 183 | { |
2c2278f3 | 184 | // [coroutine.handle.con], construct/reset |
49789fd0 | 185 | |
2c2278f3 JW |
186 | constexpr coroutine_handle() noexcept { } |
187 | ||
188 | constexpr coroutine_handle(nullptr_t) noexcept { } | |
189 | ||
190 | static coroutine_handle | |
191 | from_promise(_Promise& __p) | |
49789fd0 IS |
192 | { |
193 | coroutine_handle __self; | |
194 | __self._M_fr_ptr | |
2c2278f3 | 195 | = __builtin_coro_promise((char*) &__p, __alignof(_Promise), true); |
49789fd0 IS |
196 | return __self; |
197 | } | |
198 | ||
2c2278f3 | 199 | coroutine_handle& operator=(nullptr_t) noexcept |
49789fd0 | 200 | { |
2c2278f3 | 201 | _M_fr_ptr = nullptr; |
49789fd0 IS |
202 | return *this; |
203 | } | |
204 | ||
2c2278f3 | 205 | // [coroutine.handle.export.import], export/import |
49789fd0 | 206 | |
2c2278f3 JW |
207 | constexpr void* address() const noexcept { return _M_fr_ptr; } |
208 | ||
26a3f288 | 209 | constexpr static coroutine_handle from_address(void* __a) noexcept |
2c2278f3 JW |
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 | }; | |
49789fd0 IS |
246 | |
247 | /// [coroutine.noop] | |
248 | struct noop_coroutine_promise | |
249 | { | |
250 | }; | |
251 | ||
49789fd0 IS |
252 | // 17.12.4.1 Class noop_coroutine_promise |
253 | /// [coroutine.promise.noop] | |
254 | template <> | |
2c2278f3 | 255 | struct coroutine_handle<noop_coroutine_promise> |
49789fd0 | 256 | { |
2c2278f3 JW |
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()); } | |
49789fd0 | 262 | |
2c2278f3 | 263 | // [coroutine.handle.noop.observers], observers |
49789fd0 IS |
264 | constexpr explicit operator bool() const noexcept { return true; } |
265 | ||
266 | constexpr bool done() const noexcept { return false; } | |
267 | ||
2c2278f3 | 268 | // [coroutine.handle.noop.resumption], resumption |
49789fd0 IS |
269 | void operator()() const noexcept {} |
270 | ||
271 | void resume() const noexcept {} | |
272 | ||
273 | void destroy() const noexcept {} | |
274 | ||
2c2278f3 JW |
275 | // [coroutine.handle.noop.promise], promise access |
276 | noop_coroutine_promise& promise() const noexcept | |
94fd05f1 | 277 | { return _S_fr.__p; } |
2c2278f3 JW |
278 | |
279 | // [coroutine.handle.noop.address], address | |
280 | constexpr void* address() const noexcept { return _M_fr_ptr; } | |
49789fd0 | 281 | |
49789fd0 | 282 | private: |
2c2278f3 JW |
283 | friend coroutine_handle noop_coroutine() noexcept; |
284 | ||
94fd05f1 JW |
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; | |
49789fd0 | 295 | |
94fd05f1 JW |
296 | explicit coroutine_handle() noexcept = default; |
297 | ||
298 | void* _M_fr_ptr = &_S_fr; | |
49789fd0 IS |
299 | }; |
300 | ||
301 | using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; | |
302 | ||
94fd05f1 JW |
303 | inline noop_coroutine_handle::__frame |
304 | noop_coroutine_handle::_S_fr{}; | |
305 | ||
49789fd0 IS |
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 | { | |
f1b6e46c | 315 | constexpr bool await_ready() const noexcept { return false; } |
49789fd0 | 316 | |
f1b6e46c | 317 | constexpr void await_suspend(coroutine_handle<>) const noexcept {} |
49789fd0 | 318 | |
f1b6e46c | 319 | constexpr void await_resume() const noexcept {} |
49789fd0 IS |
320 | }; |
321 | ||
322 | struct suspend_never | |
323 | { | |
f1b6e46c | 324 | constexpr bool await_ready() const noexcept { return true; } |
49789fd0 | 325 | |
f1b6e46c | 326 | constexpr void await_suspend(coroutine_handle<>) const noexcept {} |
49789fd0 | 327 | |
f1b6e46c | 328 | constexpr void await_resume() const noexcept {} |
49789fd0 IS |
329 | }; |
330 | ||
dcf69ac5 | 331 | } // namespace __n4861 |
49789fd0 IS |
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 |