1302affcbSDimitry Andric// -*- C++ -*-
2302affcbSDimitry Andric//===----------------------------- coroutine -----------------------------===//
3302affcbSDimitry Andric//
4302affcbSDimitry Andric//                     The LLVM Compiler Infrastructure
5302affcbSDimitry Andric//
6302affcbSDimitry Andric// This file is distributed under the University of Illinois Open Source
7302affcbSDimitry Andric// License. See LICENSE.TXT for details.
8302affcbSDimitry Andric//
9302affcbSDimitry Andric//===----------------------------------------------------------------------===//
10302affcbSDimitry Andric
11302affcbSDimitry Andric#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
12302affcbSDimitry Andric#define _LIBCPP_EXPERIMENTAL_COROUTINE
13302affcbSDimitry Andric
14302affcbSDimitry Andric/**
15302affcbSDimitry Andric    experimental/coroutine synopsis
16302affcbSDimitry Andric
17302affcbSDimitry Andric// C++next
18302affcbSDimitry Andric
19302affcbSDimitry Andricnamespace std {
20302affcbSDimitry Andricnamespace experimental {
21302affcbSDimitry Andricinline namespace coroutines_v1 {
22302affcbSDimitry Andric
23302affcbSDimitry Andric  // 18.11.1 coroutine traits
24302affcbSDimitry Andrictemplate <typename R, typename... ArgTypes>
25302affcbSDimitry Andricclass coroutine_traits;
26302affcbSDimitry Andric// 18.11.2 coroutine handle
27302affcbSDimitry Andrictemplate <typename Promise = void>
28302affcbSDimitry Andricclass coroutine_handle;
29302affcbSDimitry Andric// 18.11.2.7 comparison operators:
30302affcbSDimitry Andricbool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
31302affcbSDimitry Andricbool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
32302affcbSDimitry Andricbool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
33302affcbSDimitry Andricbool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
34302affcbSDimitry Andricbool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
35302affcbSDimitry Andricbool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
36302affcbSDimitry Andric// 18.11.3 trivial awaitables
37302affcbSDimitry Andricstruct suspend_never;
38302affcbSDimitry Andricstruct suspend_always;
39302affcbSDimitry Andric// 18.11.2.8 hash support:
40302affcbSDimitry Andrictemplate <class T> struct hash;
41302affcbSDimitry Andrictemplate <class P> struct hash<coroutine_handle<P>>;
42302affcbSDimitry Andric
43302affcbSDimitry Andric} // namespace coroutines_v1
44302affcbSDimitry Andric} // namespace experimental
45302affcbSDimitry Andric} // namespace std
46302affcbSDimitry Andric
47302affcbSDimitry Andric */
48302affcbSDimitry Andric
49302affcbSDimitry Andric#include <experimental/__config>
50302affcbSDimitry Andric#include <new>
51302affcbSDimitry Andric#include <type_traits>
52302affcbSDimitry Andric#include <functional>
53302affcbSDimitry Andric#include <memory> // for hash<T*>
54302affcbSDimitry Andric#include <cstddef>
55302affcbSDimitry Andric#include <cassert>
56302affcbSDimitry Andric#include <__debug>
57302affcbSDimitry Andric
58302affcbSDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
59302affcbSDimitry Andric#pragma GCC system_header
60302affcbSDimitry Andric#endif
61302affcbSDimitry Andric
62302affcbSDimitry Andric#ifdef _LIBCPP_HAS_NO_COROUTINES
63302affcbSDimitry Andric# if defined(_LIBCPP_WARNING)
64302affcbSDimitry Andric    _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler")
65302affcbSDimitry Andric# else
66302affcbSDimitry Andric#   warning <experimental/coroutine> cannot be used with this compiler
67302affcbSDimitry Andric# endif
68302affcbSDimitry Andric#endif
69302affcbSDimitry Andric
70302affcbSDimitry Andric#ifndef _LIBCPP_HAS_NO_COROUTINES
71302affcbSDimitry Andric
72302affcbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
73302affcbSDimitry Andric
74302affcbSDimitry Andrictemplate <class _Tp, class = void>
75302affcbSDimitry Andricstruct __coroutine_traits_sfinae {};
76302affcbSDimitry Andric
77302affcbSDimitry Andrictemplate <class _Tp>
78302affcbSDimitry Andricstruct __coroutine_traits_sfinae<
79302affcbSDimitry Andric    _Tp, typename __void_t<typename _Tp::promise_type>::type>
80302affcbSDimitry Andric{
81302affcbSDimitry Andric  using promise_type = typename _Tp::promise_type;
82302affcbSDimitry Andric};
83302affcbSDimitry Andric
84302affcbSDimitry Andrictemplate <typename _Ret, typename... _Args>
85302affcbSDimitry Andricstruct _LIBCPP_TEMPLATE_VIS coroutine_traits
86302affcbSDimitry Andric    : public __coroutine_traits_sfinae<_Ret>
87302affcbSDimitry Andric{
88302affcbSDimitry Andric};
89302affcbSDimitry Andric
90302affcbSDimitry Andrictemplate <typename _Promise = void>
91302affcbSDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle;
92302affcbSDimitry Andric
93302affcbSDimitry Andrictemplate <>
94302affcbSDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
95302affcbSDimitry Andricpublic:
964ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
97302affcbSDimitry Andric    _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
98302affcbSDimitry Andric
994ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
100302affcbSDimitry Andric    _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
101302affcbSDimitry Andric
1024ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
103302affcbSDimitry Andric    coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
104302affcbSDimitry Andric        __handle_ = nullptr;
105302affcbSDimitry Andric        return *this;
106302affcbSDimitry Andric    }
107302affcbSDimitry Andric
1084ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
109302affcbSDimitry Andric    _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
110302affcbSDimitry Andric
1114ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
112302affcbSDimitry Andric    _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
113302affcbSDimitry Andric
1144ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
115302affcbSDimitry Andric    void operator()() { resume(); }
116302affcbSDimitry Andric
1174ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
118302affcbSDimitry Andric    void resume() {
119302affcbSDimitry Andric      _LIBCPP_ASSERT(__is_suspended(),
120302affcbSDimitry Andric                     "resume() can only be called on suspended coroutines");
121302affcbSDimitry Andric      _LIBCPP_ASSERT(!done(),
122302affcbSDimitry Andric                "resume() has undefined behavior when the coroutine is done");
123302affcbSDimitry Andric      __builtin_coro_resume(__handle_);
124302affcbSDimitry Andric    }
125302affcbSDimitry Andric
1264ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
127302affcbSDimitry Andric    void destroy() {
128302affcbSDimitry Andric      _LIBCPP_ASSERT(__is_suspended(),
129302affcbSDimitry Andric                     "destroy() can only be called on suspended coroutines");
130302affcbSDimitry Andric      __builtin_coro_destroy(__handle_);
131302affcbSDimitry Andric    }
132302affcbSDimitry Andric
1334ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
134302affcbSDimitry Andric    bool done() const {
135302affcbSDimitry Andric      _LIBCPP_ASSERT(__is_suspended(),
136302affcbSDimitry Andric                     "done() can only be called on suspended coroutines");
137302affcbSDimitry Andric      return __builtin_coro_done(__handle_);
138302affcbSDimitry Andric    }
139302affcbSDimitry Andric
140302affcbSDimitry Andricpublic:
1414ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
142302affcbSDimitry Andric    static coroutine_handle from_address(void* __addr) _NOEXCEPT {
143302affcbSDimitry Andric        coroutine_handle __tmp;
144302affcbSDimitry Andric        __tmp.__handle_ = __addr;
145302affcbSDimitry Andric        return __tmp;
146302affcbSDimitry Andric    }
147302affcbSDimitry Andric
14889cb50c9SDimitry Andric    // FIXME: Should from_address(nullptr) be allowed?
1494ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
15089cb50c9SDimitry Andric    static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
15189cb50c9SDimitry Andric      return coroutine_handle(nullptr);
15289cb50c9SDimitry Andric    }
15389cb50c9SDimitry Andric
15489cb50c9SDimitry Andric    template <class _Tp, bool _CallIsValid = false>
15589cb50c9SDimitry Andric    static coroutine_handle from_address(_Tp*) {
15689cb50c9SDimitry Andric      static_assert(_CallIsValid,
15789cb50c9SDimitry Andric       "coroutine_handle<void>::from_address cannot be called with "
15889cb50c9SDimitry Andric        "non-void pointers");
15989cb50c9SDimitry Andric    }
16089cb50c9SDimitry Andric
161302affcbSDimitry Andricprivate:
162302affcbSDimitry Andric  bool __is_suspended() const _NOEXCEPT  {
163302affcbSDimitry Andric    // FIXME actually implement a check for if the coro is suspended.
164302affcbSDimitry Andric    return __handle_;
165302affcbSDimitry Andric  }
166302affcbSDimitry Andric
167302affcbSDimitry Andric  template <class _PromiseT> friend class coroutine_handle;
168302affcbSDimitry Andric  void* __handle_;
169302affcbSDimitry Andric};
170302affcbSDimitry Andric
171302affcbSDimitry Andric// 18.11.2.7 comparison operators:
1724ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
173302affcbSDimitry Andricbool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
174302affcbSDimitry Andric    return __x.address() == __y.address();
175302affcbSDimitry Andric}
1764ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
177302affcbSDimitry Andricbool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
178302affcbSDimitry Andric    return !(__x == __y);
179302affcbSDimitry Andric}
1804ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
181302affcbSDimitry Andricbool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
182302affcbSDimitry Andric    return less<void*>()(__x.address(), __y.address());
183302affcbSDimitry Andric}
1844ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
185302affcbSDimitry Andricbool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
186302affcbSDimitry Andric    return __y < __x;
187302affcbSDimitry Andric}
1884ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
189302affcbSDimitry Andricbool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
190302affcbSDimitry Andric    return !(__x > __y);
191302affcbSDimitry Andric}
1924ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
193302affcbSDimitry Andricbool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
194302affcbSDimitry Andric    return !(__x < __y);
195302affcbSDimitry Andric}
196302affcbSDimitry Andric
197302affcbSDimitry Andrictemplate <typename _Promise>
198302affcbSDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
199302affcbSDimitry Andric    using _Base = coroutine_handle<>;
200302affcbSDimitry Andricpublic:
201302affcbSDimitry Andric#ifndef _LIBCPP_CXX03_LANG
202302affcbSDimitry Andric    // 18.11.2.1 construct/reset
203302affcbSDimitry Andric    using coroutine_handle<>::coroutine_handle;
204302affcbSDimitry Andric#else
2054ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
2064ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
207302affcbSDimitry Andric#endif
208302affcbSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
209302affcbSDimitry Andric    coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
210302affcbSDimitry Andric        _Base::operator=(nullptr);
211302affcbSDimitry Andric        return *this;
212302affcbSDimitry Andric    }
213302affcbSDimitry Andric
214302affcbSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
215302affcbSDimitry Andric    _Promise& promise() const {
2164ba319b5SDimitry Andric        return *static_cast<_Promise*>(
217*b5893f02SDimitry Andric            __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
218302affcbSDimitry Andric    }
219302affcbSDimitry Andric
220302affcbSDimitry Andricpublic:
2214ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
222302affcbSDimitry Andric    static coroutine_handle from_address(void* __addr) _NOEXCEPT {
223302affcbSDimitry Andric        coroutine_handle __tmp;
224302affcbSDimitry Andric        __tmp.__handle_ = __addr;
225302affcbSDimitry Andric        return __tmp;
226302affcbSDimitry Andric    }
227302affcbSDimitry Andric
228302affcbSDimitry Andric    // NOTE: this overload isn't required by the standard but is needed so
229302affcbSDimitry Andric    // the deleted _Promise* overload doesn't make from_address(nullptr)
230302affcbSDimitry Andric    // ambiguous.
231302affcbSDimitry Andric    // FIXME: should from_address work with nullptr?
2324ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
233302affcbSDimitry Andric    static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
23489cb50c9SDimitry Andric      return coroutine_handle(nullptr);
235302affcbSDimitry Andric    }
236302affcbSDimitry Andric
23789cb50c9SDimitry Andric    template <class _Tp, bool _CallIsValid = false>
23889cb50c9SDimitry Andric    static coroutine_handle from_address(_Tp*) {
23989cb50c9SDimitry Andric      static_assert(_CallIsValid,
24089cb50c9SDimitry Andric       "coroutine_handle<promise_type>::from_address cannot be called with "
24189cb50c9SDimitry Andric        "non-void pointers");
24289cb50c9SDimitry Andric    }
24389cb50c9SDimitry Andric
24489cb50c9SDimitry Andric    template <bool _CallIsValid = false>
24589cb50c9SDimitry Andric    static coroutine_handle from_address(_Promise*) {
24689cb50c9SDimitry Andric      static_assert(_CallIsValid,
24789cb50c9SDimitry Andric       "coroutine_handle<promise_type>::from_address cannot be used with "
24889cb50c9SDimitry Andric        "pointers to the coroutine's promise type; use 'from_promise' instead");
24989cb50c9SDimitry Andric    }
250302affcbSDimitry Andric
2514ba319b5SDimitry Andric    _LIBCPP_INLINE_VISIBILITY
252302affcbSDimitry Andric    static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
25324d58133SDimitry Andric        typedef typename remove_cv<_Promise>::type _RawPromise;
254302affcbSDimitry Andric        coroutine_handle __tmp;
25524d58133SDimitry Andric        __tmp.__handle_ = __builtin_coro_promise(
25624d58133SDimitry Andric            _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
257*b5893f02SDimitry Andric             _LIBCPP_ALIGNOF(_Promise), true);
258302affcbSDimitry Andric        return __tmp;
259302affcbSDimitry Andric    }
260302affcbSDimitry Andric};
261302affcbSDimitry Andric
2624ba319b5SDimitry Andric#if __has_builtin(__builtin_coro_noop)
2634ba319b5SDimitry Andricstruct noop_coroutine_promise {};
2644ba319b5SDimitry Andric
2654ba319b5SDimitry Andrictemplate <>
2664ba319b5SDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
2674ba319b5SDimitry Andric    : public coroutine_handle<> {
2684ba319b5SDimitry Andric  using _Base = coroutine_handle<>;
2694ba319b5SDimitry Andric  using _Promise = noop_coroutine_promise;
2704ba319b5SDimitry Andricpublic:
2714ba319b5SDimitry Andric
2724ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
2734ba319b5SDimitry Andric  _Promise& promise() const {
2744ba319b5SDimitry Andric    return *static_cast<_Promise*>(
275*b5893f02SDimitry Andric      __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
2764ba319b5SDimitry Andric  }
2774ba319b5SDimitry Andric
2784ba319b5SDimitry Andric  _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
2794ba319b5SDimitry Andric  _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
2804ba319b5SDimitry Andric
2814ba319b5SDimitry Andric  _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
2824ba319b5SDimitry Andric  _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
2834ba319b5SDimitry Andric  _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
2844ba319b5SDimitry Andric
2854ba319b5SDimitry Andricprivate:
2864ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
2874ba319b5SDimitry Andric  friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
2884ba319b5SDimitry Andric
2894ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
2904ba319b5SDimitry Andric    this->__handle_ = __builtin_coro_noop();
2914ba319b5SDimitry Andric  }
2924ba319b5SDimitry Andric};
2934ba319b5SDimitry Andric
2944ba319b5SDimitry Andricusing noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
2954ba319b5SDimitry Andric
2964ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY
2974ba319b5SDimitry Andricnoop_coroutine_handle noop_coroutine() _NOEXCEPT {
2984ba319b5SDimitry Andric  return noop_coroutine_handle();
2994ba319b5SDimitry Andric}
3004ba319b5SDimitry Andric#endif // __has_builtin(__builtin_coro_noop)
3014ba319b5SDimitry Andric
302302affcbSDimitry Andricstruct _LIBCPP_TYPE_VIS suspend_never {
3034ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
304302affcbSDimitry Andric  bool await_ready() const _NOEXCEPT { return true; }
3054ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
306302affcbSDimitry Andric  void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
3074ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
308302affcbSDimitry Andric  void await_resume() const _NOEXCEPT {}
309302affcbSDimitry Andric};
310302affcbSDimitry Andric
311302affcbSDimitry Andricstruct _LIBCPP_TYPE_VIS suspend_always {
3124ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
313302affcbSDimitry Andric  bool await_ready() const _NOEXCEPT { return false; }
3144ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
315302affcbSDimitry Andric  void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
3164ba319b5SDimitry Andric  _LIBCPP_INLINE_VISIBILITY
317302affcbSDimitry Andric  void await_resume() const _NOEXCEPT {}
318302affcbSDimitry Andric};
319302affcbSDimitry Andric
320302affcbSDimitry Andric_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
321302affcbSDimitry Andric
322302affcbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
323302affcbSDimitry Andric
324302affcbSDimitry Andrictemplate <class _Tp>
325302affcbSDimitry Andricstruct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
326302affcbSDimitry Andric    using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
327302affcbSDimitry Andric    _LIBCPP_INLINE_VISIBILITY
328302affcbSDimitry Andric    size_t operator()(__arg_type const& __v) const _NOEXCEPT
329302affcbSDimitry Andric    {return hash<void*>()(__v.address());}
330302affcbSDimitry Andric};
331302affcbSDimitry Andric
332302affcbSDimitry Andric_LIBCPP_END_NAMESPACE_STD
333302affcbSDimitry Andric
334302affcbSDimitry Andric#endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
335302affcbSDimitry Andric
336302affcbSDimitry Andric#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
337