13ca91850SEric Fiselier// -*- C++ -*-
2eb8650a7SLouis Dionne//===----------------------------------------------------------------------===//
33ca91850SEric Fiselier//
42946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
52946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
62946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
73ca91850SEric Fiselier//
83ca91850SEric Fiselier//===----------------------------------------------------------------------===//
93ca91850SEric Fiselier
103ca91850SEric Fiselier#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE
113ca91850SEric Fiselier#define _LIBCPP_EXPERIMENTAL_COROUTINE
123ca91850SEric Fiselier
133ca91850SEric Fiselier/**
143ca91850SEric Fiselier    experimental/coroutine synopsis
153ca91850SEric Fiselier
163ca91850SEric Fiselier// C++next
173ca91850SEric Fiselier
183ca91850SEric Fiseliernamespace std {
193ca91850SEric Fiseliernamespace experimental {
203ca91850SEric Fiselierinline namespace coroutines_v1 {
213ca91850SEric Fiselier
223ca91850SEric Fiselier  // 18.11.1 coroutine traits
233ca91850SEric Fiseliertemplate <typename R, typename... ArgTypes>
243ca91850SEric Fiselierclass coroutine_traits;
253ca91850SEric Fiselier// 18.11.2 coroutine handle
263ca91850SEric Fiseliertemplate <typename Promise = void>
273ca91850SEric Fiselierclass coroutine_handle;
283ca91850SEric Fiselier// 18.11.2.7 comparison operators:
29997a3914SEric Fiselierbool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
30997a3914SEric Fiselierbool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
31997a3914SEric Fiselierbool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
32997a3914SEric Fiselierbool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
33997a3914SEric Fiselierbool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
34997a3914SEric Fiselierbool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT;
353ca91850SEric Fiselier// 18.11.3 trivial awaitables
363ca91850SEric Fiselierstruct suspend_never;
373ca91850SEric Fiselierstruct suspend_always;
383ca91850SEric Fiselier// 18.11.2.8 hash support:
393ca91850SEric Fiseliertemplate <class T> struct hash;
403ca91850SEric Fiseliertemplate <class P> struct hash<coroutine_handle<P>>;
413ca91850SEric Fiselier
423ca91850SEric Fiselier} // namespace coroutines_v1
433ca91850SEric Fiselier} // namespace experimental
443ca91850SEric Fiselier} // namespace std
453ca91850SEric Fiselier
463ca91850SEric Fiselier */
473ca91850SEric Fiselier
48385cc25aSLouis Dionne#include <__assert> // all public C++ headers provide the assertion handler
49faef447eSNikolas Klauser#include <__functional/hash.h>
50*34f73804SNikolas Klauser#include <__functional/operations.h>
514d81a46fSArthur O'Dwyer#include <cstddef>
523ca91850SEric Fiselier#include <experimental/__config>
533ca91850SEric Fiselier#include <memory> // for hash<T*>
544d81a46fSArthur O'Dwyer#include <new>
554d81a46fSArthur O'Dwyer#include <type_traits>
563ca91850SEric Fiselier
573ca91850SEric Fiselier#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
583ca91850SEric Fiselier#  pragma GCC system_header
593ca91850SEric Fiselier#endif
603ca91850SEric Fiselier
612e6ae1d3SChuanqi Xu#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES
62eb04c8caSEric Fiselier
633ca91850SEric Fiselier_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES
643ca91850SEric Fiselier
653ca91850SEric Fiseliertemplate <class _Tp, class = void>
663ca91850SEric Fiselierstruct __coroutine_traits_sfinae {};
673ca91850SEric Fiselier
683ca91850SEric Fiseliertemplate <class _Tp>
693ca91850SEric Fiselierstruct __coroutine_traits_sfinae<
703ca91850SEric Fiselier    _Tp, typename __void_t<typename _Tp::promise_type>::type>
713ca91850SEric Fiselier{
723ca91850SEric Fiselier  using promise_type = typename _Tp::promise_type;
733ca91850SEric Fiselier};
743ca91850SEric Fiselier
753ca91850SEric Fiseliertemplate <typename _Ret, typename... _Args>
76c3d6a929SEric Fiselierstruct coroutine_traits
773ca91850SEric Fiselier    : public __coroutine_traits_sfinae<_Ret>
783ca91850SEric Fiselier{
793ca91850SEric Fiselier};
803ca91850SEric Fiselier
81ea96891fSEric Fiseliertemplate <typename _Promise = void>
823ca91850SEric Fiselierclass _LIBCPP_TEMPLATE_VIS coroutine_handle;
833ca91850SEric Fiselier
843ca91850SEric Fiseliertemplate <>
853ca91850SEric Fiselierclass _LIBCPP_TEMPLATE_VIS coroutine_handle<void> {
863ca91850SEric Fiselierpublic:
870f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
88997a3914SEric Fiselier    _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
893ca91850SEric Fiselier
900f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
91997a3914SEric Fiselier    _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
923ca91850SEric Fiselier
930f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
94997a3914SEric Fiselier    coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
953ca91850SEric Fiselier        __handle_ = nullptr;
963ca91850SEric Fiselier        return *this;
973ca91850SEric Fiselier    }
983ca91850SEric Fiselier
990f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
100997a3914SEric Fiselier    _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
1013ca91850SEric Fiselier
1020f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
103997a3914SEric Fiselier    _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
1043ca91850SEric Fiselier
1050f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
10651056aefSEric Fiselier    void operator()() { resume(); }
1073ca91850SEric Fiselier
1080f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
10951056aefSEric Fiselier    void resume() {
1103ca91850SEric Fiselier      _LIBCPP_ASSERT(__is_suspended(),
1113ca91850SEric Fiselier                     "resume() can only be called on suspended coroutines");
1123ca91850SEric Fiselier      _LIBCPP_ASSERT(!done(),
1133ca91850SEric Fiselier                "resume() has undefined behavior when the coroutine is done");
1143ca91850SEric Fiselier      __builtin_coro_resume(__handle_);
1153ca91850SEric Fiselier    }
1163ca91850SEric Fiselier
1170f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
11851056aefSEric Fiselier    void destroy() {
1193ca91850SEric Fiselier      _LIBCPP_ASSERT(__is_suspended(),
1203ca91850SEric Fiselier                     "destroy() can only be called on suspended coroutines");
1213ca91850SEric Fiselier      __builtin_coro_destroy(__handle_);
1223ca91850SEric Fiselier    }
1233ca91850SEric Fiselier
1240f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
1253ca91850SEric Fiselier    bool done() const {
1263ca91850SEric Fiselier      _LIBCPP_ASSERT(__is_suspended(),
1273ca91850SEric Fiselier                     "done() can only be called on suspended coroutines");
1283ca91850SEric Fiselier      return __builtin_coro_done(__handle_);
1293ca91850SEric Fiselier    }
1303ca91850SEric Fiselier
1313ca91850SEric Fiselierpublic:
1320f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
133997a3914SEric Fiselier    static coroutine_handle from_address(void* __addr) _NOEXCEPT {
1343ca91850SEric Fiselier        coroutine_handle __tmp;
1353ca91850SEric Fiselier        __tmp.__handle_ = __addr;
1363ca91850SEric Fiselier        return __tmp;
1373ca91850SEric Fiselier    }
1383ca91850SEric Fiselier
1393fd0228eSEric Fiselier    // FIXME: Should from_address(nullptr) be allowed?
1400f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
1413fd0228eSEric Fiselier    static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
1426e88ac2bSEric Fiselier      return coroutine_handle(nullptr);
1433fd0228eSEric Fiselier    }
1443fd0228eSEric Fiselier
1453fd0228eSEric Fiselier    template <class _Tp, bool _CallIsValid = false>
1463fd0228eSEric Fiselier    static coroutine_handle from_address(_Tp*) {
1473fd0228eSEric Fiselier      static_assert(_CallIsValid,
1483fd0228eSEric Fiselier       "coroutine_handle<void>::from_address cannot be called with "
1493fd0228eSEric Fiselier        "non-void pointers");
1503fd0228eSEric Fiselier    }
1513fd0228eSEric Fiselier
1523ca91850SEric Fiselierprivate:
153997a3914SEric Fiselier  bool __is_suspended() const _NOEXCEPT  {
1543ca91850SEric Fiselier    // FIXME actually implement a check for if the coro is suspended.
1553ca91850SEric Fiselier    return __handle_;
1563ca91850SEric Fiselier  }
1573ca91850SEric Fiselier
1583ca91850SEric Fiselier  template <class _PromiseT> friend class coroutine_handle;
1593ca91850SEric Fiselier  void* __handle_;
1603ca91850SEric Fiselier};
1613ca91850SEric Fiselier
1623ca91850SEric Fiselier// 18.11.2.7 comparison operators:
1630f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
164997a3914SEric Fiselierbool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
1653ca91850SEric Fiselier    return __x.address() == __y.address();
1663ca91850SEric Fiselier}
1670f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
168997a3914SEric Fiselierbool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
1693ca91850SEric Fiselier    return !(__x == __y);
1703ca91850SEric Fiselier}
1710f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
172997a3914SEric Fiselierbool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
1733ca91850SEric Fiselier    return less<void*>()(__x.address(), __y.address());
1743ca91850SEric Fiselier}
1750f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
176997a3914SEric Fiselierbool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
1773ca91850SEric Fiselier    return __y < __x;
1783ca91850SEric Fiselier}
1790f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
180997a3914SEric Fiselierbool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
1813ca91850SEric Fiselier    return !(__x > __y);
1823ca91850SEric Fiselier}
1830f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
184997a3914SEric Fiselierbool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
1853ca91850SEric Fiselier    return !(__x < __y);
1863ca91850SEric Fiselier}
1873ca91850SEric Fiselier
1883ca91850SEric Fiseliertemplate <typename _Promise>
1893ca91850SEric Fiselierclass _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
1903ca91850SEric Fiselier    using _Base = coroutine_handle<>;
1913ca91850SEric Fiselierpublic:
192997a3914SEric Fiselier#ifndef _LIBCPP_CXX03_LANG
1933ca91850SEric Fiselier    // 18.11.2.1 construct/reset
1943ca91850SEric Fiselier    using coroutine_handle<>::coroutine_handle;
195997a3914SEric Fiselier#else
1960f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
1970f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
198997a3914SEric Fiselier#endif
1993ca91850SEric Fiselier    _LIBCPP_INLINE_VISIBILITY
200997a3914SEric Fiselier    coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
2013ca91850SEric Fiselier        _Base::operator=(nullptr);
2023ca91850SEric Fiselier        return *this;
2033ca91850SEric Fiselier    }
2043ca91850SEric Fiselier
2053ca91850SEric Fiselier    _LIBCPP_INLINE_VISIBILITY
2062944c5a3SEric Fiselier    _Promise& promise() const {
2070f87a807SGor Nishanov        return *static_cast<_Promise*>(
208d108bf85SEric Fiselier            __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
2093ca91850SEric Fiselier    }
2103ca91850SEric Fiselier
2113ca91850SEric Fiselierpublic:
2120f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
213997a3914SEric Fiselier    static coroutine_handle from_address(void* __addr) _NOEXCEPT {
2143ca91850SEric Fiselier        coroutine_handle __tmp;
2153ca91850SEric Fiselier        __tmp.__handle_ = __addr;
2163ca91850SEric Fiselier        return __tmp;
2173ca91850SEric Fiselier    }
2183ca91850SEric Fiselier
219bae0a1d4SEric Fiselier    // NOTE: this overload isn't required by the standard but is needed so
220bae0a1d4SEric Fiselier    // the deleted _Promise* overload doesn't make from_address(nullptr)
221bae0a1d4SEric Fiselier    // ambiguous.
222bae0a1d4SEric Fiselier    // FIXME: should from_address work with nullptr?
2230f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
224bae0a1d4SEric Fiselier    static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
2256e88ac2bSEric Fiselier      return coroutine_handle(nullptr);
226bae0a1d4SEric Fiselier    }
227bae0a1d4SEric Fiselier
2283fd0228eSEric Fiselier    template <class _Tp, bool _CallIsValid = false>
2293fd0228eSEric Fiselier    static coroutine_handle from_address(_Tp*) {
2303fd0228eSEric Fiselier      static_assert(_CallIsValid,
2313fd0228eSEric Fiselier       "coroutine_handle<promise_type>::from_address cannot be called with "
2323fd0228eSEric Fiselier        "non-void pointers");
2333fd0228eSEric Fiselier    }
2343fd0228eSEric Fiselier
2353fd0228eSEric Fiselier    template <bool _CallIsValid = false>
2363fd0228eSEric Fiselier    static coroutine_handle from_address(_Promise*) {
2373fd0228eSEric Fiselier      static_assert(_CallIsValid,
2383fd0228eSEric Fiselier       "coroutine_handle<promise_type>::from_address cannot be used with "
2393fd0228eSEric Fiselier        "pointers to the coroutine's promise type; use 'from_promise' instead");
2403fd0228eSEric Fiselier    }
241207d13cfSEric Fiselier
2420f87a807SGor Nishanov    _LIBCPP_INLINE_VISIBILITY
243997a3914SEric Fiselier    static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
244f9bc0589SEric Fiselier        typedef typename remove_cv<_Promise>::type _RawPromise;
2453ca91850SEric Fiselier        coroutine_handle __tmp;
246f9bc0589SEric Fiselier        __tmp.__handle_ = __builtin_coro_promise(
247f9bc0589SEric Fiselier            _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
248d108bf85SEric Fiselier             _LIBCPP_ALIGNOF(_Promise), true);
2493ca91850SEric Fiselier        return __tmp;
2503ca91850SEric Fiselier    }
2513ca91850SEric Fiselier};
2523ca91850SEric Fiselier
2530f87a807SGor Nishanov#if __has_builtin(__builtin_coro_noop)
2540f87a807SGor Nishanovstruct noop_coroutine_promise {};
2550f87a807SGor Nishanov
2560f87a807SGor Nishanovtemplate <>
2570f87a807SGor Nishanovclass _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
2580f87a807SGor Nishanov    : public coroutine_handle<> {
2590f87a807SGor Nishanov  using _Base = coroutine_handle<>;
2600f87a807SGor Nishanov  using _Promise = noop_coroutine_promise;
2610f87a807SGor Nishanovpublic:
2620f87a807SGor Nishanov
2630f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
2640f87a807SGor Nishanov  _Promise& promise() const {
2650f87a807SGor Nishanov    return *static_cast<_Promise*>(
266d108bf85SEric Fiselier      __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false));
2670f87a807SGor Nishanov  }
2680f87a807SGor Nishanov
2690f87a807SGor Nishanov  _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
2700f87a807SGor Nishanov  _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
2710f87a807SGor Nishanov
2728f310655SGor Nishanov  _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
2738f310655SGor Nishanov  _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
2748f310655SGor Nishanov  _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
2750f87a807SGor Nishanov
2760f87a807SGor Nishanovprivate:
277cf3ae384SLouis Dionne  _LIBCPP_INLINE_VISIBILITY
2780f87a807SGor Nishanov  friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
2790f87a807SGor Nishanov
2800f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
2810f87a807SGor Nishanov    this->__handle_ = __builtin_coro_noop();
2820f87a807SGor Nishanov  }
2830f87a807SGor Nishanov};
2840f87a807SGor Nishanov
2850f87a807SGor Nishanovusing noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
2860f87a807SGor Nishanov
2870f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY
2880f87a807SGor Nishanovnoop_coroutine_handle noop_coroutine() _NOEXCEPT {
289b1e985dbSGor Nishanov  return noop_coroutine_handle();
2900f87a807SGor Nishanov}
2910f87a807SGor Nishanov#endif // __has_builtin(__builtin_coro_noop)
2920f87a807SGor Nishanov
293c3d6a929SEric Fiselierstruct suspend_never {
2940f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
295997a3914SEric Fiselier  bool await_ready() const _NOEXCEPT { return true; }
2960f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
297997a3914SEric Fiselier  void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
2980f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
299997a3914SEric Fiselier  void await_resume() const _NOEXCEPT {}
3003ca91850SEric Fiselier};
3013ca91850SEric Fiselier
302c3d6a929SEric Fiselierstruct suspend_always {
3030f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
304997a3914SEric Fiselier  bool await_ready() const _NOEXCEPT { return false; }
3050f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
306997a3914SEric Fiselier  void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
3070f87a807SGor Nishanov  _LIBCPP_INLINE_VISIBILITY
308997a3914SEric Fiselier  void await_resume() const _NOEXCEPT {}
3093ca91850SEric Fiselier};
3103ca91850SEric Fiselier
3113ca91850SEric Fiselier_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
3123ca91850SEric Fiselier
3133ca91850SEric Fiselier_LIBCPP_BEGIN_NAMESPACE_STD
3143ca91850SEric Fiselier
3153ca91850SEric Fiseliertemplate <class _Tp>
3163ca91850SEric Fiselierstruct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
3173ca91850SEric Fiselier    using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
3183ca91850SEric Fiselier    _LIBCPP_INLINE_VISIBILITY
319997a3914SEric Fiselier    size_t operator()(__arg_type const& __v) const _NOEXCEPT
320997a3914SEric Fiselier    {return hash<void*>()(__v.address());}
3213ca91850SEric Fiselier};
3223ca91850SEric Fiselier
3233ca91850SEric Fiselier_LIBCPP_END_NAMESPACE_STD
3243ca91850SEric Fiselier
3252e6ae1d3SChuanqi Xu#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES)
326eb04c8caSEric Fiselier
3273ca91850SEric Fiselier#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
328