|
|
@@ -52,6 +52,7 @@ template <class P> struct hash<coroutine_handle<P>>; |
|
|
|
#include <memory> // for hash<T*> |
|
|
|
#include <cstddef> |
|
|
|
#include <cassert> |
|
|
|
#include <compare> |
|
|
|
|
|
|
|
#if defined(__clang__) |
|
|
|
#include "clang_builtin.h" |
|
|
@@ -80,17 +81,21 @@ namespace std { |
|
|
|
using promise_type = typename _Tp::promise_type; |
|
|
|
}; |
|
|
|
|
|
|
|
// 17.12.2, coroutine traits |
|
|
|
template <typename _Ret, typename... _Args> |
|
|
|
struct coroutine_traits : public __coroutine_traits_sfinae<_Ret> |
|
|
|
{ |
|
|
|
}; |
|
|
|
|
|
|
|
// 17.12.3, coroutine handle |
|
|
|
template <typename _Promise = void> |
|
|
|
class coroutine_handle; |
|
|
|
|
|
|
|
template <> |
|
|
|
class coroutine_handle<void> { |
|
|
|
class coroutine_handle<void> |
|
|
|
{ |
|
|
|
public: |
|
|
|
// 17.12.3.1, construct/reset |
|
|
|
constexpr coroutine_handle() noexcept : __handle_(nullptr) {} |
|
|
|
constexpr coroutine_handle(nullptr_t) noexcept : __handle_(nullptr) {} |
|
|
|
coroutine_handle& operator=(nullptr_t) noexcept { |
|
|
@@ -98,28 +103,15 @@ namespace std { |
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.3.2, export/import |
|
|
|
constexpr void* address() const noexcept { return __handle_; } |
|
|
|
constexpr explicit operator bool() const noexcept { return __handle_; } |
|
|
|
|
|
|
|
void operator()() { resume(); } |
|
|
|
void resume() { |
|
|
|
__builtin_coro_resume(__handle_); |
|
|
|
} |
|
|
|
void destroy() { |
|
|
|
__builtin_coro_destroy(__handle_); |
|
|
|
} |
|
|
|
bool done() const { |
|
|
|
return __builtin_coro_done(__handle_); |
|
|
|
} |
|
|
|
public: |
|
|
|
static coroutine_handle from_address(void* __addr) noexcept { |
|
|
|
static constexpr coroutine_handle from_address(void* __addr) noexcept { |
|
|
|
coroutine_handle __tmp; |
|
|
|
__tmp.__handle_ = __addr; |
|
|
|
return __tmp; |
|
|
|
} |
|
|
|
|
|
|
|
// FIXME: Should from_address(nullptr) be allowed? |
|
|
|
static coroutine_handle from_address(nullptr_t) noexcept { |
|
|
|
static constexpr coroutine_handle from_address(nullptr_t) noexcept { |
|
|
|
return coroutine_handle(nullptr); |
|
|
|
} |
|
|
|
|
|
|
@@ -130,6 +122,22 @@ namespace std { |
|
|
|
"non-void pointers"); |
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.3.3, observers |
|
|
|
constexpr explicit operator bool() const noexcept { |
|
|
|
return __handle_ != nullptr; |
|
|
|
} |
|
|
|
bool done() const { |
|
|
|
return __builtin_coro_done(__handle_); |
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.3.4, resumption |
|
|
|
void operator()() const { resume(); } |
|
|
|
void resume() const { |
|
|
|
__builtin_coro_resume(__handle_); |
|
|
|
} |
|
|
|
void destroy() const{ |
|
|
|
__builtin_coro_destroy(__handle_); |
|
|
|
} |
|
|
|
private: |
|
|
|
bool __is_suspended() const noexcept { |
|
|
|
// FIXME actually implement a check for if the coro is suspended. |
|
|
@@ -142,50 +150,35 @@ namespace std { |
|
|
|
void* __handle_; |
|
|
|
}; |
|
|
|
|
|
|
|
// 18.11.2.7 comparison operators: |
|
|
|
inline bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
// 17.12.3.6, comparison operators |
|
|
|
constexpr bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return __x.address() == __y.address(); |
|
|
|
} |
|
|
|
inline bool operator!=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return !(__x == __y); |
|
|
|
} |
|
|
|
inline bool operator<(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return less<void*>()(__x.address(), __y.address()); |
|
|
|
} |
|
|
|
inline bool operator>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return __y < __x; |
|
|
|
} |
|
|
|
inline bool operator<=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return !(__x > __y); |
|
|
|
} |
|
|
|
inline bool operator>=(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return !(__x < __y); |
|
|
|
constexpr strong_ordering operator<=>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { |
|
|
|
return __x.address() <=> __y.address(); |
|
|
|
} |
|
|
|
|
|
|
|
template <typename _Promise> |
|
|
|
class coroutine_handle : public coroutine_handle<> { |
|
|
|
class coroutine_handle : public coroutine_handle<> |
|
|
|
{ |
|
|
|
using _Base = coroutine_handle<>; |
|
|
|
public: |
|
|
|
#ifndef _LIBCPP_CXX03_LANG |
|
|
|
// 18.11.2.1 construct/reset |
|
|
|
// 17.12.3.1, construct/reset |
|
|
|
using coroutine_handle<>::coroutine_handle; |
|
|
|
#else |
|
|
|
coroutine_handle() noexcept : _Base() {} |
|
|
|
coroutine_handle(nullptr_t) noexcept : _Base(nullptr) {} |
|
|
|
#endif |
|
|
|
|
|
|
|
coroutine_handle& operator=(nullptr_t) noexcept { |
|
|
|
_Base::operator=(nullptr); |
|
|
|
return *this; |
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.3.5, promise access |
|
|
|
_Promise& promise() const { |
|
|
|
return *static_cast<_Promise*>( |
|
|
|
__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); |
|
|
|
} |
|
|
|
|
|
|
|
public: |
|
|
|
static coroutine_handle from_address(void* __addr) noexcept { |
|
|
|
// 17.12.3.2, export/import |
|
|
|
static constexpr coroutine_handle from_address(void* __addr) noexcept { |
|
|
|
coroutine_handle __tmp; |
|
|
|
__tmp.__handle_ = __addr; |
|
|
|
return __tmp; |
|
|
@@ -195,7 +188,7 @@ namespace std { |
|
|
|
// the deleted _Promise* overload doesn't make from_address(nullptr) |
|
|
|
// ambiguous. |
|
|
|
// FIXME: should from_address work with nullptr? |
|
|
|
static coroutine_handle from_address(nullptr_t) noexcept { |
|
|
|
static constexpr coroutine_handle from_address(nullptr_t) noexcept { |
|
|
|
return coroutine_handle(nullptr); |
|
|
|
} |
|
|
|
|
|
|
@@ -223,23 +216,32 @@ namespace std { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 17.12.4, no-op coroutines |
|
|
|
#if __has_builtin(__builtin_coro_noop) |
|
|
|
struct noop_coroutine_promise {}; |
|
|
|
|
|
|
|
template <> |
|
|
|
class coroutine_handle<noop_coroutine_promise> |
|
|
|
: public coroutine_handle<> { |
|
|
|
class coroutine_handle<noop_coroutine_promise> : public coroutine_handle<> |
|
|
|
{ |
|
|
|
using _Base = coroutine_handle<>; |
|
|
|
using _Promise = noop_coroutine_promise; |
|
|
|
public: |
|
|
|
_Promise& promise() const { |
|
|
|
// 17.12.4.2.3, promise access |
|
|
|
_Promise& promise() const noexcept { |
|
|
|
return *static_cast<_Promise*>( |
|
|
|
__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); |
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.4.2.4, address |
|
|
|
constexpr void* address() const noexcept { |
|
|
|
return this->__handle_; |
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.4.2.1, observers |
|
|
|
constexpr explicit operator bool() const noexcept { return true; } |
|
|
|
constexpr bool done() const noexcept { return false; } |
|
|
|
|
|
|
|
// 17.12.4.2.2, resumption |
|
|
|
constexpr void operator()() const noexcept {} |
|
|
|
constexpr void resume() const noexcept {} |
|
|
|
constexpr void destroy() const noexcept {} |
|
|
@@ -251,28 +253,30 @@ namespace std { |
|
|
|
}; |
|
|
|
|
|
|
|
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; |
|
|
|
|
|
|
|
|
|
|
|
inline noop_coroutine_handle noop_coroutine() noexcept { |
|
|
|
return noop_coroutine_handle(); |
|
|
|
} |
|
|
|
#endif // __has_builtin(__builtin_coro_noop) |
|
|
|
|
|
|
|
// 17.12.5, trivial awaitables |
|
|
|
struct suspend_never { |
|
|
|
bool await_ready() const noexcept { return true; } |
|
|
|
void await_suspend(coroutine_handle<>) const noexcept {} |
|
|
|
void await_resume() const noexcept {} |
|
|
|
constexpr bool await_ready() const noexcept { return true; } |
|
|
|
constexpr void await_suspend(coroutine_handle<>) const noexcept {} |
|
|
|
constexpr void await_resume() const noexcept {} |
|
|
|
}; |
|
|
|
|
|
|
|
struct suspend_always { |
|
|
|
bool await_ready() const noexcept { return false; } |
|
|
|
void await_suspend(coroutine_handle<>) const noexcept {} |
|
|
|
void await_resume() const noexcept {} |
|
|
|
constexpr bool await_ready() const noexcept { return false; } |
|
|
|
constexpr void await_suspend(coroutine_handle<>) const noexcept {} |
|
|
|
constexpr void await_resume() const noexcept {} |
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 17.12.3.7, hash support |
|
|
|
template <class _Tp> |
|
|
|
struct hash<experimental::coroutine_handle<_Tp> > { |
|
|
|
using argument_type = experimental::coroutine_handle<_Tp>; |
|
|
|
using result_type = size_t; |
|
|
|
using __arg_type = experimental::coroutine_handle<_Tp>; |
|
|
|
size_t operator()(__arg_type const& __v) const noexcept |
|
|
|
{ |