diff options
| author | Eric Fiselier <eric@efcs.ca> | 2017-05-25 04:36:24 +0000 |
|---|---|---|
| committer | Eric Fiselier <eric@efcs.ca> | 2017-05-25 04:36:24 +0000 |
| commit | 3ca9185073ef365ac7e4e027af4c939bc27cacc3 (patch) | |
| tree | a2d2765b8dd94bcac228a973e1bcdcb3d7abd509 /libcxx/include/experimental/coroutine | |
| parent | c81c8cbe77b4f6b420e059307180c72fca0b9c98 (diff) | |
| download | bcm5719-llvm-3ca9185073ef365ac7e4e027af4c939bc27cacc3.tar.gz bcm5719-llvm-3ca9185073ef365ac7e4e027af4c939bc27cacc3.zip | |
Add <experimental/coroutine>
This patch adds the library portions of the coroutines PDTS,
which should now be supported by Clang.
llvm-svn: 303836
Diffstat (limited to 'libcxx/include/experimental/coroutine')
| -rw-r--r-- | libcxx/include/experimental/coroutine | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/libcxx/include/experimental/coroutine b/libcxx/include/experimental/coroutine new file mode 100644 index 00000000000..208a4d21761 --- /dev/null +++ b/libcxx/include/experimental/coroutine @@ -0,0 +1,260 @@ +// -*- 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 <typename R, typename... ArgTypes> +class coroutine_traits; +// 18.11.2 coroutine handle +template <typename Promise = void> +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 <class T> struct hash; +template <class P> struct hash<coroutine_handle<P>>; + +} // namespace coroutines_v1 +} // namespace experimental +} // namespace std + + */ + +#include <experimental/__config> +#include <new> +#include <type_traits> +#include <functional> +#include <memory> // for hash<T*> +#include <cstddef> +#include <cassert> +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +#ifndef __cpp_coroutines +# if defined(_LIBCPP_WARNING) + _LIBCPP_WARNING("<experimental/coroutine> cannot be used with this compiler") +# else +# warning <experimental/coroutine> cannot be used with this compiler +# endif +#endif + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_COROUTINES + +template <class _Tp, class = void> +struct __coroutine_traits_sfinae {}; + +template <class _Tp> +struct __coroutine_traits_sfinae< + _Tp, typename __void_t<typename _Tp::promise_type>::type> +{ + using promise_type = typename _Tp::promise_type; +}; + +template <typename _Ret, typename... _Args> +struct _LIBCPP_TEMPLATE_VIS coroutine_traits + : public __coroutine_traits_sfinae<_Ret> +{ +}; + +template <typename Promise = void> +class _LIBCPP_TEMPLATE_VIS coroutine_handle; + +#if defined(__cpp_coroutines) + +template <> +class _LIBCPP_TEMPLATE_VIS coroutine_handle<void> { +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()() const { resume(); } + + _LIBCPP_ALWAYS_INLINE + void resume() const { + _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() const { + _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 <class _PromiseT> 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<void*>()(__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 <typename _Promise> +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() { + return *reinterpret_cast<_Promise*>( + __builtin_coro_promise(this->__handle_, alignof(_Promise), false)); + } + + _LIBCPP_INLINE_VISIBILITY + _Promise const& promise() const { + return *reinterpret_cast<_Promise const*>( + __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; + } +}; + +#endif // defined(__cpp_coroutines) + +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 <class _Tp> +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<void*>{}(__v.address());} +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif /* _LIBCPP_EXPERIMENTAL_COROUTINE */ |

