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