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 19namespace std { 20namespace experimental { 21inline namespace coroutines_v1 { 22 23 // 18.11.1 coroutine traits 24template <typename R, typename... ArgTypes> 25class coroutine_traits; 26// 18.11.2 coroutine handle 27template <typename Promise = void> 28class coroutine_handle; 29// 18.11.2.7 comparison operators: 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; 35bool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 36// 18.11.3 trivial awaitables 37struct suspend_never; 38struct suspend_always; 39// 18.11.2.8 hash support: 40template <class T> struct hash; 41template <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 74template <class _Tp, class = void> 75struct __coroutine_traits_sfinae {}; 76 77template <class _Tp> 78struct __coroutine_traits_sfinae< 79 _Tp, typename __void_t<typename _Tp::promise_type>::type> 80{ 81 using promise_type = typename _Tp::promise_type; 82}; 83 84template <typename _Ret, typename... _Args> 85struct _LIBCPP_TEMPLATE_VIS coroutine_traits 86 : public __coroutine_traits_sfinae<_Ret> 87{ 88}; 89 90template <typename _Promise = void> 91class _LIBCPP_TEMPLATE_VIS coroutine_handle; 92 93template <> 94class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { 95public: 96 _LIBCPP_ALWAYS_INLINE 97 _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} 98 99 _LIBCPP_ALWAYS_INLINE 100 _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} 101 102 _LIBCPP_ALWAYS_INLINE 103 coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 104 __handle_ = nullptr; 105 return *this; 106 } 107 108 _LIBCPP_ALWAYS_INLINE 109 _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } 110 111 _LIBCPP_ALWAYS_INLINE 112 _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } 113 114 _LIBCPP_ALWAYS_INLINE 115 void operator()() { resume(); } 116 117 _LIBCPP_ALWAYS_INLINE 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_ALWAYS_INLINE 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_ALWAYS_INLINE 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 140public: 141 _LIBCPP_ALWAYS_INLINE 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_ALWAYS_INLINE 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 161private: 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: 172inline _LIBCPP_ALWAYS_INLINE 173bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 174 return __x.address() == __y.address(); 175} 176inline _LIBCPP_ALWAYS_INLINE 177bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 178 return !(__x == __y); 179} 180inline _LIBCPP_ALWAYS_INLINE 181bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 182 return less<void*>()(__x.address(), __y.address()); 183} 184inline _LIBCPP_ALWAYS_INLINE 185bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 186 return __y < __x; 187} 188inline _LIBCPP_ALWAYS_INLINE 189bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 190 return !(__x > __y); 191} 192inline _LIBCPP_ALWAYS_INLINE 193bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 194 return !(__x < __y); 195} 196 197template <typename _Promise> 198class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { 199 using _Base = coroutine_handle<>; 200public: 201#ifndef _LIBCPP_CXX03_LANG 202 // 18.11.2.1 construct/reset 203 using coroutine_handle<>::coroutine_handle; 204#else 205 _LIBCPP_ALWAYS_INLINE coroutine_handle() _NOEXCEPT : _Base() {} 206 _LIBCPP_ALWAYS_INLINE 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 *reinterpret_cast<_Promise*>( 217 __builtin_coro_promise(this->__handle_, __alignof(_Promise), false)); 218 } 219 220public: 221 _LIBCPP_ALWAYS_INLINE 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_ALWAYS_INLINE 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_ALWAYS_INLINE 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 262struct _LIBCPP_TYPE_VIS suspend_never { 263 _LIBCPP_ALWAYS_INLINE 264 bool await_ready() const _NOEXCEPT { return true; } 265 _LIBCPP_ALWAYS_INLINE 266 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 267 _LIBCPP_ALWAYS_INLINE 268 void await_resume() const _NOEXCEPT {} 269}; 270 271struct _LIBCPP_TYPE_VIS suspend_always { 272 _LIBCPP_ALWAYS_INLINE 273 bool await_ready() const _NOEXCEPT { return false; } 274 _LIBCPP_ALWAYS_INLINE 275 void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 276 _LIBCPP_ALWAYS_INLINE 277 void await_resume() const _NOEXCEPT {} 278}; 279 280_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES 281 282_LIBCPP_BEGIN_NAMESPACE_STD 283 284template <class _Tp> 285struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { 286 using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; 287 _LIBCPP_INLINE_VISIBILITY 288 size_t operator()(__arg_type const& __v) const _NOEXCEPT 289 {return hash<void*>()(__v.address());} 290}; 291 292_LIBCPP_END_NAMESPACE_STD 293 294#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) 295 296#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ 297