1302affcbSDimitry Andric// -*- C++ -*- 2302affcbSDimitry Andric//===----------------------------- coroutine -----------------------------===// 3302affcbSDimitry Andric// 4302affcbSDimitry Andric// The LLVM Compiler Infrastructure 5302affcbSDimitry Andric// 6302affcbSDimitry Andric// This file is distributed under the University of Illinois Open Source 7302affcbSDimitry Andric// License. See LICENSE.TXT for details. 8302affcbSDimitry Andric// 9302affcbSDimitry Andric//===----------------------------------------------------------------------===// 10302affcbSDimitry Andric 11302affcbSDimitry Andric#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE 12302affcbSDimitry Andric#define _LIBCPP_EXPERIMENTAL_COROUTINE 13302affcbSDimitry Andric 14302affcbSDimitry Andric/** 15302affcbSDimitry Andric experimental/coroutine synopsis 16302affcbSDimitry Andric 17302affcbSDimitry Andric// C++next 18302affcbSDimitry Andric 19302affcbSDimitry Andricnamespace std { 20302affcbSDimitry Andricnamespace experimental { 21302affcbSDimitry Andricinline namespace coroutines_v1 { 22302affcbSDimitry Andric 23302affcbSDimitry Andric // 18.11.1 coroutine traits 24302affcbSDimitry Andrictemplate <typename R, typename... ArgTypes> 25302affcbSDimitry Andricclass coroutine_traits; 26302affcbSDimitry Andric// 18.11.2 coroutine handle 27302affcbSDimitry Andrictemplate <typename Promise = void> 28302affcbSDimitry Andricclass coroutine_handle; 29302affcbSDimitry Andric// 18.11.2.7 comparison operators: 30302affcbSDimitry Andricbool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 31302affcbSDimitry Andricbool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 32302affcbSDimitry Andricbool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 33302affcbSDimitry Andricbool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 34302affcbSDimitry Andricbool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 35302affcbSDimitry Andricbool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 36302affcbSDimitry Andric// 18.11.3 trivial awaitables 37302affcbSDimitry Andricstruct suspend_never; 38302affcbSDimitry Andricstruct suspend_always; 39302affcbSDimitry Andric// 18.11.2.8 hash support: 40302affcbSDimitry Andrictemplate <class T> struct hash; 41302affcbSDimitry Andrictemplate <class P> struct hash<coroutine_handle<P>>; 42302affcbSDimitry Andric 43302affcbSDimitry Andric} // namespace coroutines_v1 44302affcbSDimitry Andric} // namespace experimental 45302affcbSDimitry Andric} // namespace std 46302affcbSDimitry Andric 47302affcbSDimitry Andric */ 48302affcbSDimitry Andric 49302affcbSDimitry Andric#include <experimental/__config> 50302affcbSDimitry Andric#include <new> 51302affcbSDimitry Andric#include <type_traits> 52302affcbSDimitry Andric#include <functional> 53302affcbSDimitry Andric#include <memory> // for hash<T*> 54302affcbSDimitry Andric#include <cstddef> 55302affcbSDimitry Andric#include <cassert> 56302affcbSDimitry Andric#include <__debug> 57302affcbSDimitry Andric 58302affcbSDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 59302affcbSDimitry Andric#pragma GCC system_header 60302affcbSDimitry Andric#endif 61302affcbSDimitry Andric 62302affcbSDimitry Andric#ifdef _LIBCPP_HAS_NO_COROUTINES 63302affcbSDimitry Andric# if defined(_LIBCPP_WARNING) 64302affcbSDimitry Andric _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler") 65302affcbSDimitry Andric# else 66302affcbSDimitry Andric# warning <experimental/coroutine> cannot be used with this compiler 67302affcbSDimitry Andric# endif 68302affcbSDimitry Andric#endif 69302affcbSDimitry Andric 70302affcbSDimitry Andric#ifndef _LIBCPP_HAS_NO_COROUTINES 71302affcbSDimitry Andric 72302affcbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES 73302affcbSDimitry Andric 74302affcbSDimitry Andrictemplate <class _Tp, class = void> 75302affcbSDimitry Andricstruct __coroutine_traits_sfinae {}; 76302affcbSDimitry Andric 77302affcbSDimitry Andrictemplate <class _Tp> 78302affcbSDimitry Andricstruct __coroutine_traits_sfinae< 79302affcbSDimitry Andric _Tp, typename __void_t<typename _Tp::promise_type>::type> 80302affcbSDimitry Andric{ 81302affcbSDimitry Andric using promise_type = typename _Tp::promise_type; 82302affcbSDimitry Andric}; 83302affcbSDimitry Andric 84302affcbSDimitry Andrictemplate <typename _Ret, typename... _Args> 85302affcbSDimitry Andricstruct _LIBCPP_TEMPLATE_VIS coroutine_traits 86302affcbSDimitry Andric : public __coroutine_traits_sfinae<_Ret> 87302affcbSDimitry Andric{ 88302affcbSDimitry Andric}; 89302affcbSDimitry Andric 90302affcbSDimitry Andrictemplate <typename _Promise = void> 91302affcbSDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle; 92302affcbSDimitry Andric 93302affcbSDimitry Andrictemplate <> 94302affcbSDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { 95302affcbSDimitry Andricpublic: 964ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 97302affcbSDimitry Andric _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} 98302affcbSDimitry Andric 994ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 100302affcbSDimitry Andric _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} 101302affcbSDimitry Andric 1024ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 103302affcbSDimitry Andric coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 104302affcbSDimitry Andric __handle_ = nullptr; 105302affcbSDimitry Andric return *this; 106302affcbSDimitry Andric } 107302affcbSDimitry Andric 1084ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 109302affcbSDimitry Andric _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } 110302affcbSDimitry Andric 1114ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 112302affcbSDimitry Andric _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } 113302affcbSDimitry Andric 1144ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 115302affcbSDimitry Andric void operator()() { resume(); } 116302affcbSDimitry Andric 1174ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 118302affcbSDimitry Andric void resume() { 119302affcbSDimitry Andric _LIBCPP_ASSERT(__is_suspended(), 120302affcbSDimitry Andric "resume() can only be called on suspended coroutines"); 121302affcbSDimitry Andric _LIBCPP_ASSERT(!done(), 122302affcbSDimitry Andric "resume() has undefined behavior when the coroutine is done"); 123302affcbSDimitry Andric __builtin_coro_resume(__handle_); 124302affcbSDimitry Andric } 125302affcbSDimitry Andric 1264ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 127302affcbSDimitry Andric void destroy() { 128302affcbSDimitry Andric _LIBCPP_ASSERT(__is_suspended(), 129302affcbSDimitry Andric "destroy() can only be called on suspended coroutines"); 130302affcbSDimitry Andric __builtin_coro_destroy(__handle_); 131302affcbSDimitry Andric } 132302affcbSDimitry Andric 1334ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 134302affcbSDimitry Andric bool done() const { 135302affcbSDimitry Andric _LIBCPP_ASSERT(__is_suspended(), 136302affcbSDimitry Andric "done() can only be called on suspended coroutines"); 137302affcbSDimitry Andric return __builtin_coro_done(__handle_); 138302affcbSDimitry Andric } 139302affcbSDimitry Andric 140302affcbSDimitry Andricpublic: 1414ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 142302affcbSDimitry Andric static coroutine_handle from_address(void* __addr) _NOEXCEPT { 143302affcbSDimitry Andric coroutine_handle __tmp; 144302affcbSDimitry Andric __tmp.__handle_ = __addr; 145302affcbSDimitry Andric return __tmp; 146302affcbSDimitry Andric } 147302affcbSDimitry Andric 14889cb50c9SDimitry Andric // FIXME: Should from_address(nullptr) be allowed? 1494ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 15089cb50c9SDimitry Andric static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 15189cb50c9SDimitry Andric return coroutine_handle(nullptr); 15289cb50c9SDimitry Andric } 15389cb50c9SDimitry Andric 15489cb50c9SDimitry Andric template <class _Tp, bool _CallIsValid = false> 15589cb50c9SDimitry Andric static coroutine_handle from_address(_Tp*) { 15689cb50c9SDimitry Andric static_assert(_CallIsValid, 15789cb50c9SDimitry Andric "coroutine_handle<void>::from_address cannot be called with " 15889cb50c9SDimitry Andric "non-void pointers"); 15989cb50c9SDimitry Andric } 16089cb50c9SDimitry Andric 161302affcbSDimitry Andricprivate: 162302affcbSDimitry Andric bool __is_suspended() const _NOEXCEPT { 163302affcbSDimitry Andric // FIXME actually implement a check for if the coro is suspended. 164302affcbSDimitry Andric return __handle_; 165302affcbSDimitry Andric } 166302affcbSDimitry Andric 167302affcbSDimitry Andric template <class _PromiseT> friend class coroutine_handle; 168302affcbSDimitry Andric void* __handle_; 169302affcbSDimitry Andric}; 170302affcbSDimitry Andric 171302affcbSDimitry Andric// 18.11.2.7 comparison operators: 1724ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 173302affcbSDimitry Andricbool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 174302affcbSDimitry Andric return __x.address() == __y.address(); 175302affcbSDimitry Andric} 1764ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 177302affcbSDimitry Andricbool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 178302affcbSDimitry Andric return !(__x == __y); 179302affcbSDimitry Andric} 1804ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 181302affcbSDimitry Andricbool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 182302affcbSDimitry Andric return less<void*>()(__x.address(), __y.address()); 183302affcbSDimitry Andric} 1844ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 185302affcbSDimitry Andricbool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 186302affcbSDimitry Andric return __y < __x; 187302affcbSDimitry Andric} 1884ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 189302affcbSDimitry Andricbool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 190302affcbSDimitry Andric return !(__x > __y); 191302affcbSDimitry Andric} 1924ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 193302affcbSDimitry Andricbool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 194302affcbSDimitry Andric return !(__x < __y); 195302affcbSDimitry Andric} 196302affcbSDimitry Andric 197302affcbSDimitry Andrictemplate <typename _Promise> 198302affcbSDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { 199302affcbSDimitry Andric using _Base = coroutine_handle<>; 200302affcbSDimitry Andricpublic: 201302affcbSDimitry Andric#ifndef _LIBCPP_CXX03_LANG 202302affcbSDimitry Andric // 18.11.2.1 construct/reset 203302affcbSDimitry Andric using coroutine_handle<>::coroutine_handle; 204302affcbSDimitry Andric#else 2054ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {} 2064ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} 207302affcbSDimitry Andric#endif 208302affcbSDimitry Andric _LIBCPP_INLINE_VISIBILITY 209302affcbSDimitry Andric coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 210302affcbSDimitry Andric _Base::operator=(nullptr); 211302affcbSDimitry Andric return *this; 212302affcbSDimitry Andric } 213302affcbSDimitry Andric 214302affcbSDimitry Andric _LIBCPP_INLINE_VISIBILITY 215302affcbSDimitry Andric _Promise& promise() const { 2164ba319b5SDimitry Andric return *static_cast<_Promise*>( 217*b5893f02SDimitry Andric __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 218302affcbSDimitry Andric } 219302affcbSDimitry Andric 220302affcbSDimitry Andricpublic: 2214ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 222302affcbSDimitry Andric static coroutine_handle from_address(void* __addr) _NOEXCEPT { 223302affcbSDimitry Andric coroutine_handle __tmp; 224302affcbSDimitry Andric __tmp.__handle_ = __addr; 225302affcbSDimitry Andric return __tmp; 226302affcbSDimitry Andric } 227302affcbSDimitry Andric 228302affcbSDimitry Andric // NOTE: this overload isn't required by the standard but is needed so 229302affcbSDimitry Andric // the deleted _Promise* overload doesn't make from_address(nullptr) 230302affcbSDimitry Andric // ambiguous. 231302affcbSDimitry Andric // FIXME: should from_address work with nullptr? 2324ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 233302affcbSDimitry Andric static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 23489cb50c9SDimitry Andric return coroutine_handle(nullptr); 235302affcbSDimitry Andric } 236302affcbSDimitry Andric 23789cb50c9SDimitry Andric template <class _Tp, bool _CallIsValid = false> 23889cb50c9SDimitry Andric static coroutine_handle from_address(_Tp*) { 23989cb50c9SDimitry Andric static_assert(_CallIsValid, 24089cb50c9SDimitry Andric "coroutine_handle<promise_type>::from_address cannot be called with " 24189cb50c9SDimitry Andric "non-void pointers"); 24289cb50c9SDimitry Andric } 24389cb50c9SDimitry Andric 24489cb50c9SDimitry Andric template <bool _CallIsValid = false> 24589cb50c9SDimitry Andric static coroutine_handle from_address(_Promise*) { 24689cb50c9SDimitry Andric static_assert(_CallIsValid, 24789cb50c9SDimitry Andric "coroutine_handle<promise_type>::from_address cannot be used with " 24889cb50c9SDimitry Andric "pointers to the coroutine's promise type; use 'from_promise' instead"); 24989cb50c9SDimitry Andric } 250302affcbSDimitry Andric 2514ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 252302affcbSDimitry Andric static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { 25324d58133SDimitry Andric typedef typename remove_cv<_Promise>::type _RawPromise; 254302affcbSDimitry Andric coroutine_handle __tmp; 25524d58133SDimitry Andric __tmp.__handle_ = __builtin_coro_promise( 25624d58133SDimitry Andric _VSTD::addressof(const_cast<_RawPromise&>(__promise)), 257*b5893f02SDimitry Andric _LIBCPP_ALIGNOF(_Promise), true); 258302affcbSDimitry Andric return __tmp; 259302affcbSDimitry Andric } 260302affcbSDimitry Andric}; 261302affcbSDimitry Andric 2624ba319b5SDimitry Andric#if __has_builtin(__builtin_coro_noop) 2634ba319b5SDimitry Andricstruct noop_coroutine_promise {}; 2644ba319b5SDimitry Andric 2654ba319b5SDimitry Andrictemplate <> 2664ba319b5SDimitry Andricclass _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise> 2674ba319b5SDimitry Andric : public coroutine_handle<> { 2684ba319b5SDimitry Andric using _Base = coroutine_handle<>; 2694ba319b5SDimitry Andric using _Promise = noop_coroutine_promise; 2704ba319b5SDimitry Andricpublic: 2714ba319b5SDimitry Andric 2724ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 2734ba319b5SDimitry Andric _Promise& promise() const { 2744ba319b5SDimitry Andric return *static_cast<_Promise*>( 275*b5893f02SDimitry Andric __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 2764ba319b5SDimitry Andric } 2774ba319b5SDimitry Andric 2784ba319b5SDimitry Andric _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } 2794ba319b5SDimitry Andric _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } 2804ba319b5SDimitry Andric 2814ba319b5SDimitry Andric _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {} 2824ba319b5SDimitry Andric _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {} 2834ba319b5SDimitry Andric _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {} 2844ba319b5SDimitry Andric 2854ba319b5SDimitry Andricprivate: 2864ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 2874ba319b5SDimitry Andric friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT; 2884ba319b5SDimitry Andric 2894ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT { 2904ba319b5SDimitry Andric this->__handle_ = __builtin_coro_noop(); 2914ba319b5SDimitry Andric } 2924ba319b5SDimitry Andric}; 2934ba319b5SDimitry Andric 2944ba319b5SDimitry Andricusing noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; 2954ba319b5SDimitry Andric 2964ba319b5SDimitry Andricinline _LIBCPP_INLINE_VISIBILITY 2974ba319b5SDimitry Andricnoop_coroutine_handle noop_coroutine() _NOEXCEPT { 2984ba319b5SDimitry Andric return noop_coroutine_handle(); 2994ba319b5SDimitry Andric} 3004ba319b5SDimitry Andric#endif // __has_builtin(__builtin_coro_noop) 3014ba319b5SDimitry Andric 302302affcbSDimitry Andricstruct _LIBCPP_TYPE_VIS suspend_never { 3034ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 304302affcbSDimitry Andric bool await_ready() const _NOEXCEPT { return true; } 3054ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 306302affcbSDimitry Andric void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 3074ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 308302affcbSDimitry Andric void await_resume() const _NOEXCEPT {} 309302affcbSDimitry Andric}; 310302affcbSDimitry Andric 311302affcbSDimitry Andricstruct _LIBCPP_TYPE_VIS suspend_always { 3124ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 313302affcbSDimitry Andric bool await_ready() const _NOEXCEPT { return false; } 3144ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 315302affcbSDimitry Andric void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 3164ba319b5SDimitry Andric _LIBCPP_INLINE_VISIBILITY 317302affcbSDimitry Andric void await_resume() const _NOEXCEPT {} 318302affcbSDimitry Andric}; 319302affcbSDimitry Andric 320302affcbSDimitry Andric_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES 321302affcbSDimitry Andric 322302affcbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD 323302affcbSDimitry Andric 324302affcbSDimitry Andrictemplate <class _Tp> 325302affcbSDimitry Andricstruct hash<_VSTD_CORO::coroutine_handle<_Tp> > { 326302affcbSDimitry Andric using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; 327302affcbSDimitry Andric _LIBCPP_INLINE_VISIBILITY 328302affcbSDimitry Andric size_t operator()(__arg_type const& __v) const _NOEXCEPT 329302affcbSDimitry Andric {return hash<void*>()(__v.address());} 330302affcbSDimitry Andric}; 331302affcbSDimitry Andric 332302affcbSDimitry Andric_LIBCPP_END_NAMESPACE_STD 333302affcbSDimitry Andric 334302affcbSDimitry Andric#endif // !defined(_LIBCPP_HAS_NO_COROUTINES) 335302affcbSDimitry Andric 336302affcbSDimitry Andric#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ 337