1// -*- C++ -*- 2//===----------------------------------------------------------------------===// 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 <__assert> // all public C++ headers provide the assertion handler 49#include <__functional/hash.h> 50#include <__functional/operations.h> 51#include <cstddef> 52#include <experimental/__config> 53#include <new> 54#include <type_traits> 55 56#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 57# include <atomic> 58# include <climits> 59# include <cmath> 60# include <compare> 61# include <concepts> 62# include <ctime> 63# include <initializer_list> 64# include <iosfwd> 65# include <iterator> 66# include <memory> 67# include <ratio> 68# include <stdexcept> 69# include <tuple> 70# include <typeinfo> 71# include <utility> 72# include <variant> 73#endif 74 75#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 76# pragma GCC system_header 77#endif 78 79#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES 80 81_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES 82 83template <class _Tp, class = void> 84struct __coroutine_traits_sfinae {}; 85 86template <class _Tp> 87struct __coroutine_traits_sfinae<_Tp, __void_t<typename _Tp::promise_type> > 88{ 89 using promise_type = typename _Tp::promise_type; 90}; 91 92template <typename _Ret, typename... _Args> 93struct coroutine_traits 94 : public __coroutine_traits_sfinae<_Ret> 95{ 96}; 97 98template <typename _Promise = void> 99class _LIBCPP_TEMPLATE_VIS coroutine_handle; 100 101template <> 102class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { 103public: 104 _LIBCPP_INLINE_VISIBILITY 105 _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} 106 107 _LIBCPP_INLINE_VISIBILITY 108 _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} 109 110 _LIBCPP_INLINE_VISIBILITY 111 coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 112 __handle_ = nullptr; 113 return *this; 114 } 115 116 _LIBCPP_INLINE_VISIBILITY 117 _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } 118 119 _LIBCPP_INLINE_VISIBILITY 120 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } 121 122 _LIBCPP_INLINE_VISIBILITY 123 void operator()() { resume(); } 124 125 _LIBCPP_INLINE_VISIBILITY 126 void resume() { 127 _LIBCPP_ASSERT(__is_suspended(), 128 "resume() can only be called on suspended coroutines"); 129 _LIBCPP_ASSERT(!done(), 130 "resume() has undefined behavior when the coroutine is done"); 131 __builtin_coro_resume(__handle_); 132 } 133 134 _LIBCPP_INLINE_VISIBILITY 135 void destroy() { 136 _LIBCPP_ASSERT(__is_suspended(), 137 "destroy() can only be called on suspended coroutines"); 138 __builtin_coro_destroy(__handle_); 139 } 140 141 _LIBCPP_INLINE_VISIBILITY 142 bool done() const { 143 _LIBCPP_ASSERT(__is_suspended(), 144 "done() can only be called on suspended coroutines"); 145 return __builtin_coro_done(__handle_); 146 } 147 148public: 149 _LIBCPP_INLINE_VISIBILITY 150 static coroutine_handle from_address(void* __addr) _NOEXCEPT { 151 coroutine_handle __tmp; 152 __tmp.__handle_ = __addr; 153 return __tmp; 154 } 155 156 // FIXME: Should from_address(nullptr) be allowed? 157 _LIBCPP_INLINE_VISIBILITY 158 static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 159 return coroutine_handle(nullptr); 160 } 161 162 template <class _Tp, bool _CallIsValid = false> 163 static coroutine_handle from_address(_Tp*) { 164 static_assert(_CallIsValid, 165 "coroutine_handle<void>::from_address cannot be called with " 166 "non-void pointers"); 167 } 168 169private: 170 bool __is_suspended() const _NOEXCEPT { 171 // FIXME actually implement a check for if the coro is suspended. 172 return __handle_; 173 } 174 175 template <class _PromiseT> friend class coroutine_handle; 176 void* __handle_; 177}; 178 179// 18.11.2.7 comparison operators: 180inline _LIBCPP_INLINE_VISIBILITY 181bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 182 return __x.address() == __y.address(); 183} 184inline _LIBCPP_INLINE_VISIBILITY 185bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 186 return !(__x == __y); 187} 188inline _LIBCPP_INLINE_VISIBILITY 189bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 190 return less<void*>()(__x.address(), __y.address()); 191} 192inline _LIBCPP_INLINE_VISIBILITY 193bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 194 return __y < __x; 195} 196inline _LIBCPP_INLINE_VISIBILITY 197bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 198 return !(__x > __y); 199} 200inline _LIBCPP_INLINE_VISIBILITY 201bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 202 return !(__x < __y); 203} 204 205template <typename _Promise> 206class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { 207 using _Base = coroutine_handle<>; 208public: 209#ifndef _LIBCPP_CXX03_LANG 210 // 18.11.2.1 construct/reset 211 using coroutine_handle<>::coroutine_handle; 212#else 213 _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {} 214 _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} 215#endif 216 _LIBCPP_INLINE_VISIBILITY 217 coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 218 _Base::operator=(nullptr); 219 return *this; 220 } 221 222 _LIBCPP_INLINE_VISIBILITY 223 _Promise& promise() const { 224 return *static_cast<_Promise*>( 225 __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 226 } 227 228public: 229 _LIBCPP_INLINE_VISIBILITY 230 static coroutine_handle from_address(void* __addr) _NOEXCEPT { 231 coroutine_handle __tmp; 232 __tmp.__handle_ = __addr; 233 return __tmp; 234 } 235 236 // NOTE: this overload isn't required by the standard but is needed so 237 // the deleted _Promise* overload doesn't make from_address(nullptr) 238 // ambiguous. 239 // FIXME: should from_address work with nullptr? 240 _LIBCPP_INLINE_VISIBILITY 241 static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 242 return coroutine_handle(nullptr); 243 } 244 245 template <class _Tp, bool _CallIsValid = false> 246 static coroutine_handle from_address(_Tp*) { 247 static_assert(_CallIsValid, 248 "coroutine_handle<promise_type>::from_address cannot be called with " 249 "non-void pointers"); 250 } 251 252 template <bool _CallIsValid = false> 253 static coroutine_handle from_address(_Promise*) { 254 static_assert(_CallIsValid, 255 "coroutine_handle<promise_type>::from_address cannot be used with " 256 "pointers to the coroutine's promise type; use 'from_promise' instead"); 257 } 258 259 _LIBCPP_INLINE_VISIBILITY 260 static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { 261 typedef __remove_cv_t<_Promise> _RawPromise; 262 coroutine_handle __tmp; 263 __tmp.__handle_ = __builtin_coro_promise( 264 _VSTD::addressof(const_cast<_RawPromise&>(__promise)), 265 _LIBCPP_ALIGNOF(_Promise), true); 266 return __tmp; 267 } 268}; 269 270#if __has_builtin(__builtin_coro_noop) 271struct noop_coroutine_promise {}; 272 273template <> 274class _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise> 275 : public coroutine_handle<> { 276 using _Base = coroutine_handle<>; 277 using _Promise = noop_coroutine_promise; 278public: 279 280 _LIBCPP_INLINE_VISIBILITY 281 _Promise& promise() const { 282 return *static_cast<_Promise*>( 283 __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 284 } 285 286 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } 287 _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } 288 289 _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()() const _NOEXCEPT {} 290 _LIBCPP_CONSTEXPR_SINCE_CXX20 void resume() const _NOEXCEPT {} 291 _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy() const _NOEXCEPT {} 292 293private: 294 _LIBCPP_INLINE_VISIBILITY 295 friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT; 296 297 _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT { 298 this->__handle_ = __builtin_coro_noop(); 299 } 300}; 301 302using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; 303 304inline _LIBCPP_INLINE_VISIBILITY 305noop_coroutine_handle noop_coroutine() _NOEXCEPT { 306 return noop_coroutine_handle(); 307} 308#endif // __has_builtin(__builtin_coro_noop) 309 310struct suspend_never { 311 _LIBCPP_INLINE_VISIBILITY 312 bool await_ready() const _NOEXCEPT { return true; } 313 _LIBCPP_INLINE_VISIBILITY 314 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 315 _LIBCPP_INLINE_VISIBILITY 316 void await_resume() const _NOEXCEPT {} 317}; 318 319struct suspend_always { 320 _LIBCPP_INLINE_VISIBILITY 321 bool await_ready() const _NOEXCEPT { return false; } 322 _LIBCPP_INLINE_VISIBILITY 323 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 324 _LIBCPP_INLINE_VISIBILITY 325 void await_resume() const _NOEXCEPT {} 326}; 327 328_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES 329 330_LIBCPP_BEGIN_NAMESPACE_STD 331 332template <class _Tp> 333struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { 334 using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; 335 _LIBCPP_INLINE_VISIBILITY 336 size_t operator()(__arg_type const& __v) const _NOEXCEPT 337 {return hash<void*>()(__v.address());} 338}; 339 340_LIBCPP_END_NAMESPACE_STD 341 342#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) 343 344#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ 345