13ca91850SEric Fiselier// -*- C++ -*- 2eb8650a7SLouis Dionne//===----------------------------------------------------------------------===// 33ca91850SEric Fiselier// 42946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 52946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information. 62946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 73ca91850SEric Fiselier// 83ca91850SEric Fiselier//===----------------------------------------------------------------------===// 93ca91850SEric Fiselier 103ca91850SEric Fiselier#ifndef _LIBCPP_EXPERIMENTAL_COROUTINE 113ca91850SEric Fiselier#define _LIBCPP_EXPERIMENTAL_COROUTINE 123ca91850SEric Fiselier 133ca91850SEric Fiselier/** 143ca91850SEric Fiselier experimental/coroutine synopsis 153ca91850SEric Fiselier 163ca91850SEric Fiselier// C++next 173ca91850SEric Fiselier 183ca91850SEric Fiseliernamespace std { 193ca91850SEric Fiseliernamespace experimental { 203ca91850SEric Fiselierinline namespace coroutines_v1 { 213ca91850SEric Fiselier 223ca91850SEric Fiselier // 18.11.1 coroutine traits 233ca91850SEric Fiseliertemplate <typename R, typename... ArgTypes> 243ca91850SEric Fiselierclass coroutine_traits; 253ca91850SEric Fiselier// 18.11.2 coroutine handle 263ca91850SEric Fiseliertemplate <typename Promise = void> 273ca91850SEric Fiselierclass coroutine_handle; 283ca91850SEric Fiselier// 18.11.2.7 comparison operators: 29997a3914SEric Fiselierbool operator==(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 30997a3914SEric Fiselierbool operator!=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 31997a3914SEric Fiselierbool operator<(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 32997a3914SEric Fiselierbool operator<=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 33997a3914SEric Fiselierbool operator>=(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 34997a3914SEric Fiselierbool operator>(coroutine_handle<> x, coroutine_handle<> y) _NOEXCEPT; 353ca91850SEric Fiselier// 18.11.3 trivial awaitables 363ca91850SEric Fiselierstruct suspend_never; 373ca91850SEric Fiselierstruct suspend_always; 383ca91850SEric Fiselier// 18.11.2.8 hash support: 393ca91850SEric Fiseliertemplate <class T> struct hash; 403ca91850SEric Fiseliertemplate <class P> struct hash<coroutine_handle<P>>; 413ca91850SEric Fiselier 423ca91850SEric Fiselier} // namespace coroutines_v1 433ca91850SEric Fiselier} // namespace experimental 443ca91850SEric Fiselier} // namespace std 453ca91850SEric Fiselier 463ca91850SEric Fiselier */ 473ca91850SEric Fiselier 48385cc25aSLouis Dionne#include <__assert> // all public C++ headers provide the assertion handler 49faef447eSNikolas Klauser#include <__functional/hash.h> 50*34f73804SNikolas Klauser#include <__functional/operations.h> 514d81a46fSArthur O'Dwyer#include <cstddef> 523ca91850SEric Fiselier#include <experimental/__config> 533ca91850SEric Fiselier#include <memory> // for hash<T*> 544d81a46fSArthur O'Dwyer#include <new> 554d81a46fSArthur O'Dwyer#include <type_traits> 563ca91850SEric Fiselier 573ca91850SEric Fiselier#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 583ca91850SEric Fiselier# pragma GCC system_header 593ca91850SEric Fiselier#endif 603ca91850SEric Fiselier 612e6ae1d3SChuanqi Xu#ifndef _LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES 62eb04c8caSEric Fiselier 633ca91850SEric Fiselier_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES 643ca91850SEric Fiselier 653ca91850SEric Fiseliertemplate <class _Tp, class = void> 663ca91850SEric Fiselierstruct __coroutine_traits_sfinae {}; 673ca91850SEric Fiselier 683ca91850SEric Fiseliertemplate <class _Tp> 693ca91850SEric Fiselierstruct __coroutine_traits_sfinae< 703ca91850SEric Fiselier _Tp, typename __void_t<typename _Tp::promise_type>::type> 713ca91850SEric Fiselier{ 723ca91850SEric Fiselier using promise_type = typename _Tp::promise_type; 733ca91850SEric Fiselier}; 743ca91850SEric Fiselier 753ca91850SEric Fiseliertemplate <typename _Ret, typename... _Args> 76c3d6a929SEric Fiselierstruct coroutine_traits 773ca91850SEric Fiselier : public __coroutine_traits_sfinae<_Ret> 783ca91850SEric Fiselier{ 793ca91850SEric Fiselier}; 803ca91850SEric Fiselier 81ea96891fSEric Fiseliertemplate <typename _Promise = void> 823ca91850SEric Fiselierclass _LIBCPP_TEMPLATE_VIS coroutine_handle; 833ca91850SEric Fiselier 843ca91850SEric Fiseliertemplate <> 853ca91850SEric Fiselierclass _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { 863ca91850SEric Fiselierpublic: 870f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 88997a3914SEric Fiselier _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} 893ca91850SEric Fiselier 900f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 91997a3914SEric Fiselier _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} 923ca91850SEric Fiselier 930f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 94997a3914SEric Fiselier coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 953ca91850SEric Fiselier __handle_ = nullptr; 963ca91850SEric Fiselier return *this; 973ca91850SEric Fiselier } 983ca91850SEric Fiselier 990f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 100997a3914SEric Fiselier _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } 1013ca91850SEric Fiselier 1020f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 103997a3914SEric Fiselier _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } 1043ca91850SEric Fiselier 1050f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 10651056aefSEric Fiselier void operator()() { resume(); } 1073ca91850SEric Fiselier 1080f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 10951056aefSEric Fiselier void resume() { 1103ca91850SEric Fiselier _LIBCPP_ASSERT(__is_suspended(), 1113ca91850SEric Fiselier "resume() can only be called on suspended coroutines"); 1123ca91850SEric Fiselier _LIBCPP_ASSERT(!done(), 1133ca91850SEric Fiselier "resume() has undefined behavior when the coroutine is done"); 1143ca91850SEric Fiselier __builtin_coro_resume(__handle_); 1153ca91850SEric Fiselier } 1163ca91850SEric Fiselier 1170f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 11851056aefSEric Fiselier void destroy() { 1193ca91850SEric Fiselier _LIBCPP_ASSERT(__is_suspended(), 1203ca91850SEric Fiselier "destroy() can only be called on suspended coroutines"); 1213ca91850SEric Fiselier __builtin_coro_destroy(__handle_); 1223ca91850SEric Fiselier } 1233ca91850SEric Fiselier 1240f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 1253ca91850SEric Fiselier bool done() const { 1263ca91850SEric Fiselier _LIBCPP_ASSERT(__is_suspended(), 1273ca91850SEric Fiselier "done() can only be called on suspended coroutines"); 1283ca91850SEric Fiselier return __builtin_coro_done(__handle_); 1293ca91850SEric Fiselier } 1303ca91850SEric Fiselier 1313ca91850SEric Fiselierpublic: 1320f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 133997a3914SEric Fiselier static coroutine_handle from_address(void* __addr) _NOEXCEPT { 1343ca91850SEric Fiselier coroutine_handle __tmp; 1353ca91850SEric Fiselier __tmp.__handle_ = __addr; 1363ca91850SEric Fiselier return __tmp; 1373ca91850SEric Fiselier } 1383ca91850SEric Fiselier 1393fd0228eSEric Fiselier // FIXME: Should from_address(nullptr) be allowed? 1400f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 1413fd0228eSEric Fiselier static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 1426e88ac2bSEric Fiselier return coroutine_handle(nullptr); 1433fd0228eSEric Fiselier } 1443fd0228eSEric Fiselier 1453fd0228eSEric Fiselier template <class _Tp, bool _CallIsValid = false> 1463fd0228eSEric Fiselier static coroutine_handle from_address(_Tp*) { 1473fd0228eSEric Fiselier static_assert(_CallIsValid, 1483fd0228eSEric Fiselier "coroutine_handle<void>::from_address cannot be called with " 1493fd0228eSEric Fiselier "non-void pointers"); 1503fd0228eSEric Fiselier } 1513fd0228eSEric Fiselier 1523ca91850SEric Fiselierprivate: 153997a3914SEric Fiselier bool __is_suspended() const _NOEXCEPT { 1543ca91850SEric Fiselier // FIXME actually implement a check for if the coro is suspended. 1553ca91850SEric Fiselier return __handle_; 1563ca91850SEric Fiselier } 1573ca91850SEric Fiselier 1583ca91850SEric Fiselier template <class _PromiseT> friend class coroutine_handle; 1593ca91850SEric Fiselier void* __handle_; 1603ca91850SEric Fiselier}; 1613ca91850SEric Fiselier 1623ca91850SEric Fiselier// 18.11.2.7 comparison operators: 1630f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 164997a3914SEric Fiselierbool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 1653ca91850SEric Fiselier return __x.address() == __y.address(); 1663ca91850SEric Fiselier} 1670f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 168997a3914SEric Fiselierbool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 1693ca91850SEric Fiselier return !(__x == __y); 1703ca91850SEric Fiselier} 1710f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 172997a3914SEric Fiselierbool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 1733ca91850SEric Fiselier return less<void*>()(__x.address(), __y.address()); 1743ca91850SEric Fiselier} 1750f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 176997a3914SEric Fiselierbool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 1773ca91850SEric Fiselier return __y < __x; 1783ca91850SEric Fiselier} 1790f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 180997a3914SEric Fiselierbool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 1813ca91850SEric Fiselier return !(__x > __y); 1823ca91850SEric Fiselier} 1830f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 184997a3914SEric Fiselierbool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { 1853ca91850SEric Fiselier return !(__x < __y); 1863ca91850SEric Fiselier} 1873ca91850SEric Fiselier 1883ca91850SEric Fiseliertemplate <typename _Promise> 1893ca91850SEric Fiselierclass _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { 1903ca91850SEric Fiselier using _Base = coroutine_handle<>; 1913ca91850SEric Fiselierpublic: 192997a3914SEric Fiselier#ifndef _LIBCPP_CXX03_LANG 1933ca91850SEric Fiselier // 18.11.2.1 construct/reset 1943ca91850SEric Fiselier using coroutine_handle<>::coroutine_handle; 195997a3914SEric Fiselier#else 1960f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {} 1970f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} 198997a3914SEric Fiselier#endif 1993ca91850SEric Fiselier _LIBCPP_INLINE_VISIBILITY 200997a3914SEric Fiselier coroutine_handle& operator=(nullptr_t) _NOEXCEPT { 2013ca91850SEric Fiselier _Base::operator=(nullptr); 2023ca91850SEric Fiselier return *this; 2033ca91850SEric Fiselier } 2043ca91850SEric Fiselier 2053ca91850SEric Fiselier _LIBCPP_INLINE_VISIBILITY 2062944c5a3SEric Fiselier _Promise& promise() const { 2070f87a807SGor Nishanov return *static_cast<_Promise*>( 208d108bf85SEric Fiselier __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 2093ca91850SEric Fiselier } 2103ca91850SEric Fiselier 2113ca91850SEric Fiselierpublic: 2120f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 213997a3914SEric Fiselier static coroutine_handle from_address(void* __addr) _NOEXCEPT { 2143ca91850SEric Fiselier coroutine_handle __tmp; 2153ca91850SEric Fiselier __tmp.__handle_ = __addr; 2163ca91850SEric Fiselier return __tmp; 2173ca91850SEric Fiselier } 2183ca91850SEric Fiselier 219bae0a1d4SEric Fiselier // NOTE: this overload isn't required by the standard but is needed so 220bae0a1d4SEric Fiselier // the deleted _Promise* overload doesn't make from_address(nullptr) 221bae0a1d4SEric Fiselier // ambiguous. 222bae0a1d4SEric Fiselier // FIXME: should from_address work with nullptr? 2230f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 224bae0a1d4SEric Fiselier static coroutine_handle from_address(nullptr_t) _NOEXCEPT { 2256e88ac2bSEric Fiselier return coroutine_handle(nullptr); 226bae0a1d4SEric Fiselier } 227bae0a1d4SEric Fiselier 2283fd0228eSEric Fiselier template <class _Tp, bool _CallIsValid = false> 2293fd0228eSEric Fiselier static coroutine_handle from_address(_Tp*) { 2303fd0228eSEric Fiselier static_assert(_CallIsValid, 2313fd0228eSEric Fiselier "coroutine_handle<promise_type>::from_address cannot be called with " 2323fd0228eSEric Fiselier "non-void pointers"); 2333fd0228eSEric Fiselier } 2343fd0228eSEric Fiselier 2353fd0228eSEric Fiselier template <bool _CallIsValid = false> 2363fd0228eSEric Fiselier static coroutine_handle from_address(_Promise*) { 2373fd0228eSEric Fiselier static_assert(_CallIsValid, 2383fd0228eSEric Fiselier "coroutine_handle<promise_type>::from_address cannot be used with " 2393fd0228eSEric Fiselier "pointers to the coroutine's promise type; use 'from_promise' instead"); 2403fd0228eSEric Fiselier } 241207d13cfSEric Fiselier 2420f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 243997a3914SEric Fiselier static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { 244f9bc0589SEric Fiselier typedef typename remove_cv<_Promise>::type _RawPromise; 2453ca91850SEric Fiselier coroutine_handle __tmp; 246f9bc0589SEric Fiselier __tmp.__handle_ = __builtin_coro_promise( 247f9bc0589SEric Fiselier _VSTD::addressof(const_cast<_RawPromise&>(__promise)), 248d108bf85SEric Fiselier _LIBCPP_ALIGNOF(_Promise), true); 2493ca91850SEric Fiselier return __tmp; 2503ca91850SEric Fiselier } 2513ca91850SEric Fiselier}; 2523ca91850SEric Fiselier 2530f87a807SGor Nishanov#if __has_builtin(__builtin_coro_noop) 2540f87a807SGor Nishanovstruct noop_coroutine_promise {}; 2550f87a807SGor Nishanov 2560f87a807SGor Nishanovtemplate <> 2570f87a807SGor Nishanovclass _LIBCPP_TEMPLATE_VIS coroutine_handle<noop_coroutine_promise> 2580f87a807SGor Nishanov : public coroutine_handle<> { 2590f87a807SGor Nishanov using _Base = coroutine_handle<>; 2600f87a807SGor Nishanov using _Promise = noop_coroutine_promise; 2610f87a807SGor Nishanovpublic: 2620f87a807SGor Nishanov 2630f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 2640f87a807SGor Nishanov _Promise& promise() const { 2650f87a807SGor Nishanov return *static_cast<_Promise*>( 266d108bf85SEric Fiselier __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); 2670f87a807SGor Nishanov } 2680f87a807SGor Nishanov 2690f87a807SGor Nishanov _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } 2700f87a807SGor Nishanov _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } 2710f87a807SGor Nishanov 2728f310655SGor Nishanov _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {} 2738f310655SGor Nishanov _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {} 2748f310655SGor Nishanov _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {} 2750f87a807SGor Nishanov 2760f87a807SGor Nishanovprivate: 277cf3ae384SLouis Dionne _LIBCPP_INLINE_VISIBILITY 2780f87a807SGor Nishanov friend coroutine_handle<noop_coroutine_promise> noop_coroutine() _NOEXCEPT; 2790f87a807SGor Nishanov 2800f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT { 2810f87a807SGor Nishanov this->__handle_ = __builtin_coro_noop(); 2820f87a807SGor Nishanov } 2830f87a807SGor Nishanov}; 2840f87a807SGor Nishanov 2850f87a807SGor Nishanovusing noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; 2860f87a807SGor Nishanov 2870f87a807SGor Nishanovinline _LIBCPP_INLINE_VISIBILITY 2880f87a807SGor Nishanovnoop_coroutine_handle noop_coroutine() _NOEXCEPT { 289b1e985dbSGor Nishanov return noop_coroutine_handle(); 2900f87a807SGor Nishanov} 2910f87a807SGor Nishanov#endif // __has_builtin(__builtin_coro_noop) 2920f87a807SGor Nishanov 293c3d6a929SEric Fiselierstruct suspend_never { 2940f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 295997a3914SEric Fiselier bool await_ready() const _NOEXCEPT { return true; } 2960f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 297997a3914SEric Fiselier void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 2980f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 299997a3914SEric Fiselier void await_resume() const _NOEXCEPT {} 3003ca91850SEric Fiselier}; 3013ca91850SEric Fiselier 302c3d6a929SEric Fiselierstruct suspend_always { 3030f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 304997a3914SEric Fiselier bool await_ready() const _NOEXCEPT { return false; } 3050f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 306997a3914SEric Fiselier void await_suspend(coroutine_handle<>) const _NOEXCEPT {} 3070f87a807SGor Nishanov _LIBCPP_INLINE_VISIBILITY 308997a3914SEric Fiselier void await_resume() const _NOEXCEPT {} 3093ca91850SEric Fiselier}; 3103ca91850SEric Fiselier 3113ca91850SEric Fiselier_LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES 3123ca91850SEric Fiselier 3133ca91850SEric Fiselier_LIBCPP_BEGIN_NAMESPACE_STD 3143ca91850SEric Fiselier 3153ca91850SEric Fiseliertemplate <class _Tp> 3163ca91850SEric Fiselierstruct hash<_VSTD_CORO::coroutine_handle<_Tp> > { 3173ca91850SEric Fiselier using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; 3183ca91850SEric Fiselier _LIBCPP_INLINE_VISIBILITY 319997a3914SEric Fiselier size_t operator()(__arg_type const& __v) const _NOEXCEPT 320997a3914SEric Fiselier {return hash<void*>()(__v.address());} 3213ca91850SEric Fiselier}; 3223ca91850SEric Fiselier 3233ca91850SEric Fiselier_LIBCPP_END_NAMESPACE_STD 3243ca91850SEric Fiselier 3252e6ae1d3SChuanqi Xu#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) 326eb04c8caSEric Fiselier 3273ca91850SEric Fiselier#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ 328