]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/libcxx/include/experimental/coroutine
Merge ^/head r357408 through r357661.
[FreeBSD/FreeBSD.git] / contrib / llvm-project / libcxx / include / experimental / coroutine
1 // -*- C++ -*-
2 //===----------------------------- coroutine -----------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
11 #define _LIBCPP_EXPERIMENTAL_COROUTINE
12
13 /**
14     experimental/coroutine synopsis
15
16 // C++next
17
18 namespace std {
19 namespace experimental {
20 inline namespace coroutines_v1 {
21
22   // 18.11.1 coroutine traits
23 template <typename R, typename... ArgTypes>
24 class coroutine_traits;
25 // 18.11.2 coroutine handle
26 template <typename Promise = void>
27 class coroutine_handle;
28 // 18.11.2.7 comparison operators:
29 bool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
30 bool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
31 bool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
32 bool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
33 bool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
34 bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
35 // 18.11.3 trivial awaitables
36 struct suspend_never;
37 struct suspend_always;
38 // 18.11.2.8 hash support:
39 template <class T> struct hash;
40 template <class P> struct hash<coroutine_handle<P>>;
41
42 } // namespace coroutines_v1
43 } // namespace experimental
44 } // namespace std
45
46  */
47
48 #include <experimental/__config>
49 #include <new>
50 #include <type_traits>
51 #include <functional>
52 #include <memory> // for hash<T*>
53 #include <cstddef>
54 #include <__debug>
55
56 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
57 #pragma GCC system_header
58 #endif
59
60 #ifdef _LIBCPP_HAS_NO_COROUTINES
61 # if defined(_LIBCPP_WARNING)
62     _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler")
63 # else
64 #   warning <experimental/coroutine> cannot be used with this compiler
65 # endif
66 #endif
67
68 #ifndef _LIBCPP_HAS_NO_COROUTINES
69
70 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
71
72 template <class _Tp, class = void>
73 struct __coroutine_traits_sfinae {};
74
75 template <class _Tp>
76 struct __coroutine_traits_sfinae<
77     _Tp, typename __void_t<typename _Tp::promise_type>::type>
78 {
79   using promise_type = typename _Tp::promise_type;
80 };
81
82 template <typename _Ret, typename... _Args>
83 struct coroutine_traits
84     : public __coroutine_traits_sfinae<_Ret>
85 {
86 };
87
88 template <typename _Promise = void>
89 class _LIBCPP_TEMPLATE_VIS coroutine_handle;
90
91 template <>
92 class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
93 public:
94     _LIBCPP_INLINE_VISIBILITY
95     _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
96
97     _LIBCPP_INLINE_VISIBILITY
98     _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
99
100     _LIBCPP_INLINE_VISIBILITY
101     coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
102         __handle_ = nullptr;
103         return *this;
104     }
105
106     _LIBCPP_INLINE_VISIBILITY
107     _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
108
109     _LIBCPP_INLINE_VISIBILITY
110     _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
111
112     _LIBCPP_INLINE_VISIBILITY
113     void operator()() { resume(); }
114
115     _LIBCPP_INLINE_VISIBILITY
116     void resume() {
117       _LIBCPP_ASSERT(__is_suspended(),
118                      "resume() can only be called on suspended coroutines");
119       _LIBCPP_ASSERT(!done(),
120                 "resume() has undefined behavior when the coroutine is done");
121       __builtin_coro_resume(__handle_);
122     }
123
124     _LIBCPP_INLINE_VISIBILITY
125     void destroy() {
126       _LIBCPP_ASSERT(__is_suspended(),
127                      "destroy() can only be called on suspended coroutines");
128       __builtin_coro_destroy(__handle_);
129     }
130
131     _LIBCPP_INLINE_VISIBILITY
132     bool done() const {
133       _LIBCPP_ASSERT(__is_suspended(),
134                      "done() can only be called on suspended coroutines");
135       return __builtin_coro_done(__handle_);
136     }
137
138 public:
139     _LIBCPP_INLINE_VISIBILITY
140     static coroutine_handle from_address(void* __addr) _NOEXCEPT {
141         coroutine_handle __tmp;
142         __tmp.__handle_ = __addr;
143         return __tmp;
144     }
145
146     // FIXME: Should from_address(nullptr) be allowed?
147     _LIBCPP_INLINE_VISIBILITY
148     static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
149       return coroutine_handle(nullptr);
150     }
151
152     template <class _Tp, bool _CallIsValid = false>
153     static coroutine_handle from_address(_Tp*) {
154       static_assert(_CallIsValid,
155        "coroutine_handle<void>::from_address cannot be called with "
156         "non-void pointers");
157     }
158
159 private:
160   bool __is_suspended() const _NOEXCEPT  {
161     // FIXME actually implement a check for if the coro is suspended.
162     return __handle_;
163   }
164
165   template <class _PromiseT> friend class coroutine_handle;
166   void* __handle_;
167 };
168
169 // 18.11.2.7 comparison operators:
170 inline _LIBCPP_INLINE_VISIBILITY
171 bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
172     return __x.address() == __y.address();
173 }
174 inline _LIBCPP_INLINE_VISIBILITY
175 bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
176     return !(__x == __y);
177 }
178 inline _LIBCPP_INLINE_VISIBILITY
179 bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
180     return less<void*>()(__x.address(), __y.address());
181 }
182 inline _LIBCPP_INLINE_VISIBILITY
183 bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
184     return __y < __x;
185 }
186 inline _LIBCPP_INLINE_VISIBILITY
187 bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
188     return !(__x > __y);
189 }
190 inline _LIBCPP_INLINE_VISIBILITY
191 bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
192     return !(__x < __y);
193 }
194
195 template <typename _Promise>
196 class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
197     using _Base = coroutine_handle<>;
198 public:
199 #ifndef _LIBCPP_CXX03_LANG
200     // 18.11.2.1 construct/reset
201     using coroutine_handle<>::coroutine_handle;
202 #else
203     _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
204     _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
205 #endif
206     _LIBCPP_INLINE_VISIBILITY
207     coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
208         _Base::operator=(nullptr);
209         return *this;
210     }
211
212     _LIBCPP_INLINE_VISIBILITY
213     _Promise& promise() const {
214         return *static_cast<_Promise*>(
215             __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
216     }
217
218 public:
219     _LIBCPP_INLINE_VISIBILITY
220     static coroutine_handle from_address(void* __addr) _NOEXCEPT {
221         coroutine_handle __tmp;
222         __tmp.__handle_ = __addr;
223         return __tmp;
224     }
225
226     // NOTE: this overload isn't required by the standard but is needed so
227     // the deleted _Promise* overload doesn't make from_address(nullptr)
228     // ambiguous.
229     // FIXME: should from_address work with nullptr?
230     _LIBCPP_INLINE_VISIBILITY
231     static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
232       return coroutine_handle(nullptr);
233     }
234
235     template <class _Tp, bool _CallIsValid = false>
236     static coroutine_handle from_address(_Tp*) {
237       static_assert(_CallIsValid,
238        "coroutine_handle<promise_type>::from_address cannot be called with "
239         "non-void pointers");
240     }
241
242     template <bool _CallIsValid = false>
243     static coroutine_handle from_address(_Promise*) {
244       static_assert(_CallIsValid,
245        "coroutine_handle<promise_type>::from_address cannot be used with "
246         "pointers to the coroutine's promise type; use 'from_promise' instead");
247     }
248
249     _LIBCPP_INLINE_VISIBILITY
250     static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
251         typedef typename remove_cv<_Promise>::type _RawPromise;
252         coroutine_handle __tmp;
253         __tmp.__handle_ = __builtin_coro_promise(
254             _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
255              _LIBCPP_ALIGNOF(_Promise), true);
256         return __tmp;
257     }
258 };
259
260 #if __has_builtin(__builtin_coro_noop)
261 struct noop_coroutine_promise {};
262
263 template <>
264 class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
265     : public coroutine_handle<> {
266   using _Base = coroutine_handle<>;
267   using _Promise = noop_coroutine_promise;
268 public:
269
270   _LIBCPP_INLINE_VISIBILITY
271   _Promise& promise() const {
272     return *static_cast<_Promise*>(
273       __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
274   }
275
276   _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
277   _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
278
279   _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
280   _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
281   _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
282
283 private:
284   _LIBCPP_INLINE_VISIBILITY
285   friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
286
287   _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
288     this->__handle_ = __builtin_coro_noop();
289   }
290 };
291
292 using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
293
294 inline _LIBCPP_INLINE_VISIBILITY
295 noop_coroutine_handle noop_coroutine() _NOEXCEPT {
296   return noop_coroutine_handle();
297 }
298 #endif // __has_builtin(__builtin_coro_noop)
299
300 struct suspend_never {
301   _LIBCPP_INLINE_VISIBILITY
302   bool await_ready() const _NOEXCEPT { return true; }
303   _LIBCPP_INLINE_VISIBILITY
304   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
305   _LIBCPP_INLINE_VISIBILITY
306   void await_resume() const _NOEXCEPT {}
307 };
308
309 struct suspend_always {
310   _LIBCPP_INLINE_VISIBILITY
311   bool await_ready() const _NOEXCEPT { return false; }
312   _LIBCPP_INLINE_VISIBILITY
313   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
314   _LIBCPP_INLINE_VISIBILITY
315   void await_resume() const _NOEXCEPT {}
316 };
317
318 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
319
320 _LIBCPP_BEGIN_NAMESPACE_STD
321
322 template <class _Tp>
323 struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
324     using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
325     _LIBCPP_INLINE_VISIBILITY
326     size_t operator()(__arg_type const& __v) const _NOEXCEPT
327     {return hash<void*>()(__v.address());}
328 };
329
330 _LIBCPP_END_NAMESPACE_STD
331
332 #endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
333
334 #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */