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_INLINE_VISIBILITY
     97     _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {}
     98 
     99     _LIBCPP_INLINE_VISIBILITY
    100     _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {}
    101 
    102     _LIBCPP_INLINE_VISIBILITY
    103     coroutine_handle& operator=(nullptr_t) _NOEXCEPT {
    104         __handle_ = nullptr;
    105         return *this;
    106     }
    107 
    108     _LIBCPP_INLINE_VISIBILITY
    109     _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; }
    110 
    111     _LIBCPP_INLINE_VISIBILITY
    112     _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; }
    113 
    114     _LIBCPP_INLINE_VISIBILITY
    115     void operator()() { resume(); }
    116 
    117     _LIBCPP_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    173 bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    174     return __x.address() == __y.address();
    175 }
    176 inline _LIBCPP_INLINE_VISIBILITY
    177 bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    178     return !(__x == __y);
    179 }
    180 inline _LIBCPP_INLINE_VISIBILITY
    181 bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    182     return less<void*>()(__x.address(), __y.address());
    183 }
    184 inline _LIBCPP_INLINE_VISIBILITY
    185 bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    186     return __y < __x;
    187 }
    188 inline _LIBCPP_INLINE_VISIBILITY
    189 bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT {
    190     return !(__x > __y);
    191 }
    192 inline _LIBCPP_INLINE_VISIBILITY
    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_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {}
    206     _LIBCPP_INLINE_VISIBILITY 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 *static_cast<_Promise*>(
    217             __builtin_coro_promise(this->__handle_, __alignof(_Promise), false));
    218     }
    219 
    220 public:
    221     _LIBCPP_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    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_INLINE_VISIBILITY
    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 #if __has_builtin(__builtin_coro_noop)
    263 struct noop_coroutine_promise {};
    264 
    265 template <>
    266 class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise>
    267     : public coroutine_handle<> {
    268   using _Base = coroutine_handle<>;
    269   using _Promise = noop_coroutine_promise;
    270 public:
    271 
    272   _LIBCPP_INLINE_VISIBILITY
    273   _Promise& promise() const {
    274     return *static_cast<_Promise*>(
    275       __builtin_coro_promise(this->__handle_, __alignof(_Promise), false));
    276   }
    277 
    278   _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; }
    279   _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; }
    280 
    281   _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {}
    282   _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {}
    283   _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {}
    284 
    285 private:
    286   _LIBCPP_INLINE_VISIBILITY
    287   friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT;
    288 
    289   _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT {
    290     this->__handle_ = __builtin_coro_noop();
    291   }
    292 };
    293 
    294 using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
    295 
    296 inline _LIBCPP_INLINE_VISIBILITY
    297 noop_coroutine_handle noop_coroutine() _NOEXCEPT {
    298   return noop_coroutine_handle();
    299 }
    300 #endif // __has_builtin(__builtin_coro_noop)
    301 
    302 struct _LIBCPP_TYPE_VIS suspend_never {
    303   _LIBCPP_INLINE_VISIBILITY
    304   bool await_ready() const _NOEXCEPT { return true; }
    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 struct _LIBCPP_TYPE_VIS suspend_always {
    312   _LIBCPP_INLINE_VISIBILITY
    313   bool await_ready() const _NOEXCEPT { return false; }
    314   _LIBCPP_INLINE_VISIBILITY
    315   void await_suspend(coroutine_handle<>) const _NOEXCEPT {}
    316   _LIBCPP_INLINE_VISIBILITY
    317   void await_resume() const _NOEXCEPT {}
    318 };
    319 
    320 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES
    321 
    322 _LIBCPP_BEGIN_NAMESPACE_STD
    323 
    324 template <class _Tp>
    325 struct hash<_VSTD_CORO::coroutine_handle<_Tp> > {
    326     using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>;
    327     _LIBCPP_INLINE_VISIBILITY
    328     size_t operator()(__arg_type const& __v) const _NOEXCEPT
    329     {return hash<void*>()(__v.address());}
    330 };
    331 
    332 _LIBCPP_END_NAMESPACE_STD
    333 
    334 #endif // !defined(_LIBCPP_HAS_NO_COROUTINES)
    335 
    336 #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */
    337