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