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