set_exception(std::make_exception_ptr(std::move(e))); | set_exception(std::make_exception_ptr(std::move(e))); | ||||
} | } | ||||
future_type get_future() | |||||
future_type get_future() noexcept | |||||
{ | { | ||||
return future_type{ this->_state }; | return future_type{ this->_state }; | ||||
} | } |
template <typename T> | template <typename T> | ||||
struct counted_ptr | struct counted_ptr | ||||
{ | { | ||||
counted_ptr() = default; | |||||
counted_ptr(const counted_ptr& cp) : _p(cp._p) | |||||
counted_ptr() noexcept = default; | |||||
counted_ptr(const counted_ptr& cp) : _p(cp._p) | |||||
{ | { | ||||
_lock(); | _lock(); | ||||
} | } | ||||
counted_ptr(T* p) : _p(p) | |||||
counted_ptr(T* p) : _p(p) | |||||
{ | { | ||||
_lock(); | _lock(); | ||||
} | } | ||||
std::swap(_p, cp._p); | std::swap(_p, cp._p); | ||||
} | } | ||||
counted_ptr& operator=(const counted_ptr& cp) | |||||
counted_ptr& operator=(const counted_ptr& cp) | |||||
{ | { | ||||
if (&cp != this) | if (&cp != this) | ||||
{ | { | ||||
_unlock(); | _unlock(); | ||||
} | } | ||||
T* operator->() const | |||||
T* operator->() const noexcept | |||||
{ | { | ||||
return _p; | return _p; | ||||
} | } | ||||
T* get() const | |||||
T* get() const noexcept | |||||
{ | { | ||||
return _p; | return _p; | ||||
} | } |
counted_ptr<state_type> _state; | counted_ptr<state_type> _state; | ||||
future_t(counted_ptr<state_type> _st) | |||||
future_t(counted_ptr<state_type> _st) noexcept | |||||
:_state(std::move(_st)) {} | :_state(std::move(_st)) {} | ||||
future_t(const future_t&) = default; | future_t(const future_t&) = default; | ||||
future_t(future_t&&) = default; | future_t(future_t&&) = default; | ||||
future_t& operator = (const future_t&) = default; | future_t& operator = (const future_t&) = default; | ||||
future_t& operator = (future_t&&) = default; | future_t& operator = (future_t&&) = default; | ||||
bool await_ready() | |||||
bool await_ready() noexcept | |||||
{ | { | ||||
return _state->future_await_ready(); | return _state->future_await_ready(); | ||||
} | } |
return generator_t{ *this }; | return generator_t{ *this }; | ||||
} | } | ||||
std::experimental::suspend_always initial_suspend() | |||||
std::experimental::suspend_always initial_suspend() noexcept | |||||
{ | { | ||||
return {}; | return {}; | ||||
} | } | ||||
std::experimental::suspend_always final_suspend() | |||||
std::experimental::suspend_always final_suspend() noexcept | |||||
{ | { | ||||
return {}; | return {}; | ||||
} | } | ||||
std::experimental::suspend_always yield_value(_Ty const& _Value) | |||||
std::experimental::suspend_always yield_value(_Ty const& _Value) noexcept | |||||
{ | { | ||||
_CurrentValue = std::addressof(_Value); | _CurrentValue = std::addressof(_Value); | ||||
return {}; | return {}; | ||||
} | } | ||||
//template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | //template<class = std::enable_if_t<!std::is_same_v<_Ty, void>, _Ty>> | ||||
void return_value(_Ty const& _Value) | |||||
void return_value(_Ty const& _Value) noexcept | |||||
{ | { | ||||
_CurrentValue = std::addressof(_Value); | _CurrentValue = std::addressof(_Value); | ||||
} | } | ||||
//template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | //template<class = std::enable_if_t<std::is_same_v<_Ty, void>, _Ty>> | ||||
void return_value() | |||||
void return_value() noexcept | |||||
{ | { | ||||
_CurrentValue = nullptr; | _CurrentValue = nullptr; | ||||
} | } | ||||
#endif | #endif | ||||
template <typename _Uty> | template <typename _Uty> | ||||
_Uty&& await_transform(_Uty&& _Whatever) | |||||
_Uty&& await_transform(_Uty&& _Whatever) noexcept | |||||
{ | { | ||||
static_assert(std::is_same_v<_Uty, void>, | static_assert(std::is_same_v<_Uty, void>, | ||||
"co_await is not supported in coroutines of type std::experiemental::generator_t"); | "co_await is not supported in coroutines of type std::experiemental::generator_t"); | ||||
return std::forward<_Uty>(_Whatever); | return std::forward<_Uty>(_Whatever); | ||||
} | } | ||||
state_type* get_state() | |||||
state_type* get_state() noexcept | |||||
{ | { | ||||
#if RESUMEF_INLINE_STATE | #if RESUMEF_INLINE_STATE | ||||
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); |
#pragma once | #pragma once | ||||
#ifndef _offset_of | |||||
#define _offset_of(c, m) reinterpret_cast<size_t>(&static_cast<c *>(0)->m) | |||||
#endif | |||||
#define co_yield_void co_yield nullptr | #define co_yield_void co_yield nullptr | ||||
#define co_return_void co_return nullptr | #define co_return_void co_return nullptr | ||||
#define resumf_guard_lock(lker) (lker).lock(); resumef::scoped_lock<resumef::mutex_t> __resumf_guard##lker##__(std::adopt_lock, (lker)) | #define resumf_guard_lock(lker) (lker).lock(); resumef::scoped_lock<resumef::mutex_t> __resumf_guard##lker##__(std::adopt_lock, (lker)) |
using promise_type = promise_t<value_type>; | using promise_type = promise_t<value_type>; | ||||
using future_type = future_t<value_type>; | using future_type = future_t<value_type>; | ||||
promise_impl_t(){} | |||||
promise_impl_t() noexcept {} | |||||
promise_impl_t(promise_impl_t&& _Right) noexcept = default; | promise_impl_t(promise_impl_t&& _Right) noexcept = default; | ||||
promise_impl_t& operator = (promise_impl_t&& _Right) noexcept = default; | promise_impl_t& operator = (promise_impl_t&& _Right) noexcept = default; | ||||
promise_impl_t(const promise_impl_t&) = delete; | promise_impl_t(const promise_impl_t&) = delete; | ||||
promise_impl_t& operator = (const promise_impl_t&) = delete; | promise_impl_t& operator = (const promise_impl_t&) = delete; | ||||
auto get_state()->state_type*; | |||||
auto get_state() noexcept->state_type*; | |||||
suspend_on_initial initial_suspend() noexcept; | suspend_on_initial initial_suspend() noexcept; | ||||
suspend_on_final final_suspend() noexcept; | suspend_on_final final_suspend() noexcept; | ||||
template <typename _Uty> | template <typename _Uty> | ||||
_Uty&& await_transform(_Uty&& _Whatever); | |||||
_Uty&& await_transform(_Uty&& _Whatever) noexcept; | |||||
void set_exception(std::exception_ptr e); | void set_exception(std::exception_ptr e); | ||||
#ifdef __clang__ | #ifdef __clang__ | ||||
void unhandled_exception(); //If the coroutine ends with an uncaught exception, it performs the following: | void unhandled_exception(); //If the coroutine ends with an uncaught exception, it performs the following: | ||||
#endif | #endif | ||||
future_type get_return_object(); | |||||
void cancellation_requested(); | |||||
future_type get_return_object() noexcept; | |||||
void cancellation_requested() noexcept; | |||||
using _Alloc_char = std::allocator<char>; | using _Alloc_char = std::allocator<char>; | ||||
void* operator new(size_t _Size); | void* operator new(size_t _Size); |
template <typename _Ty> | template <typename _Ty> | ||||
template <typename _Uty> | template <typename _Uty> | ||||
_Uty&& promise_impl_t<_Ty>::await_transform(_Uty&& _Whatever) | |||||
_Uty&& promise_impl_t<_Ty>::await_transform(_Uty&& _Whatever) noexcept | |||||
{ | { | ||||
if constexpr (is_future_v<_Uty> || is_awaitable_v<_Uty>) | if constexpr (is_future_v<_Uty> || is_awaitable_v<_Uty>) | ||||
{ | { | ||||
#endif | #endif | ||||
template <typename _Ty> | template <typename _Ty> | ||||
inline future_t<_Ty> promise_impl_t<_Ty>::get_return_object() | |||||
inline future_t<_Ty> promise_impl_t<_Ty>::get_return_object() noexcept | |||||
{ | { | ||||
return { this->get_state() }; | return { this->get_state() }; | ||||
} | } | ||||
template <typename _Ty> | template <typename _Ty> | ||||
inline void promise_impl_t<_Ty>::cancellation_requested() | |||||
inline void promise_impl_t<_Ty>::cancellation_requested() noexcept | |||||
{ | { | ||||
} | } | ||||
template <typename _Ty> | template <typename _Ty> | ||||
auto promise_impl_t<_Ty>::get_state() -> state_type* | |||||
auto promise_impl_t<_Ty>::get_state() noexcept -> state_type* | |||||
{ | { | ||||
#if RESUMEF_INLINE_STATE | #if RESUMEF_INLINE_STATE | ||||
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); |
task_base_t() = default; | task_base_t() = default; | ||||
virtual ~task_base_t(); | virtual ~task_base_t(); | ||||
state_base_t* get_state() const | |||||
state_base_t* get_state() const noexcept | |||||
{ | { | ||||
return _state.get(); | return _state.get(); | ||||
} | } |
return _ready_task.empty() && _runing_states.empty() && _timer->empty(); | return _ready_task.empty() && _runing_states.empty() && _timer->empty(); | ||||
} | } | ||||
inline timer_manager* timer() const | |||||
inline timer_manager* timer() const noexcept | |||||
{ | { | ||||
return _timer.get(); | return _timer.get(); | ||||
} | } |
std::thread::id owner_thread_id; | std::thread::id owner_thread_id; | ||||
#endif | #endif | ||||
spinlock() | |||||
spinlock() noexcept | |||||
{ | { | ||||
lck = FREE_VALUE; | lck = FREE_VALUE; | ||||
} | } | ||||
void lock() | |||||
void lock() noexcept | |||||
{ | { | ||||
using namespace std::chrono; | using namespace std::chrono; | ||||
#endif | #endif | ||||
} | } | ||||
bool try_lock() | |||||
bool try_lock() noexcept | |||||
{ | { | ||||
int val = FREE_VALUE; | int val = FREE_VALUE; | ||||
bool ret = lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acquire); | bool ret = lck.compare_exchange_weak(val, LOCKED_VALUE, std::memory_order_acquire); | ||||
return ret; | return ret; | ||||
} | } | ||||
void unlock() | |||||
void unlock() noexcept | |||||
{ | { | ||||
#if _DEBUG | #if _DEBUG | ||||
owner_thread_id = std::thread::id(); | owner_thread_id = std::thread::id(); |
} | } | ||||
} | } | ||||
bool state_generator_t::has_handler() const | |||||
bool state_generator_t::has_handler() const noexcept | |||||
{ | { | ||||
return (bool)_coro; | return (bool)_coro; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
bool state_future_t::has_handler() const | |||||
bool state_future_t::has_handler() const noexcept | |||||
{ | { | ||||
scoped_lock<lock_type> __guard(_mtx); | scoped_lock<lock_type> __guard(_mtx); | ||||
return has_handler_skip_lock(); | return has_handler_skip_lock(); |
virtual void destroy_deallocate() = 0; | virtual void destroy_deallocate() = 0; | ||||
public: | public: | ||||
virtual void resume() = 0; | virtual void resume() = 0; | ||||
virtual bool has_handler() const = 0; | |||||
virtual bool has_handler() const noexcept = 0; | |||||
void set_scheduler(scheduler_t* sch) | void set_scheduler(scheduler_t* sch) | ||||
{ | { | ||||
virtual void destroy_deallocate() override; | virtual void destroy_deallocate() override; | ||||
public: | public: | ||||
virtual void resume() override; | virtual void resume() override; | ||||
virtual bool has_handler() const override; | |||||
virtual bool has_handler() const noexcept override; | |||||
bool switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler); | bool switch_scheduler_await_suspend(scheduler_t* sch, coroutine_handle<> handler); | ||||
std::atomic<result_type> _has_value{ result_type::None }; | std::atomic<result_type> _has_value{ result_type::None }; | ||||
bool _is_future; | bool _is_future; | ||||
initor_type _is_initor = initor_type::None; | initor_type _is_initor = initor_type::None; | ||||
static_assert(sizeof(std::atomic<result_type>) == 1); | |||||
static_assert(alignof(std::atomic<result_type>) == 1); | |||||
static_assert(sizeof(bool) == 1); | |||||
static_assert(alignof(bool) == 1); | |||||
static_assert(sizeof(std::atomic<initor_type>) == 1); | |||||
static_assert(alignof(std::atomic<initor_type>) == 1); | |||||
public: | public: | ||||
state_future_t() | state_future_t() | ||||
{ | { | ||||
virtual void destroy_deallocate() override; | virtual void destroy_deallocate() override; | ||||
virtual void resume() override; | virtual void resume() override; | ||||
virtual bool has_handler() const override; | |||||
virtual bool has_handler() const noexcept override; | |||||
inline bool is_ready() const | |||||
inline bool is_ready() const noexcept | |||||
{ | { | ||||
return 0 != reinterpret_cast<const std::atomic<uint16_t> &>(_has_value).load(std::memory_order_acquire); | |||||
//return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future; | |||||
//msvc认为是constexpr表达式(不写还给警告),然而,clang不这么认为。 | |||||
//放弃constexpr,反正合格的编译器都会优化掉这个if判断的。 | |||||
if | |||||
#ifndef __clang__ | |||||
constexpr | |||||
#endif | |||||
(_offset_of(state_future_t, _is_future) - _offset_of(state_future_t, _has_value) == 1) | |||||
return 0 != reinterpret_cast<const std::atomic<uint16_t> &>(_has_value).load(std::memory_order_acquire); | |||||
else | |||||
return _has_value.load(std::memory_order_acquire) != result_type::None || _is_future; | |||||
} | } | ||||
inline bool has_handler_skip_lock() const | |||||
inline bool has_handler_skip_lock() const noexcept | |||||
{ | { | ||||
return (bool)_coro || _is_initor != initor_type::None; | return (bool)_coro || _is_initor != initor_type::None; | ||||
} | } | ||||
return _parent ? _parent->get_scheduler() : _scheduler; | return _parent ? _parent->get_scheduler() : _scheduler; | ||||
} | } | ||||
inline state_base_t * get_parent() const | |||||
inline state_base_t * get_parent() const noexcept | |||||
{ | { | ||||
return _parent; | return _parent; | ||||
} | } | ||||
inline uint32_t get_alloc_size() const | |||||
inline uint32_t get_alloc_size() const noexcept | |||||
{ | { | ||||
return _alloc_size; | return _alloc_size; | ||||
} | } | ||||
inline bool future_await_ready() | |||||
inline bool future_await_ready() noexcept | |||||
{ | { | ||||
//scoped_lock<lock_type> __guard(this->_mtx); | //scoped_lock<lock_type> __guard(this->_mtx); | ||||
return _has_value.load(std::memory_order_acquire) != result_type::None; | return _has_value.load(std::memory_order_acquire) != result_type::None; | ||||
case result_type::Exception: | case result_type::Exception: | ||||
_exception.~exception_ptr(); | _exception.~exception_ptr(); | ||||
break; | break; | ||||
default: | |||||
default: | |||||
break; | break; | ||||
} | } | ||||
} | } |
switch_scheduler_t& operator = (const switch_scheduler_t&) = default; | switch_scheduler_t& operator = (const switch_scheduler_t&) = default; | ||||
switch_scheduler_t& operator = (switch_scheduler_t&&) = default; | switch_scheduler_t& operator = (switch_scheduler_t&&) = default; | ||||
bool await_ready() | |||||
bool await_ready() noexcept | |||||
{ | { | ||||
return false; | return false; | ||||
} | } | ||||
sptr->switch_scheduler_await_suspend(_scheduler, handler); | sptr->switch_scheduler_await_suspend(_scheduler, handler); | ||||
} | } | ||||
void await_resume() | |||||
void await_resume() noexcept | |||||
{ | { | ||||
} | } | ||||
private: | private: |
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | ||||
<ConfigurationType>Application</ConfigurationType> | <ConfigurationType>Application</ConfigurationType> | ||||
<UseDebugLibraries>false</UseDebugLibraries> | <UseDebugLibraries>false</UseDebugLibraries> | ||||
<PlatformToolset>ClangCL</PlatformToolset> | |||||
<PlatformToolset>v142</PlatformToolset> | |||||
<WholeProgramOptimization>true</WholeProgramOptimization> | <WholeProgramOptimization>true</WholeProgramOptimization> | ||||
<CharacterSet>NotSet</CharacterSet> | <CharacterSet>NotSet</CharacterSet> | ||||
</PropertyGroup> | </PropertyGroup> |