Home | History | Annotate | Download | only in experimental
      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     // FIXME: Should from_address(nullptr) be allowed?
    149     _LIBCPP_ALWAYS_INLINE
    150     static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
    151       return coroutine_handle(nullptr);
    152     }
    153 
    154     template <class _Tp, bool _CallIsValid = false>
    155     static coroutine_handle from_address(_Tp*) {
    156       static_assert(_CallIsValid,
    157        "coroutine_handle<void>::from_address cannot be called with "
    158         "non-void pointers");
    159     }
    160 
    161 private:
    162   bool __is_suspended() const _NOEXCEPT  {
    163     // FIXME actually implement a check for if the coro is suspended.
    164     return __handle_;
    165   }
    166 
    167   template <class _PromiseT> friend class coroutine_handle;
    168   void* __handle_;
    169 };
    170 
    171 // 18.11.2.7 comparison operators:
    172 inline _LIBCPP_ALWAYS_INLINE
    173 bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    174     return __x.address() == __y.address();
    175 }
    176 inline _LIBCPP_ALWAYS_INLINE
    177 bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    178     return !(__x == __y);
    179 }
    180 inline _LIBCPP_ALWAYS_INLINE
    181 bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    182     return less<void*>()(__x.address(), __y.address());
    183 }
    184 inline _LIBCPP_ALWAYS_INLINE
    185 bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    186     return __y < __x;
    187 }
    188 inline _LIBCPP_ALWAYS_INLINE
    189 bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    190     return !(__x > __y);
    191 }
    192 inline _LIBCPP_ALWAYS_INLINE
    193 bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    194     return !(__x < __y);
    195 }
    196 
    197 template <typename _Promise>
    198 class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> {
    199     using _Base = coroutine_handle<>;
    200 public:
    201 #ifndef _LIBCPP_CXX03_LANG
    202     // 18.11.2.1 construct/reset
    203     using coroutine_handle<>::coroutine_handle;
    204 #else
    205     _LIBCPP_ALWAYS_INLINE coroutine_handle() _NOEXCEPT : _Base() {}
    206     _LIBCPP_ALWAYS_INLINE coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {}
    207 #endif
    208     _LIBCPP_INLINE_VISIBILITY
    209     coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
    210         _Base::operator=(nullptr);
    211         return *this;
    212     }
    213 
    214     _LIBCPP_INLINE_VISIBILITY
    215     _Promise& promise() const {
    216         return *reinterpret_cast<_Promise*>(
    217             __builtin_coro_promise(this->__handle_, __alignof(_Promise), false));
    218     }
    219 
    220 public:
    221     _LIBCPP_ALWAYS_INLINE
    222     static coroutine_handle from_address(void* __addr) _NOEXCEPT {
    223         coroutine_handle __tmp;
    224         __tmp.__handle_ = __addr;
    225         return __tmp;
    226     }
    227 
    228     // NOTE: this overload isn't required by the standard but is needed so
    229     // the deleted _Promise* overload doesn't make from_address(nullptr)
    230     // ambiguous.
    231     // FIXME: should from_address work with nullptr?
    232     _LIBCPP_ALWAYS_INLINE
    233     static coroutine_handle from_address(nullptr_t) _NOEXCEPT {
    234       return coroutine_handle(nullptr);
    235     }
    236 
    237     template <class _Tp, bool _CallIsValid = false>
    238     static coroutine_handle from_address(_Tp*) {
    239       static_assert(_CallIsValid,
    240        "coroutine_handle<promise_type>::from_address cannot be called with "
    241         "non-void pointers");
    242     }
    243 
    244     template <bool _CallIsValid = false>
    245     static coroutine_handle from_address(_Promise*) {
    246       static_assert(_CallIsValid,
    247        "coroutine_handle<promise_type>::from_address cannot be used with "
    248         "pointers to the coroutine's promise type; use 'from_promise' instead");
    249     }
    250 
    251     _LIBCPP_ALWAYS_INLINE
    252     static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT {
    253         typedef typename remove_cv<_Promise>::type _RawPromise;
    254         coroutine_handle __tmp;
    255         __tmp.__handle_ = __builtin_coro_promise(
    256             _VSTD::addressof(const_cast<_RawPromise&>(__promise)),
    257              __alignof(_Promise), true);
    258         return __tmp;
    259     }
    260 };
    261 
    262 struct _LIBCPP_TYPE_VIS suspend_never {
    263   _LIBCPP_ALWAYS_INLINE
    264   bool await_ready() const _NOEXCEPT { return true; }
    265   _LIBCPP_ALWAYS_INLINE
    266   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
    267   _LIBCPP_ALWAYS_INLINE
    268   void await_resume() const _NOEXCEPT {}
    269 };
    270 
    271 struct _LIBCPP_TYPE_VIS suspend_always {
    272   _LIBCPP_ALWAYS_INLINE
    273   bool await_ready() const _NOEXCEPT { return false; }
    274   _LIBCPP_ALWAYS_INLINE
    275   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
    276   _LIBCPP_ALWAYS_INLINE
    277   void await_resume() const _NOEXCEPT {}
    278 };
    279 
    280 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
    281 
    282 _LIBCPP_BEGIN_NAMESPACE_STD
    283 
    284 template <class _Tp>
    285 struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
    286     using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
    287     _LIBCPP_INLINE_VISIBILITY
    288     size_t operator()(__arg_type const& __v) const _NOEXCEPT
    289     {return hash<void*>()(__v.address());}
    290 };
    291 
    292 _LIBCPP_END_NAMESPACE_STD
    293 
    294 #endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
    295 
    296 #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
    297