// -*- C++ -*- //===----------------------------- coroutine -----------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef _LIBCPP_EXPERIMENTAL_COROUTINE #define _LIBCPP_EXPERIMENTAL_COROUTINE /** experimental/coroutine synopsis // C++next namespace std { namespace experimental { inline namespace coroutines_v1 { // 18.11.1 coroutine traits template class coroutine_traits; // 18.11.2 coroutine handle template class coroutine_handle; // 18.11.2.7 comparison operators: bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept; bool operator!=(coroutine_handle<> x, coroutine_handle<> y) noexcept; bool operator<(coroutine_handle<> x, coroutine_handle<> y) noexcept; bool operator<=(coroutine_handle<> x, coroutine_handle<> y) noexcept; bool operator>=(coroutine_handle<> x, coroutine_handle<> y) noexcept; bool operator>(coroutine_handle<> x, coroutine_handle<> y) noexcept; // 18.11.3 trivial awaitables struct suspend_never; struct suspend_always; // 18.11.2.8 hash support: template struct hash; template struct hash>; } // namespace coroutines_v1 } // namespace experimental } // namespace std */ #include #include #include #include #include // for hash #include #include #include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif #ifdef _LIBCPP_HAS_NO_COROUTINES # if defined(_LIBCPP_WARNING) _LIBCPP_WARNING(" cannot be used with this compiler") # else # warning cannot be used with this compiler # endif #endif #ifndef _LIBCPP_HAS_NO_COROUTINES _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES template struct __coroutine_traits_sfinae {}; template struct __coroutine_traits_sfinae< _Tp, typename __void_t::type> { using promise_type = typename _Tp::promise_type; }; template struct _LIBCPP_TEMPLATE_VIS coroutine_traits : public __coroutine_traits_sfinae<_Ret> { }; template class _LIBCPP_TEMPLATE_VIS coroutine_handle; template <> class _LIBCPP_TEMPLATE_VIS coroutine_handle { public: _LIBCPP_ALWAYS_INLINE constexpr coroutine_handle() noexcept : __handle_(nullptr) {} _LIBCPP_ALWAYS_INLINE constexpr coroutine_handle(nullptr_t) noexcept : __handle_(nullptr) {} _LIBCPP_ALWAYS_INLINE coroutine_handle& operator=(nullptr_t) noexcept { __handle_ = nullptr; return *this; } _LIBCPP_ALWAYS_INLINE constexpr void* address() const noexcept { return __handle_; } _LIBCPP_ALWAYS_INLINE constexpr explicit operator bool() const noexcept { return __handle_; } _LIBCPP_ALWAYS_INLINE void operator()() { resume(); } _LIBCPP_ALWAYS_INLINE void resume() { _LIBCPP_ASSERT(__is_suspended(), "resume() can only be called on suspended coroutines"); _LIBCPP_ASSERT(!done(), "resume() has undefined behavior when the coroutine is done"); __builtin_coro_resume(__handle_); } _LIBCPP_ALWAYS_INLINE void destroy() { _LIBCPP_ASSERT(__is_suspended(), "destroy() can only be called on suspended coroutines"); __builtin_coro_destroy(__handle_); } _LIBCPP_ALWAYS_INLINE bool done() const { _LIBCPP_ASSERT(__is_suspended(), "done() can only be called on suspended coroutines"); return __builtin_coro_done(__handle_); } public: _LIBCPP_ALWAYS_INLINE static coroutine_handle from_address(void* __addr) noexcept { coroutine_handle __tmp; __tmp.__handle_ = __addr; return __tmp; } private: bool __is_suspended() const noexcept { // FIXME actually implement a check for if the coro is suspended. return __handle_; } template friend class coroutine_handle; void* __handle_; }; // 18.11.2.7 comparison operators: inline _LIBCPP_ALWAYS_INLINE bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return __x.address() == __y.address(); } inline _LIBCPP_ALWAYS_INLINE bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return !(__x == __y); } inline _LIBCPP_ALWAYS_INLINE bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return less()(__x.address(), __y.address()); } inline _LIBCPP_ALWAYS_INLINE bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return __y < __x; } inline _LIBCPP_ALWAYS_INLINE bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return !(__x > __y); } inline _LIBCPP_ALWAYS_INLINE bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { return !(__x < __y); } template class _LIBCPP_TEMPLATE_VIS coroutine_handle : public coroutine_handle<> { using _Base = coroutine_handle<>; public: // 18.11.2.1 construct/reset using coroutine_handle<>::coroutine_handle; _LIBCPP_INLINE_VISIBILITY coroutine_handle& operator=(nullptr_t) noexcept { _Base::operator=(nullptr); return *this; } _LIBCPP_INLINE_VISIBILITY _Promise& promise() const { return *reinterpret_cast<_Promise*>( __builtin_coro_promise(this->__handle_, alignof(_Promise), false)); } public: _LIBCPP_ALWAYS_INLINE static coroutine_handle from_address(void* __addr) noexcept { coroutine_handle __tmp; __tmp.__handle_ = __addr; return __tmp; } _LIBCPP_ALWAYS_INLINE static coroutine_handle from_promise(_Promise& __promise) noexcept { coroutine_handle __tmp; __tmp.__handle_ = __builtin_coro_promise(_VSTD::addressof(__promise), alignof(_Promise), true); return __tmp; } }; struct _LIBCPP_TYPE_VIS suspend_never { _LIBCPP_ALWAYS_INLINE bool await_ready() const noexcept { return true; } _LIBCPP_ALWAYS_INLINE void await_suspend(coroutine_handle<>) const noexcept {} _LIBCPP_ALWAYS_INLINE void await_resume() const noexcept {} }; struct _LIBCPP_TYPE_VIS suspend_always { _LIBCPP_ALWAYS_INLINE bool await_ready() const noexcept { return false; } _LIBCPP_ALWAYS_INLINE void await_suspend(coroutine_handle<>) const noexcept {} _LIBCPP_ALWAYS_INLINE void await_resume() const noexcept {} }; _LIBCPP_END_NAMESPACE_EXPERIMENTAL_COROUTINES _LIBCPP_BEGIN_NAMESPACE_STD template struct hash<_VSTD_CORO::coroutine_handle<_Tp> > { using __arg_type = _VSTD_CORO::coroutine_handle<_Tp>; _LIBCPP_INLINE_VISIBILITY size_t operator()(__arg_type const& __v) const noexcept {return hash{}(__v.address());} }; _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_COROUTINES) #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */