]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libc++/include/experimental/coroutine
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304149, and update
[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_ALWAYS_INLINE
97     _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
98
99     _LIBCPP_ALWAYS_INLINE
100     _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
101
102     _LIBCPP_ALWAYS_INLINE
103     coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
104         __handle_ = nullptr;
105         return *this;
106     }
107
108     _LIBCPP_ALWAYS_INLINE
109     _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
110
111     _LIBCPP_ALWAYS_INLINE
112     _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
113
114     _LIBCPP_ALWAYS_INLINE
115     void operator()() { resume(); }
116
117     _LIBCPP_ALWAYS_INLINE
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_ALWAYS_INLINE
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_ALWAYS_INLINE
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_ALWAYS_INLINE
142     static coroutine_handle from_address(void* __addr) _NOEXCEPT {
143         coroutine_handle __tmp;
144         __tmp.__handle_ = __addr;
145         return __tmp;
146     }
147
148 private:
149   bool __is_suspended() const _NOEXCEPT  {
150     // FIXME actually implement a check for if the coro is suspended.
151     return __handle_;
152   }
153
154   template <class _PromiseT> friend class coroutine_handle;
155   void* __handle_;
156 };
157
158 // 18.11.2.7 comparison operators:
159 inline _LIBCPP_ALWAYS_INLINE
160 bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
161     return __x.address() == __y.address();
162 }
163 inline _LIBCPP_ALWAYS_INLINE
164 bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
165     return !(__x == __y);
166 }
167 inline _LIBCPP_ALWAYS_INLINE
168 bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
169     return less<void*>()(__x.address(), __y.address());
170 }
171 inline _LIBCPP_ALWAYS_INLINE
172 bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
173     return __y < __x;
174 }
175 inline _LIBCPP_ALWAYS_INLINE
176 bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
177     return !(__x > __y);
178 }
179 inline _LIBCPP_ALWAYS_INLINE
180 bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
181     return !(__x < __y);
182 }
183
184 template <typename _Promise>
185 class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
186     using _Base = coroutine_handle<>;
187 public:
188 #ifndef _LIBCPP_CXX03_LANG
189     // 18.11.2.1 construct/reset
190     using coroutine_handle<>::coroutine_handle;
191 #else
192     _LIBCPP_ALWAYS_INLINE coroutine_handle() _NOEXCEPT : _Base() {}
193     _LIBCPP_ALWAYS_INLINE coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
194 #endif
195     _LIBCPP_INLINE_VISIBILITY
196     coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
197         _Base::operator=(nullptr);
198         return *this;
199     }
200
201     _LIBCPP_INLINE_VISIBILITY
202     _Promise& promise() const {
203         return *reinterpret_cast<_Promise*>(
204             __builtin_coro_promise(this->__handle_, __alignof(_Promise), false));
205     }
206
207 public:
208     _LIBCPP_ALWAYS_INLINE
209     static coroutine_handle from_address(void* __addr) _NOEXCEPT {
210         coroutine_handle __tmp;
211         __tmp.__handle_ = __addr;
212         return __tmp;
213     }
214
215     // NOTE: this overload isn't required by the standard but is needed so
216     // the deleted _Promise* overload doesn't make from_address(nullptr)
217     // ambiguous.
218     // FIXME: should from_address work with nullptr?
219     _LIBCPP_ALWAYS_INLINE
220     static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
221       return {};
222     }
223
224     // from_address cannot be used with the coroutines promise type.
225     static coroutine_handle from_address(_Promise*) = delete;
226
227     _LIBCPP_ALWAYS_INLINE
228     static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
229         coroutine_handle __tmp;
230         __tmp.__handle_ = __builtin_coro_promise(_VSTD::addressof(__promise),
231                                                  __alignof(_Promise), true);
232         return __tmp;
233     }
234 };
235
236 struct _LIBCPP_TYPE_VIS suspend_never {
237   _LIBCPP_ALWAYS_INLINE
238   bool await_ready() const _NOEXCEPT { return true; }
239   _LIBCPP_ALWAYS_INLINE
240   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
241   _LIBCPP_ALWAYS_INLINE
242   void await_resume() const _NOEXCEPT {}
243 };
244
245 struct _LIBCPP_TYPE_VIS suspend_always {
246   _LIBCPP_ALWAYS_INLINE
247   bool await_ready() const _NOEXCEPT { return false; }
248   _LIBCPP_ALWAYS_INLINE
249   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
250   _LIBCPP_ALWAYS_INLINE
251   void await_resume() const _NOEXCEPT {}
252 };
253
254 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
255
256 _LIBCPP_BEGIN_NAMESPACE_STD
257
258 template <class _Tp>
259 struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
260     using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
261     _LIBCPP_INLINE_VISIBILITY
262     size_t operator()(__arg_type const& __v) const _NOEXCEPT
263     {return hash<void*>()(__v.address());}
264 };
265
266 _LIBCPP_END_NAMESPACE_STD
267
268 #endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
269
270 #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */