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