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