File frame.h¶
File List > coroutine > frame.h
Go to the documentation of this file.
#pragma once
#ifndef _COROUTINE_
#define _COROUTINE_
// suppress <experimental/resumable>
#define _EXPERIMENTAL_RESUMABLE_
// enforced by MSVC, but be explicit
#ifndef _RESUMABLE_FUNCTIONS_SUPPORTED
#define _RESUMABLE_FUNCTIONS_SUPPORTED
#endif
// requires C++ 17 __has_include
#if __has_include(<yvals_core.h>)
#include <yvals_core.h>
#endif
#if _STL_COMPILER_PREPROCESSOR
#include <memory>
#include <new>
#endif // _STL_COMPILER_PREPROCESSOR
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <exception> // std::current_exception
#include <functional> // std::hash
#if defined(__cpp_coroutines)
// ...
#endif
struct portable_coro_prefix;
bool portable_coro_done(portable_coro_prefix* _Handle);
void portable_coro_resume(portable_coro_prefix* _Handle);
void portable_coro_destroy(portable_coro_prefix* _Handle);
auto portable_coro_from_promise(void* _PromAddr, ptrdiff_t _PromSize)
-> portable_coro_prefix*;
void* portable_coro_get_promise(portable_coro_prefix* _Handle,
ptrdiff_t _PromSize);
namespace std {
// 17.12.3, coroutine handle
template <typename _PromiseT = void>
struct coroutine_handle;
// STRUCT TEMPLATE coroutine_handle
template <>
struct coroutine_handle<void> {
// 17.12.3.1, construct
constexpr coroutine_handle() noexcept {
}
// 17.12.3.1, reset
constexpr coroutine_handle(std::nullptr_t) noexcept {
}
coroutine_handle& operator=(nullptr_t) noexcept {
_Ptr = nullptr;
return *this;
}
// 17.12.3.2, export
constexpr void* address() const noexcept {
return _Ptr;
}
// 17.12.3.2, import
static /*constexpr*/ coroutine_handle from_address(void* _Addr) {
coroutine_handle _Result{};
_Result._Ptr = reinterpret_cast<portable_coro_prefix*>(_Addr);
return _Result;
}
// 17.12.3.3, observers
constexpr explicit operator bool() const noexcept {
return _Ptr != nullptr;
}
bool done() const {
return portable_coro_done(_Ptr);
}
// 17.12.3.4, resumption
void resume() const {
return portable_coro_resume(_Ptr);
}
void operator()() const {
return portable_coro_resume(_Ptr);
}
void destroy() const {
return portable_coro_destroy(_Ptr);
}
protected: // this is `private` in the standard
portable_coro_prefix* _Ptr = nullptr;
};
template <typename _PromiseT>
struct coroutine_handle : public coroutine_handle<void> {
// 17.12.3.1, construct
using coroutine_handle<void>::coroutine_handle;
static coroutine_handle from_promise(_PromiseT& _Prom) {
auto* _Addr = portable_coro_from_promise(&_Prom, sizeof(_PromiseT));
return coroutine_handle::from_address(_Addr);
}
// 17.12.3.1, reset
coroutine_handle& operator=(nullptr_t) noexcept {
this->_Ptr = nullptr;
return *this;
}
// 17.12.3.2, export/import
static /*constexpr*/ coroutine_handle from_address(void* _Addr) noexcept {
coroutine_handle _Result{};
_Result._Ptr = reinterpret_cast<portable_coro_prefix*>(_Addr);
return _Result;
}
// 17.12.3.5, promise access
_PromiseT& promise() const {
auto* _Prefix =
reinterpret_cast<portable_coro_prefix*>(this->address());
void* _Addr = portable_coro_get_promise(_Prefix, sizeof(_PromiseT));
_PromiseT* _Prom = reinterpret_cast<_PromiseT*>(_Addr);
return *_Prom;
}
};
// 17.12.3.6, comparison operators
constexpr bool operator==(const coroutine_handle<void> _Left,
const coroutine_handle<void> _Right) noexcept {
return _Left.address() == _Right.address();
}
constexpr bool operator!=(const coroutine_handle<void> _Left,
const coroutine_handle<void> _Right) noexcept {
return !(_Left == _Right);
}
constexpr bool operator<(const coroutine_handle<void> _Left,
const coroutine_handle<void> _Right) noexcept {
return _Left.address() < _Right.address();
}
constexpr bool operator>(const coroutine_handle<void> _Left,
const coroutine_handle<void> _Right) noexcept {
return _Right < _Left;
}
constexpr bool operator<=(const coroutine_handle<void> _Left,
const coroutine_handle<void> _Right) noexcept {
return !(_Left > _Right);
}
constexpr bool operator>=(const coroutine_handle<void> _Left,
const coroutine_handle<void> _Right) noexcept {
return !(_Left < _Right);
}
// 17.12.4, no-op coroutines
struct noop_coroutine_promise {};
// STRUCT noop_coroutine_handle
using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;
// 17.12.4.3
noop_coroutine_handle noop_coroutine() noexcept;
// STRUCT coroutine_handle<noop_coroutine_promise>
template <>
struct coroutine_handle<noop_coroutine_promise>
: public coroutine_handle<void> {
// 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 {
}
#if defined(__clang__)
#if __has_builtin(__builtin_coro_noop)
noop_coroutine_promise& promise() const noexcept {
void* _Prom =
__builtin_coro_promise(__builtin_coro_noop(), //
alignof(noop_coroutine_promise), false);
return *(noop_coroutine_promise*)(_Prom);
}
private:
coroutine_handle() noexcept
: coroutine_handle<void>{from_address(__builtin_coro_noop())} {
}
#else
#error "requires higher clang version to use __builtin_coro_noop"
#endif
#elif defined(_MSC_VER)
// 17.12.4.2.4, address
// C3615: cannot result in a constant expression
constexpr void* address() const noexcept {
return (noop_coroutine_promise*)(UINTPTR_MAX - 0x170704);
}
// 17.12.4.2.3, promise access
noop_coroutine_promise& promise() const noexcept {
return *(noop_coroutine_promise*)(this->address());
}
private:
coroutine_handle() noexcept
: coroutine_handle<void>{from_address(&this->promise())} {
// A noop_coroutine_handle's ptr is always a non-null pointer
}
#endif
private:
friend noop_coroutine_handle noop_coroutine() noexcept;
};
inline noop_coroutine_handle noop_coroutine() noexcept {
return {};
}
// 17.12.5, trivial awaitables
// STRUCT suspend_never
class suspend_never {
public:
constexpr bool await_ready() const noexcept {
return true;
}
constexpr void await_resume() const noexcept {
}
constexpr void await_suspend(coroutine_handle<void>) const noexcept {
}
};
// STRUCT suspend_always
class suspend_always {
public:
constexpr bool await_ready() const noexcept {
return false;
}
constexpr void await_resume() const noexcept {
}
constexpr void await_suspend(coroutine_handle<void>) const noexcept {
}
};
// 17.12.2, coroutine traits
template <class _Ret, class = void>
struct coro_traits_sfinae {};
template <class _Ret>
struct coro_traits_sfinae<_Ret, void_t<typename _Ret::promise_type>> {
using promise_type = typename _Ret::promise_type;
};
// there is no way but to define in `std::experimental` since compilers are checking it
namespace experimental {
// STRUCT TEMPLATE coroutine_traits
template <typename _Ret, typename... _Ts>
struct coroutine_traits : coro_traits_sfinae<_Ret> {};
#if defined(__clang__)
// clang: std::experimental::coroutine_handle must be a class template
template <typename P>
struct coroutine_handle : public std::coroutine_handle<P> {};
#elif defined(_MSC_VER)
// msvc: compatibility with existing `experimental::coroutine_handle` identifiers.
using std::coroutine_handle;
// _Resumable_helper_traits class isolates front-end from public surface naming changes
// The original code is in <experimental/resumable>
template <typename _Ret, typename... _Ts>
struct _Resumable_helper_traits {
using _Traits = coroutine_traits<_Ret, _Ts...>;
using _PromiseT = typename _Traits::promise_type;
using _Handle_type = coroutine_handle<_PromiseT>;
static _PromiseT* _Promise_from_frame(void* _Addr) noexcept {
auto& prom = _Handle_type::from_address(_Addr).promise();
return &prom;
}
static _Handle_type _Handle_from_frame(void* _Addr) noexcept {
return _Handle_type::from_promise(*_Promise_from_frame(_Addr));
}
static void _Set_exception(void* _Addr) {
_Promise_from_frame(_Addr)->set_exception(std::current_exception());
}
static void _ConstructPromise(void* _Addr, void* _Resume_addr,
int _HeapElision) {
*reinterpret_cast<void**>(_Addr) = _Resume_addr;
*reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(_Addr) +
sizeof(void*)) =
2u + (_HeapElision ? 0u : 0x10000u);
auto _Prom = _Promise_from_frame(_Addr);
::new (static_cast<void*>(_Prom)) _PromiseT();
}
static void _DestructPromise(void* _Addr) {
_Promise_from_frame(_Addr)->~_PromiseT();
}
};
#endif
} // namespace experimental
// STRUCT TEMPLATE coroutine_traits
template <typename _Ret, typename... _Param>
using coroutine_traits = std::experimental::coroutine_traits<_Ret, _Param...>;
// 17.12.3.7, hash support
template <typename _PromiseT>
struct hash<coroutine_handle<_PromiseT>> {
// deprecated in C++17
using argument_type = coroutine_handle<_PromiseT>;
// deprecated in C++17
using result_type = size_t;
[[nodiscard]] //
result_type
operator()(argument_type const& _Handle) const noexcept {
return hash<void*>()(_Handle.address());
}
};
} // namespace std
#endif // _COROUTINE_