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 19namespace std { 20namespace experimental { 21inline namespace coroutines_v1 { 22 23 // 18.11.1 coroutine traits 24template <typename R, typename... ArgTypes> 25class coroutine_traits; 26// 18.11.2 coroutine handle 27template <typename Promise = void> 28class coroutine_handle; 29// 18.11.2.7 comparison operators: 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; 35bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 36// 18.11.3 trivial awaitables 37struct suspend_never; 38struct suspend_always; 39// 18.11.2.8 hash support: 40template <class T> struct hash; 41template <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 74template <class _Tp, class = void> 75struct __coroutine_traits_sfinae {}; 76 77template <class _Tp> 78struct __coroutine_traits_sfinae< 79 _Tp, typename __void_t<typename _Tp::promise_type>::type> 80{ 81 using promise_type = typename _Tp::promise_type; 82}; 83 84template <typename _Ret, typename... _Args> 85struct _LIBCPP_TEMPLATE_VIS coroutine_traits 86 : public __coroutine_traits_sfinae<_Ret> 87{ 88}; 89 90template <typename _Promise = void> 91class _LIBCPP_TEMPLATE_VIS coroutine_handle; 92 93template <> 94class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { 95public: 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 140public: 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 148private: 149 bool __is_suspended() const _NOEXCEPT { 150 // FIXME actually implement a check for if the coro is suspended. 151 return __handle_; 152 } 153 154 template <class _PromiseT> friend class coroutine_handle; 155 void* __handle_; 156}; 157 158// 18.11.2.7 comparison operators: 159inline _LIBCPP_ALWAYS_INLINE 160bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 161 return __x.address() == __y.address(); 162} 163inline _LIBCPP_ALWAYS_INLINE 164bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 165 return !(__x == __y); 166} 167inline _LIBCPP_ALWAYS_INLINE 168bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 169 return less<void*>()(__x.address(), __y.address()); 170} 171inline _LIBCPP_ALWAYS_INLINE 172bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 173 return __y < __x; 174} 175inline _LIBCPP_ALWAYS_INLINE 176bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 177 return !(__x > __y); 178} 179inline _LIBCPP_ALWAYS_INLINE 180bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 181 return !(__x < __y); 182} 183 184template <typename _Promise> 185class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { 186 using _Base = coroutine_handle<>; 187public: 188#ifndef _LIBCPP_CXX03_LANG 189 // 18.11.2.1 construct/reset 190 using coroutine_handle<>::coroutine_handle; 191#else 192 _LIBCPP_ALWAYS_INLINE coroutine_handle() _NOEXCEPT : _Base() {} 193 _LIBCPP_ALWAYS_INLINE coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} 194#endif 195 _LIBCPP_INLINE_VISIBILITY 196 coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 197 _Base::operator=(nullptr); 198 return *this; 199 } 200 201 _LIBCPP_INLINE_VISIBILITY 202 _Promise& promise() const { 203 return *reinterpret_cast<_Promise*>( 204 __builtin_coro_promise(this->__handle_, __alignof(_Promise), false)); 205 } 206 207public: 208 _LIBCPP_ALWAYS_INLINE 209 static coroutine_handle from_address(void* __addr) _NOEXCEPT { 210 coroutine_handle __tmp; 211 __tmp.__handle_ = __addr; 212 return __tmp; 213 } 214 215 // from_address cannot be used with the coroutines promise type. 216 static coroutine_handle from_address(_Promise*) = delete; 217 218 _LIBCPP_ALWAYS_INLINE 219 static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { 220 coroutine_handle __tmp; 221 __tmp.__handle_ = __builtin_coro_promise(_VSTD::addressof(__promise), 222 __alignof(_Promise), true); 223 return __tmp; 224 } 225}; 226 227struct _LIBCPP_TYPE_VIS suspend_never { 228 _LIBCPP_ALWAYS_INLINE 229 bool await_ready() const _NOEXCEPT { return true; } 230 _LIBCPP_ALWAYS_INLINE 231 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 232 _LIBCPP_ALWAYS_INLINE 233 void await_resume() const _NOEXCEPT {} 234}; 235 236struct _LIBCPP_TYPE_VIS suspend_always { 237 _LIBCPP_ALWAYS_INLINE 238 bool await_ready() const _NOEXCEPT { return false; } 239 _LIBCPP_ALWAYS_INLINE 240 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 241 _LIBCPP_ALWAYS_INLINE 242 void await_resume() const _NOEXCEPT {} 243}; 244 245_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES 246 247_LIBCPP_BEGIN_NAMESPACE_STD 248 249template <class _Tp> 250struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { 251 using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; 252 _LIBCPP_INLINE_VISIBILITY 253 size_t operator()(__arg_type const& __v) const _NOEXCEPT 254 {return hash<void*>()(__v.address());} 255}; 256 257_LIBCPP_END_NAMESPACE_STD 258 259#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) 260 261#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ 262