1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
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
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:
29bool 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;
35// 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 <__assert> // all public C++ headers provide the assertion handler
49#include <__functional/hash.h>
50#include <cstddef>
51#include <experimental/__config>
52#include <memory> // for hash<T*>
53#include <new>
54#include <type_traits>
55
56#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
57#  pragma GCC system_header
58#endif
59
60#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
61
62_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
63
64template <class _Tp, class = void>
65struct __coroutine_traits_sfinae {};
66
67template <class _Tp>
68struct __coroutine_traits_sfinae<
69    _Tp, typename __void_t<typename _Tp::promise_type>::type>
70{
71  using promise_type = typename _Tp::promise_type;
72};
73
74template <typename _Ret, typename... _Args>
75struct coroutine_traits
76    : public __coroutine_traits_sfinae<_Ret>
77{
78};
79
80template <typename _Promise = void>
81class _LIBCPP_TEMPLATE_VIS coroutine_handle;
82
83template <>
84class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
85public:
86    _LIBCPP_INLINE_VISIBILITY
87    _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
88
89    _LIBCPP_INLINE_VISIBILITY
90    _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
91
92    _LIBCPP_INLINE_VISIBILITY
93    coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
94        __handle_ = nullptr;
95        return *this;
96    }
97
98    _LIBCPP_INLINE_VISIBILITY
99    _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
100
101    _LIBCPP_INLINE_VISIBILITY
102    _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
103
104    _LIBCPP_INLINE_VISIBILITY
105    void operator()() { resume(); }
106
107    _LIBCPP_INLINE_VISIBILITY
108    void resume() {
109      _LIBCPP_ASSERT(__is_suspended(),
110                     "resume() can only be called on suspended coroutines");
111      _LIBCPP_ASSERT(!done(),
112                "resume() has undefined behavior when the coroutine is done");
113      __builtin_coro_resume(__handle_);
114    }
115
116    _LIBCPP_INLINE_VISIBILITY
117    void destroy() {
118      _LIBCPP_ASSERT(__is_suspended(),
119                     "destroy() can only be called on suspended coroutines");
120      __builtin_coro_destroy(__handle_);
121    }
122
123    _LIBCPP_INLINE_VISIBILITY
124    bool done() const {
125      _LIBCPP_ASSERT(__is_suspended(),
126                     "done() can only be called on suspended coroutines");
127      return __builtin_coro_done(__handle_);
128    }
129
130public:
131    _LIBCPP_INLINE_VISIBILITY
132    static coroutine_handle from_address(void* __addr) _NOEXCEPT {
133        coroutine_handle __tmp;
134        __tmp.__handle_ = __addr;
135        return __tmp;
136    }
137
138    // FIXME: Should from_address(nullptr) be allowed?
139    _LIBCPP_INLINE_VISIBILITY
140    static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
141      return coroutine_handle(nullptr);
142    }
143
144    template <class _Tp, bool _CallIsValid = false>
145    static coroutine_handle from_address(_Tp*) {
146      static_assert(_CallIsValid,
147       "coroutine_handle<void>::from_address cannot be called with "
148        "non-void pointers");
149    }
150
151private:
152  bool __is_suspended() const _NOEXCEPT  {
153    // FIXME actually implement a check for if the coro is suspended.
154    return __handle_;
155  }
156
157  template <class _PromiseT> friend class coroutine_handle;
158  void* __handle_;
159};
160
161// 18.11.2.7 comparison operators:
162inline _LIBCPP_INLINE_VISIBILITY
163bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
164    return __x.address() == __y.address();
165}
166inline _LIBCPP_INLINE_VISIBILITY
167bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
168    return !(__x == __y);
169}
170inline _LIBCPP_INLINE_VISIBILITY
171bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
172    return less<void*>()(__x.address(), __y.address());
173}
174inline _LIBCPP_INLINE_VISIBILITY
175bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
176    return __y < __x;
177}
178inline _LIBCPP_INLINE_VISIBILITY
179bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
180    return !(__x > __y);
181}
182inline _LIBCPP_INLINE_VISIBILITY
183bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
184    return !(__x < __y);
185}
186
187template <typename _Promise>
188class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
189    using _Base = coroutine_handle<>;
190public:
191#ifndef _LIBCPP_CXX03_LANG
192    // 18.11.2.1 construct/reset
193    using coroutine_handle<>::coroutine_handle;
194#else
195    _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
196    _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
197#endif
198    _LIBCPP_INLINE_VISIBILITY
199    coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
200        _Base::operator=(nullptr);
201        return *this;
202    }
203
204    _LIBCPP_INLINE_VISIBILITY
205    _Promise& promise() const {
206        return *static_cast<_Promise*>(
207            __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
208    }
209
210public:
211    _LIBCPP_INLINE_VISIBILITY
212    static coroutine_handle from_address(void* __addr) _NOEXCEPT {
213        coroutine_handle __tmp;
214        __tmp.__handle_ = __addr;
215        return __tmp;
216    }
217
218    // NOTE: this overload isn't required by the standard but is needed so
219    // the deleted _Promise* overload doesn't make from_address(nullptr)
220    // ambiguous.
221    // FIXME: should from_address work with nullptr?
222    _LIBCPP_INLINE_VISIBILITY
223    static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
224      return coroutine_handle(nullptr);
225    }
226
227    template <class _Tp, bool _CallIsValid = false>
228    static coroutine_handle from_address(_Tp*) {
229      static_assert(_CallIsValid,
230       "coroutine_handle<promise_type>::from_address cannot be called with "
231        "non-void pointers");
232    }
233
234    template <bool _CallIsValid = false>
235    static coroutine_handle from_address(_Promise*) {
236      static_assert(_CallIsValid,
237       "coroutine_handle<promise_type>::from_address cannot be used with "
238        "pointers to the coroutine's promise type; use 'from_promise' instead");
239    }
240
241    _LIBCPP_INLINE_VISIBILITY
242    static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
243        typedef typename remove_cv<_Promise>::type _RawPromise;
244        coroutine_handle __tmp;
245        __tmp.__handle_ = __builtin_coro_promise(
246            _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
247             _LIBCPP_ALIGNOF(_Promise), true);
248        return __tmp;
249    }
250};
251
252#if __has_builtin(__builtin_coro_noop)
253struct noop_coroutine_promise {};
254
255template <>
256class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
257    : public coroutine_handle<> {
258  using _Base = coroutine_handle<>;
259  using _Promise = noop_coroutine_promise;
260public:
261
262  _LIBCPP_INLINE_VISIBILITY
263  _Promise& promise() const {
264    return *static_cast<_Promise*>(
265      __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
266  }
267
268  _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
269  _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
270
271  _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
272  _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
273  _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
274
275private:
276  _LIBCPP_INLINE_VISIBILITY
277  friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
278
279  _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
280    this->__handle_ = __builtin_coro_noop();
281  }
282};
283
284using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
285
286inline _LIBCPP_INLINE_VISIBILITY
287noop_coroutine_handle noop_coroutine() _NOEXCEPT {
288  return noop_coroutine_handle();
289}
290#endif // __has_builtin(__builtin_coro_noop)
291
292struct suspend_never {
293  _LIBCPP_INLINE_VISIBILITY
294  bool await_ready() const _NOEXCEPT { return true; }
295  _LIBCPP_INLINE_VISIBILITY
296  void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
297  _LIBCPP_INLINE_VISIBILITY
298  void await_resume() const _NOEXCEPT {}
299};
300
301struct suspend_always {
302  _LIBCPP_INLINE_VISIBILITY
303  bool await_ready() const _NOEXCEPT { return false; }
304  _LIBCPP_INLINE_VISIBILITY
305  void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
306  _LIBCPP_INLINE_VISIBILITY
307  void await_resume() const _NOEXCEPT {}
308};
309
310_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
311
312_LIBCPP_BEGIN_NAMESPACE_STD
313
314template <class _Tp>
315struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
316    using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
317    _LIBCPP_INLINE_VISIBILITY
318    size_t operator()(__arg_type const& __v) const _NOEXCEPT
319    {return hash<void*>()(__v.address());}
320};
321
322_LIBCPP_END_NAMESPACE_STD
323
324#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)
325
326#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
327