From 3c659b956accc288f9332049d5313d0406dc48c4 Mon Sep 17 00:00:00 2001 From: barracuda156 Date: Tue, 14 Nov 2023 21:46:08 +0800 Subject: [PATCH] Add coroutine header From: https://github.com/iains/llvm-project/commit/0ec37d1e98f07379443c420569f282b12482595f --- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__config | 5 +- libcxx/include/coroutine | 409 ++++++++++++++++++++++++++ libcxx/include/experimental/coroutine | 7 + 4 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 libcxx/include/coroutine diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index d9def18d725..dc3cf73770a 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -44,6 +44,7 @@ set(files complex complex.h condition_variable + coroutine csetjmp csignal cstdarg diff --git a/libcxx/include/__config b/libcxx/include/__config index 738d891e303..1bd724722c5 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1244,7 +1244,10 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container( #define _LIBCPP_HAS_NO_IS_AGGREGATE #endif -#if !defined(__cpp_coroutines) || __cpp_coroutines < 201703L +#if defined(__clang__) && (!defined(__cpp_coroutine) || \ + __cpp_coroutine < 201703L) +#define _LIBCPP_HAS_NO_COROUTINES +#elif !defined(__cpp_impl_coroutine) || __cpp_impl_coroutine < 201703L #define _LIBCPP_HAS_NO_COROUTINES #endif diff --git a/libcxx/include/coroutine b/libcxx/include/coroutine new file mode 100644 index 00000000000..0b3eac1f021 --- /dev/null +++ b/libcxx/include/coroutine @@ -0,0 +1,409 @@ +// -*- C++ -*- +//===----------------------------- coroutine -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_COROUTINE +#define _LIBCPP_COROUTINE + +/** + experimental/coroutine synopsis + +// C++next + +namespace std { +inline namespace __coro20 { + + // 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 __coro20 +} // namespace std + + */ + +#include <__config> + +#if defined(_LIBCPP_COMPILER_GCC) + +#include +#include +#include +#include // for hash +#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_STD +inline namespace __coro20 { + +template +struct __coroutine_traits_sfinae {}; + +template +struct __coroutine_traits_sfinae< + _Tp, typename __void_t::type> +{ + using promise_type = typename _Tp::promise_type; +}; + +template +struct coroutine_traits + : public __coroutine_traits_sfinae<_Ret> +{ +}; + +template +class _LIBCPP_TEMPLATE_VIS coroutine_handle; + +template <> +class _LIBCPP_TEMPLATE_VIS coroutine_handle { +public: + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR coroutine_handle() _NOEXCEPT : __handle_(nullptr) {} + + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR coroutine_handle(nullptr_t) _NOEXCEPT : __handle_(nullptr) {} + + _LIBCPP_INLINE_VISIBILITY + coroutine_handle& operator=(nullptr_t) _NOEXCEPT { + __handle_ = nullptr; + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR void* address() const _NOEXCEPT { return __handle_; } + + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return __handle_; } + + _LIBCPP_INLINE_VISIBILITY + void operator()() { resume(); } + + _LIBCPP_INLINE_VISIBILITY + 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_INLINE_VISIBILITY + void destroy() { + _LIBCPP_ASSERT(__is_suspended(), + "destroy() can only be called on suspended coroutines"); + __builtin_coro_destroy(__handle_); + } + + _LIBCPP_INLINE_VISIBILITY + bool done() const { + _LIBCPP_ASSERT(__is_suspended(), + "done() can only be called on suspended coroutines"); + return __builtin_coro_done(__handle_); + } + +public: + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR + static coroutine_handle from_address(void* __addr) _NOEXCEPT { + coroutine_handle __tmp; + __tmp.__handle_ = __addr; + return __tmp; + } + + // FIXME: Should from_address(nullptr) be allowed? + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR + static coroutine_handle from_address(nullptr_t) _NOEXCEPT { + return coroutine_handle(nullptr); + } + + template + static coroutine_handle from_address(_Tp*) { + static_assert(_CallIsValid, + "coroutine_handle::from_address cannot be called with " + "non-void pointers"); + } + +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_INLINE_VISIBILITY +bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { + return __x.address() == __y.address(); +} +inline _LIBCPP_INLINE_VISIBILITY +bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { + return !(__x == __y); +} +inline _LIBCPP_INLINE_VISIBILITY +bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { + return less()(__x.address(), __y.address()); +} +inline _LIBCPP_INLINE_VISIBILITY +bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { + return __y < __x; +} +inline _LIBCPP_INLINE_VISIBILITY +bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) _NOEXCEPT { + return !(__x > __y); +} +inline _LIBCPP_INLINE_VISIBILITY +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: +#ifndef _LIBCPP_CXX03_LANG + // 18.11.2.1 construct/reset + using coroutine_handle<>::coroutine_handle; +#else + _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT : _Base() {} + _LIBCPP_INLINE_VISIBILITY coroutine_handle(nullptr_t) _NOEXCEPT : _Base(nullptr) {} +#endif + _LIBCPP_INLINE_VISIBILITY + coroutine_handle& operator=(nullptr_t) _NOEXCEPT { + _Base::operator=(nullptr); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + _Promise& promise() const { + return *static_cast<_Promise*>( + __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); + } + +public: + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR + static coroutine_handle from_address(void* __addr) _NOEXCEPT { + coroutine_handle __tmp; + __tmp.__handle_ = __addr; + return __tmp; + } + + // NOTE: this overload isn't required by the standard but is needed so + // the deleted _Promise* overload doesn't make from_address(nullptr) + // ambiguous. + // FIXME: should from_address work with nullptr? + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_CONSTEXPR + static coroutine_handle from_address(nullptr_t) _NOEXCEPT { + return coroutine_handle(nullptr); + } + + template + static coroutine_handle from_address(_Tp*) { + static_assert(_CallIsValid, + "coroutine_handle::from_address cannot be called with " + "non-void pointers"); + } + + template + static coroutine_handle from_address(_Promise*) { + static_assert(_CallIsValid, + "coroutine_handle::from_address cannot be used with " + "pointers to the coroutine's promise type; use 'from_promise' instead"); + } + + _LIBCPP_INLINE_VISIBILITY + static coroutine_handle from_promise(_Promise& __promise) _NOEXCEPT { + typedef typename remove_cv<_Promise>::type _RawPromise; + coroutine_handle __tmp; + __tmp.__handle_ = __builtin_coro_promise( + _VSTD::addressof(const_cast<_RawPromise&>(__promise)), + _LIBCPP_ALIGNOF(_Promise), true); + return __tmp; + } +}; + +#if __has_builtin(__builtin_coro_noop) +struct noop_coroutine_promise {}; + +template <> +class _LIBCPP_TEMPLATE_VIS coroutine_handle + : public coroutine_handle<> { + using _Base = coroutine_handle<>; + using _Promise = noop_coroutine_promise; +public: + + _LIBCPP_INLINE_VISIBILITY + _Promise& promise() const { + return *static_cast<_Promise*>( + __builtin_coro_promise(this->__handle_, _LIBCPP_ALIGNOF(_Promise), false)); + } + + _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } + _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } + + _LIBCPP_CONSTEXPR_AFTER_CXX17 void operator()() const _NOEXCEPT {} + _LIBCPP_CONSTEXPR_AFTER_CXX17 void resume() const _NOEXCEPT {} + _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy() const _NOEXCEPT {} + +private: + _LIBCPP_INLINE_VISIBILITY + friend coroutine_handle noop_coroutine() _NOEXCEPT; + + _LIBCPP_INLINE_VISIBILITY coroutine_handle() _NOEXCEPT { + this->__handle_ = __builtin_coro_noop(); + } +}; + +using noop_coroutine_handle = coroutine_handle; + +inline _LIBCPP_INLINE_VISIBILITY +noop_coroutine_handle noop_coroutine() _NOEXCEPT { + return noop_coroutine_handle(); +} +#else + /// [coroutine.noop] + struct noop_coroutine_promise + { + }; + + // 17.12.4.1 Class noop_coroutine_promise + /// [coroutine.promise.noop] + template <> + struct coroutine_handle + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3460. Unimplementable noop_coroutine_handle guarantees + // [coroutine.handle.noop.conv], conversion + _LIBCPP_CONSTEXPR operator coroutine_handle<>() const _NOEXCEPT + { return coroutine_handle<>::from_address(address()); } + + // [coroutine.handle.noop.observers], observers + _LIBCPP_CONSTEXPR explicit operator bool() const _NOEXCEPT { return true; } + + _LIBCPP_CONSTEXPR bool done() const _NOEXCEPT { return false; } + + // [coroutine.handle.noop.resumption], resumption + void operator()() const _NOEXCEPT {} + + void resume() const noexcept {} + + void destroy() const noexcept {} + + // [coroutine.handle.noop.promise], promise access + noop_coroutine_promise& promise() const noexcept + { return _S_fr.__p; } + + // [coroutine.handle.noop.address], address + _LIBCPP_CONSTEXPR void* address() const noexcept { return _M_fr_ptr; } + + private: + friend coroutine_handle noop_coroutine() _NOEXCEPT; + + struct __frame + { + static void __dummy_resume_destroy() { } + + void (*__r)() = __dummy_resume_destroy; + void (*__d)() = __dummy_resume_destroy; + struct noop_coroutine_promise __p; + }; + + static __frame _S_fr; + + explicit coroutine_handle() noexcept = default; + + void* _M_fr_ptr = &_S_fr; + }; + + using noop_coroutine_handle = coroutine_handle; + + inline noop_coroutine_handle::__frame + noop_coroutine_handle::_S_fr{}; + + inline noop_coroutine_handle noop_coroutine() _NOEXCEPT + { + return noop_coroutine_handle(); + } + +#endif // __has_builtin(__builtin_coro_noop) + +struct suspend_never { + _LIBCPP_INLINE_VISIBILITY + bool await_ready() const _NOEXCEPT { return true; } + _LIBCPP_INLINE_VISIBILITY + void await_suspend(coroutine_handle<>) const _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY + void await_resume() const _NOEXCEPT {} +}; + +struct suspend_always { + _LIBCPP_INLINE_VISIBILITY + bool await_ready() const _NOEXCEPT { return false; } + _LIBCPP_INLINE_VISIBILITY + void await_suspend(coroutine_handle<>) const _NOEXCEPT {} + _LIBCPP_INLINE_VISIBILITY + void await_resume() const _NOEXCEPT {} +}; + +} // __coro20 + +template +struct hash<_VSTD::__coro20::coroutine_handle<_Tp> > { + using __arg_type = _VSTD::__coro20::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) + +#else // the compiler doesn't support this header. + +#error this compiler should use + +#endif + +#endif /* _LIBCPP_COROUTINE */ diff --git a/libcxx/include/experimental/coroutine b/libcxx/include/experimental/coroutine index 1eb224a535a..f43440bd522 100644 --- a/libcxx/include/experimental/coroutine +++ b/libcxx/include/experimental/coroutine @@ -47,6 +47,11 @@ template struct hash>; */ #include + +#if defined(_LIBCPP_COMPILER_GCC) +# error GCC should include not +#else + #include #include #include @@ -333,4 +338,6 @@ _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_COROUTINES) +#endif // check for which compiler. + #endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */