1// -*- C++ -*- 2//===----------------------------- coroutine -----------------------------===// 3// 4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5// See https://llvm.org/LICENSE.txt for license information. 6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE 11#define _LIBCPP_EXPERIMENTAL_COROUTINE 12 13/** 14 experimental/coroutine synopsis 15 16// C++next 17 18namespace std { 19namespace experimental { 20inline namespace coroutines_v1 { 21 22 // 18.11.1 coroutine traits 23template <typename R, typename... ArgTypes> 24class coroutine_traits; 25// 18.11.2 coroutine handle 26template <typename Promise = void> 27class coroutine_handle; 28// 18.11.2.7 comparison operators: 29bool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 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; 35// 18.11.3 trivial awaitables 36struct suspend_never; 37struct suspend_always; 38// 18.11.2.8 hash support: 39template <class T> struct hash; 40template <class P> struct hash<coroutine_handle<P>>; 41 42} // namespace coroutines_v1 43} // namespace experimental 44} // namespace std 45 46 */ 47 48#include <experimental/__config> 49#include <new> 50#include <type_traits> 51#include <functional> 52#include <memory> // for hash<T*> 53#include <cstddef> 54#include <__debug> 55 56#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 57#pragma GCC system_header 58#endif 59 60#ifdef _LIBCPP_HAS_NO_COROUTINES 61# if defined(_LIBCPP_WARNING) 62 _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler") 63# else 64# warning <experimental/coroutine> cannot be used with this compiler 65# endif 66#endif 67 68#ifndef _LIBCPP_HAS_NO_COROUTINES 69 70_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES 71 72template <class _Tp, class = void> 73struct __coroutine_traits_sfinae {}; 74 75template <class _Tp> 76struct __coroutine_traits_sfinae< 77 _Tp, typename __void_t<typename _Tp::promise_type>::type> 78{ 79 using promise_type = typename _Tp::promise_type; 80}; 81 82template <typename _Ret, typename... _Args> 83struct coroutine_traits 84 : public __coroutine_traits_sfinae<_Ret> 85{ 86}; 87 88template <typename _Promise = void> 89class _LIBCPP_TEMPLATE_VIS coroutine_handle; 90 91template <> 92class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { 93public: 94 _LIBCPP_INLINE_VISIBILITY 95 _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} 96 97 _LIBCPP_INLINE_VISIBILITY 98 _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} 99 100 _LIBCPP_INLINE_VISIBILITY 101 coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 102 __handle_ = nullptr; 103 return *this; 104 } 105 106 _LIBCPP_INLINE_VISIBILITY 107 _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } 108 109 _LIBCPP_INLINE_VISIBILITY 110 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } 111 112 _LIBCPP_INLINE_VISIBILITY 113 void operator()() { resume(); } 114 115 _LIBCPP_INLINE_VISIBILITY 116 void resume() { 117 _LIBCPP_ASSERT(__is_suspended(), 118 "resume() can only be called on suspended coroutines"); 119 _LIBCPP_ASSERT(!done(), 120 "resume() has undefined behavior when the coroutine is done"); 121 __builtin_coro_resume(__handle_); 122 } 123 124 _LIBCPP_INLINE_VISIBILITY 125 void destroy() { 126 _LIBCPP_ASSERT(__is_suspended(), 127 "destroy() can only be called on suspended coroutines"); 128 __builtin_coro_destroy(__handle_); 129 } 130 131 _LIBCPP_INLINE_VISIBILITY 132 bool done() const { 133 _LIBCPP_ASSERT(__is_suspended(), 134 "done() can only be called on suspended coroutines"); 135 return __builtin_coro_done(__handle_); 136 } 137 138public: 139 _LIBCPP_INLINE_VISIBILITY 140 static coroutine_handle from_address(void* __addr) _NOEXCEPT { 141 coroutine_handle __tmp; 142 __tmp.__handle_ = __addr; 143 return __tmp; 144 } 145 146 // FIXME: Should from_address(nullptr) be allowed? 147 _LIBCPP_INLINE_VISIBILITY 148 static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 149 return coroutine_handle(nullptr); 150 } 151 152 template <class _Tp, bool _CallIsValid = false> 153 static coroutine_handle from_address(_Tp*) { 154 static_assert(_CallIsValid, 155 "coroutine_handle<void>::from_address cannot be called with " 156 "non-void pointers"); 157 } 158 159private: 160 bool __is_suspended() const _NOEXCEPT { 161 // FIXME actually implement a check for if the coro is suspended. 162 return __handle_; 163 } 164 165 template <class _PromiseT> friend class coroutine_handle; 166 void* __handle_; 167}; 168 169// 18.11.2.7 comparison operators: 170inline _LIBCPP_INLINE_VISIBILITY 171bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 172 return __x.address() == __y.address(); 173} 174inline _LIBCPP_INLINE_VISIBILITY 175bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 176 return !(__x == __y); 177} 178inline _LIBCPP_INLINE_VISIBILITY 179bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 180 return less<void*>()(__x.address(), __y.address()); 181} 182inline _LIBCPP_INLINE_VISIBILITY 183bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 184 return __y < __x; 185} 186inline _LIBCPP_INLINE_VISIBILITY 187bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 188 return !(__x > __y); 189} 190inline _LIBCPP_INLINE_VISIBILITY 191bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 192 return !(__x < __y); 193} 194 195template <typename _Promise> 196class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { 197 using _Base = coroutine_handle<>; 198public: 199#ifndef _LIBCPP_CXX03_LANG 200 // 18.11.2.1 construct/reset 201 using coroutine_handle<>::coroutine_handle; 202#else 203 _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {} 204 _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} 205#endif 206 _LIBCPP_INLINE_VISIBILITY 207 coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 208 _Base::operator=(nullptr); 209 return *this; 210 } 211 212 _LIBCPP_INLINE_VISIBILITY 213 _Promise& promise() const { 214 return *static_cast<_Promise*>( 215 __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 216 } 217 218public: 219 _LIBCPP_INLINE_VISIBILITY 220 static coroutine_handle from_address(void* __addr) _NOEXCEPT { 221 coroutine_handle __tmp; 222 __tmp.__handle_ = __addr; 223 return __tmp; 224 } 225 226 // NOTE: this overload isn't required by the standard but is needed so 227 // the deleted _Promise* overload doesn't make from_address(nullptr) 228 // ambiguous. 229 // FIXME: should from_address work with nullptr? 230 _LIBCPP_INLINE_VISIBILITY 231 static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 232 return coroutine_handle(nullptr); 233 } 234 235 template <class _Tp, bool _CallIsValid = false> 236 static coroutine_handle from_address(_Tp*) { 237 static_assert(_CallIsValid, 238 "coroutine_handle<promise_type>::from_address cannot be called with " 239 "non-void pointers"); 240 } 241 242 template <bool _CallIsValid = false> 243 static coroutine_handle from_address(_Promise*) { 244 static_assert(_CallIsValid, 245 "coroutine_handle<promise_type>::from_address cannot be used with " 246 "pointers to the coroutine's promise type; use 'from_promise' instead"); 247 } 248 249 _LIBCPP_INLINE_VISIBILITY 250 static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { 251 typedef typename remove_cv<_Promise>::type _RawPromise; 252 coroutine_handle __tmp; 253 __tmp.__handle_ = __builtin_coro_promise( 254 _VSTD::addressof(const_cast<_RawPromise&>(__promise)), 255 _LIBCPP_ALIGNOF(_Promise), true); 256 return __tmp; 257 } 258}; 259 260#if __has_builtin(__builtin_coro_noop) 261struct noop_coroutine_promise {}; 262 263template <> 264class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise> 265 : public coroutine_handle<> { 266 using _Base = coroutine_handle<>; 267 using _Promise = noop_coroutine_promise; 268public: 269 270 _LIBCPP_INLINE_VISIBILITY 271 _Promise& promise() const { 272 return *static_cast<_Promise*>( 273 __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 274 } 275 276 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } 277 _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } 278 279 _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {} 280 _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {} 281 _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {} 282 283private: 284 _LIBCPP_INLINE_VISIBILITY 285 friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT; 286 287 _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT { 288 this->__handle_ = __builtin_coro_noop(); 289 } 290}; 291 292using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; 293 294inline _LIBCPP_INLINE_VISIBILITY 295noop_coroutine_handle noop_coroutine() _NOEXCEPT { 296 return noop_coroutine_handle(); 297} 298#endif // __has_builtin(__builtin_coro_noop) 299 300struct suspend_never { 301 _LIBCPP_INLINE_VISIBILITY 302 bool await_ready() const _NOEXCEPT { return true; } 303 _LIBCPP_INLINE_VISIBILITY 304 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 305 _LIBCPP_INLINE_VISIBILITY 306 void await_resume() const _NOEXCEPT {} 307}; 308 309struct suspend_always { 310 _LIBCPP_INLINE_VISIBILITY 311 bool await_ready() const _NOEXCEPT { return false; } 312 _LIBCPP_INLINE_VISIBILITY 313 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 314 _LIBCPP_INLINE_VISIBILITY 315 void await_resume() const _NOEXCEPT {} 316}; 317 318_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES 319 320_LIBCPP_BEGIN_NAMESPACE_STD 321 322template <class _Tp> 323struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { 324 using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; 325 _LIBCPP_INLINE_VISIBILITY 326 size_t operator()(__arg_type const& __v) const _NOEXCEPT 327 {return hash<void*>()(__v.address());} 328}; 329 330_LIBCPP_END_NAMESPACE_STD 331 332#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) 333 334#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ 335