diff --git a/librf/src/unix/clang_builtin.h b/librf/src/unix/clang_builtin.h index 25b3108..60362dd 100644 --- a/librf/src/unix/clang_builtin.h +++ b/librf/src/unix/clang_builtin.h @@ -28,9 +28,11 @@ extern "C" void* __builtin_coro_promise(void* addr, int alignment, bool from_pro extern "C" size_t __builtin_coro_size(); extern "C" void* __builtin_coro_frame(); +extern "C" void* __builtin_coro_noop(); extern "C" void* __builtin_coro_free(void* coro_frame); #pragma intrinsic(__builtin_coro_size) #pragma intrinsic(__builtin_coro_frame) +#pragma intrinsic(__builtin_coro_noop) #pragma intrinsic(__builtin_coro_free) extern "C" void* __builtin_coro_id(int align, void* promise, void* fnaddr, void* parts); diff --git a/librf/src/unix/coroutine.h b/librf/src/unix/coroutine.h index e5e5241..701bd94 100644 --- a/librf/src/unix/coroutine.h +++ b/librf/src/unix/coroutine.h @@ -52,6 +52,7 @@ template struct hash>; #include // for hash #include #include +#include #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 struct coroutine_traits : public __coroutine_traits_sfinae<_Ret> { }; + // 17.12.3, coroutine handle template class coroutine_handle; template <> - class coroutine_handle { + class coroutine_handle + { 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()(__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 - 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 - : public coroutine_handle<> { + class coroutine_handle : 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; - + 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 struct hash > { + 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 {