blob: e2f0a25f77edc57251752f1c3c6422b25e992a4e [file] [log] [blame]
Eric Fiselier3ca91852017-05-25 04:36:24 +00001// -*- C++ -*-
2//===----------------------------- coroutine -----------------------------===//
3//
Chandler Carruth2946cd72019-01-19 08:50:56 +00004// 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
Eric Fiselier3ca91852017-05-25 04:36:24 +00007//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
11#define _LIBCPP_EXPERIMENTAL_COROUTINE
12
13/**
14 experimental/coroutine synopsis
15
16// C++next
17
18namespace std {
19namespace experimental {
20inline namespace coroutines_v1 {
21
22 // 18.11.1 coroutine traits
23template <typename R, typename... ArgTypes>
24class coroutine_traits;
25// 18.11.2 coroutine handle
26template <typename Promise = void>
27class coroutine_handle;
28// 18.11.2.7 comparison operators:
Eric Fiselier997a3912017-05-26 03:02:54 +000029bool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
30bool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
31bool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
32bool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
33bool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
34bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
Eric Fiselier3ca91852017-05-25 04:36:24 +000035// 18.11.3 trivial awaitables
36struct suspend_never;
37struct suspend_always;
38// 18.11.2.8 hash support:
39template <class T> struct hash;
40template <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 <cassert>
55#include <__debug>
56
57#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
58#pragma GCC system_header
59#endif
60
Eric Fiseliereb04c8c2017-05-26 01:52:59 +000061#ifdef _LIBCPP_HAS_NO_COROUTINES
Eric Fiselier3ca91852017-05-25 04:36:24 +000062# if defined(_LIBCPP_WARNING)
63 _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler")
64# else
65# warning <experimental/coroutine> cannot be used with this compiler
66# endif
67#endif
68
Eric Fiseliereb04c8c2017-05-26 01:52:59 +000069#ifndef _LIBCPP_HAS_NO_COROUTINES
70
Eric Fiselier3ca91852017-05-25 04:36:24 +000071_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
72
73template <class _Tp, class = void>
74struct __coroutine_traits_sfinae {};
75
76template <class _Tp>
77struct __coroutine_traits_sfinae<
78 _Tp, typename __void_t<typename _Tp::promise_type>::type>
79{
80 using promise_type = typename _Tp::promise_type;
81};
82
83template <typename _Ret, typename... _Args>
Eric Fiselierc3d6a922019-04-17 04:31:46 +000084struct coroutine_traits
Eric Fiselier3ca91852017-05-25 04:36:24 +000085 : public __coroutine_traits_sfinae<_Ret>
86{
87};
88
Eric Fiselierea968912017-05-25 23:39:29 +000089template <typename _Promise = void>
Eric Fiselier3ca91852017-05-25 04:36:24 +000090class _LIBCPP_TEMPLATE_VIS coroutine_handle;
91
Eric Fiselier3ca91852017-05-25 04:36:24 +000092template <>
93class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
94public:
Gor Nishanov0f87a802018-04-04 22:18:03 +000095 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +000096 _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
Eric Fiselier3ca91852017-05-25 04:36:24 +000097
Gor Nishanov0f87a802018-04-04 22:18:03 +000098 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +000099 _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
Eric Fiselier3ca91852017-05-25 04:36:24 +0000100
Gor Nishanov0f87a802018-04-04 22:18:03 +0000101 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000102 coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000103 __handle_ = nullptr;
104 return *this;
105 }
106
Gor Nishanov0f87a802018-04-04 22:18:03 +0000107 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000108 _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
Eric Fiselier3ca91852017-05-25 04:36:24 +0000109
Gor Nishanov0f87a802018-04-04 22:18:03 +0000110 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000111 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
Eric Fiselier3ca91852017-05-25 04:36:24 +0000112
Gor Nishanov0f87a802018-04-04 22:18:03 +0000113 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier51056ae2017-05-25 19:04:55 +0000114 void operator()() { resume(); }
Eric Fiselier3ca91852017-05-25 04:36:24 +0000115
Gor Nishanov0f87a802018-04-04 22:18:03 +0000116 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier51056ae2017-05-25 19:04:55 +0000117 void resume() {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000118 _LIBCPP_ASSERT(__is_suspended(),
119 "resume() can only be called on suspended coroutines");
120 _LIBCPP_ASSERT(!done(),
121 "resume() has undefined behavior when the coroutine is done");
122 __builtin_coro_resume(__handle_);
123 }
124
Gor Nishanov0f87a802018-04-04 22:18:03 +0000125 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier51056ae2017-05-25 19:04:55 +0000126 void destroy() {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000127 _LIBCPP_ASSERT(__is_suspended(),
128 "destroy() can only be called on suspended coroutines");
129 __builtin_coro_destroy(__handle_);
130 }
131
Gor Nishanov0f87a802018-04-04 22:18:03 +0000132 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier3ca91852017-05-25 04:36:24 +0000133 bool done() const {
134 _LIBCPP_ASSERT(__is_suspended(),
135 "done() can only be called on suspended coroutines");
136 return __builtin_coro_done(__handle_);
137 }
138
139public:
Gor Nishanov0f87a802018-04-04 22:18:03 +0000140 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000141 static coroutine_handle from_address(void* __addr) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000142 coroutine_handle __tmp;
143 __tmp.__handle_ = __addr;
144 return __tmp;
145 }
146
Eric Fiselier3fd02282017-05-29 19:24:25 +0000147 // FIXME: Should from_address(nullptr) be allowed?
Gor Nishanov0f87a802018-04-04 22:18:03 +0000148 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier3fd02282017-05-29 19:24:25 +0000149 static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
Eric Fiselier6e88ac22017-05-29 19:46:16 +0000150 return coroutine_handle(nullptr);
Eric Fiselier3fd02282017-05-29 19:24:25 +0000151 }
152
153 template <class _Tp, bool _CallIsValid = false>
154 static coroutine_handle from_address(_Tp*) {
155 static_assert(_CallIsValid,
156 "coroutine_handle<void>::from_address cannot be called with "
157 "non-void pointers");
158 }
159
Eric Fiselier3ca91852017-05-25 04:36:24 +0000160private:
Eric Fiselier997a3912017-05-26 03:02:54 +0000161 bool __is_suspended() const _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000162 // FIXME actually implement a check for if the coro is suspended.
163 return __handle_;
164 }
165
166 template <class _PromiseT> friend class coroutine_handle;
167 void* __handle_;
168};
169
170// 18.11.2.7 comparison operators:
Gor Nishanov0f87a802018-04-04 22:18:03 +0000171inline _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000172bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000173 return __x.address() == __y.address();
174}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000175inline _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000176bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000177 return !(__x == __y);
178}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000179inline _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000180bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000181 return less<void*>()(__x.address(), __y.address());
182}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000183inline _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000184bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000185 return __y < __x;
186}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000187inline _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000188bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000189 return !(__x > __y);
190}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000191inline _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000192bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000193 return !(__x < __y);
194}
195
196template <typename _Promise>
197class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
198 using _Base = coroutine_handle<>;
199public:
Eric Fiselier997a3912017-05-26 03:02:54 +0000200#ifndef _LIBCPP_CXX03_LANG
Eric Fiselier3ca91852017-05-25 04:36:24 +0000201 // 18.11.2.1 construct/reset
202 using coroutine_handle<>::coroutine_handle;
Eric Fiselier997a3912017-05-26 03:02:54 +0000203#else
Gor Nishanov0f87a802018-04-04 22:18:03 +0000204 _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
205 _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
Eric Fiselier997a3912017-05-26 03:02:54 +0000206#endif
Eric Fiselier3ca91852017-05-25 04:36:24 +0000207 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000208 coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000209 _Base::operator=(nullptr);
210 return *this;
211 }
212
Eric Fiselier3ca91852017-05-25 04:36:24 +0000213 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier2944c5a2017-05-25 18:52:34 +0000214 _Promise& promise() const {
Gor Nishanov0f87a802018-04-04 22:18:03 +0000215 return *static_cast<_Promise*>(
Eric Fiselierd108bf82019-01-16 01:51:12 +0000216 __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
Eric Fiselier3ca91852017-05-25 04:36:24 +0000217 }
218
219public:
Gor Nishanov0f87a802018-04-04 22:18:03 +0000220 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000221 static coroutine_handle from_address(void* __addr) _NOEXCEPT {
Eric Fiselier3ca91852017-05-25 04:36:24 +0000222 coroutine_handle __tmp;
223 __tmp.__handle_ = __addr;
224 return __tmp;
225 }
226
Eric Fiselierbae0a1d2017-05-29 06:42:01 +0000227 // NOTE: this overload isn't required by the standard but is needed so
228 // the deleted _Promise* overload doesn't make from_address(nullptr)
229 // ambiguous.
230 // FIXME: should from_address work with nullptr?
Gor Nishanov0f87a802018-04-04 22:18:03 +0000231 _LIBCPP_INLINE_VISIBILITY
Eric Fiselierbae0a1d2017-05-29 06:42:01 +0000232 static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
Eric Fiselier6e88ac22017-05-29 19:46:16 +0000233 return coroutine_handle(nullptr);
Eric Fiselierbae0a1d2017-05-29 06:42:01 +0000234 }
235
Eric Fiselier3fd02282017-05-29 19:24:25 +0000236 template <class _Tp, bool _CallIsValid = false>
237 static coroutine_handle from_address(_Tp*) {
238 static_assert(_CallIsValid,
239 "coroutine_handle<promise_type>::from_address cannot be called with "
240 "non-void pointers");
241 }
242
243 template <bool _CallIsValid = false>
244 static coroutine_handle from_address(_Promise*) {
245 static_assert(_CallIsValid,
246 "coroutine_handle<promise_type>::from_address cannot be used with "
247 "pointers to the coroutine's promise type; use 'from_promise' instead");
248 }
Eric Fiselier207d13c2017-05-29 05:00:24 +0000249
Gor Nishanov0f87a802018-04-04 22:18:03 +0000250 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000251 static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
Eric Fiselierf9bc0582017-06-16 00:36:17 +0000252 typedef typename remove_cv<_Promise>::type _RawPromise;
Eric Fiselier3ca91852017-05-25 04:36:24 +0000253 coroutine_handle __tmp;
Eric Fiselierf9bc0582017-06-16 00:36:17 +0000254 __tmp.__handle_ = __builtin_coro_promise(
255 _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
Eric Fiselierd108bf82019-01-16 01:51:12 +0000256 _LIBCPP_ALIGNOF(_Promise), true);
Eric Fiselier3ca91852017-05-25 04:36:24 +0000257 return __tmp;
258 }
259};
260
Gor Nishanov0f87a802018-04-04 22:18:03 +0000261#if __has_builtin(__builtin_coro_noop)
262struct noop_coroutine_promise {};
263
264template <>
265class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
266 : public coroutine_handle<> {
267 using _Base = coroutine_handle<>;
268 using _Promise = noop_coroutine_promise;
269public:
270
271 _LIBCPP_INLINE_VISIBILITY
272 _Promise& promise() const {
273 return *static_cast<_Promise*>(
Eric Fiselierd108bf82019-01-16 01:51:12 +0000274 __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
Gor Nishanov0f87a802018-04-04 22:18:03 +0000275 }
276
277 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
278 _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
279
Gor Nishanov8f310652018-04-05 00:18:37 +0000280 _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
281 _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
282 _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000283
284private:
Louis Dionnecf3ae382018-07-10 17:38:30 +0000285 _LIBCPP_INLINE_VISIBILITY
Gor Nishanov0f87a802018-04-04 22:18:03 +0000286 friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
287
288 _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
289 this->__handle_ = __builtin_coro_noop();
290 }
291};
292
293using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
294
295inline _LIBCPP_INLINE_VISIBILITY
296noop_coroutine_handle noop_coroutine() _NOEXCEPT {
Gor Nishanovb1e985d2018-04-04 22:51:57 +0000297 return noop_coroutine_handle();
Gor Nishanov0f87a802018-04-04 22:18:03 +0000298}
299#endif // __has_builtin(__builtin_coro_noop)
300
Eric Fiselierc3d6a922019-04-17 04:31:46 +0000301struct suspend_never {
Gor Nishanov0f87a802018-04-04 22:18:03 +0000302 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000303 bool await_ready() const _NOEXCEPT { return true; }
Gor Nishanov0f87a802018-04-04 22:18:03 +0000304 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000305 void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000306 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000307 void await_resume() const _NOEXCEPT {}
Eric Fiselier3ca91852017-05-25 04:36:24 +0000308};
309
Eric Fiselierc3d6a922019-04-17 04:31:46 +0000310struct suspend_always {
Gor Nishanov0f87a802018-04-04 22:18:03 +0000311 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000312 bool await_ready() const _NOEXCEPT { return false; }
Gor Nishanov0f87a802018-04-04 22:18:03 +0000313 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000314 void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
Gor Nishanov0f87a802018-04-04 22:18:03 +0000315 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000316 void await_resume() const _NOEXCEPT {}
Eric Fiselier3ca91852017-05-25 04:36:24 +0000317};
318
Eric Fiselier3ca91852017-05-25 04:36:24 +0000319_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
320
321_LIBCPP_BEGIN_NAMESPACE_STD
322
323template <class _Tp>
324struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
325 using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
326 _LIBCPP_INLINE_VISIBILITY
Eric Fiselier997a3912017-05-26 03:02:54 +0000327 size_t operator()(__arg_type const& __v) const _NOEXCEPT
328 {return hash<void*>()(__v.address());}
Eric Fiselier3ca91852017-05-25 04:36:24 +0000329};
330
331_LIBCPP_END_NAMESPACE_STD
332
Eric Fiseliereb04c8c2017-05-26 01:52:59 +0000333#endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
334
Eric Fiselier3ca91852017-05-25 04:36:24 +0000335#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */