generator_iterator& operator++() | generator_iterator& operator++() | ||||
{ | { | ||||
_Coro.resume(); | |||||
if (_Coro.done()) | if (_Coro.done()) | ||||
_Coro = nullptr; | _Coro = nullptr; | ||||
else | |||||
_Coro.resume(); | |||||
return *this; | return *this; | ||||
} | } | ||||
_Ty const* _CurrentValue; | _Ty const* _CurrentValue; | ||||
promise_type() | |||||
{ | |||||
state_type* st = get_state(); | |||||
new(st) state_type(coroutine_handle<promise_type>::from_promise(*this)); | |||||
st->lock(); | |||||
} | |||||
promise_type(promise_type&& _Right) noexcept = default; | |||||
promise_type& operator = (promise_type&& _Right) noexcept = default; | |||||
promise_type(const promise_type&) = delete; | |||||
promise_type& operator = (const promise_type&) = delete; | |||||
promise_type& get_return_object() | promise_type& get_return_object() | ||||
{ | { | ||||
return *this; | return *this; | ||||
return std::forward<_Uty>(_Whatever); | return std::forward<_Uty>(_Whatever); | ||||
} | } | ||||
state_type* get_state() | |||||
{ | |||||
size_t _State_size = _Align_size<state_type>(); | |||||
char* ptr = reinterpret_cast<char*>(this) - _State_size; | |||||
return reinterpret_cast<state_type*>(ptr); | |||||
} | |||||
using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | using _Alloc_char = typename std::allocator_traits<_Alloc>::template rebind_alloc<char>; | ||||
static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>, | static_assert(std::is_same_v<char*, typename std::allocator_traits<_Alloc_char>::pointer>, | ||||
"generator_t does not support allocators with fancy pointer types"); | "generator_t does not support allocators with fancy pointer types"); | ||||
void* operator new(size_t _Size) | void* operator new(size_t _Size) | ||||
{ | { | ||||
size_t _State_size = _Align_size<state_type>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < std::numeric_limits<uint32_t>::max() - sizeof(_State_size)); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "generator_promise::new, size=" << (_Size + _State_size) << std::endl; | |||||
#endif | |||||
_Alloc_char _Al; | _Alloc_char _Al; | ||||
void* ptr = _Al.allocate(_Size); | |||||
return ptr; | |||||
char* ptr = _Al.allocate(_Size + _State_size); | |||||
return ptr + _State_size; | |||||
} | } | ||||
void operator delete(void* _Ptr, size_t _Size) | void operator delete(void* _Ptr, size_t _Size) | ||||
{ | { | ||||
size_t _State_size = _Align_size<state_type>(); | |||||
assert(_Size >= sizeof(uint32_t) && _Size < std::numeric_limits<uint32_t>::max() - sizeof(_State_size)); | |||||
*reinterpret_cast<uint32_t*>(_Ptr) = static_cast<uint32_t>(_Size + _State_size); | |||||
_Alloc_char _Al; | _Alloc_char _Al; | ||||
return _Al.deallocate(static_cast<char*>(_Ptr), _Size); | |||||
state_type* st = reinterpret_cast<state_type*>(static_cast<char*>(_Ptr) - _State_size); | |||||
st->unlock(); | |||||
} | } | ||||
}; | }; | ||||
} | } | ||||
} | } | ||||
coroutine_handle<promise_type> detach() | |||||
state_type* detach_state() | |||||
{ | { | ||||
auto t = _Coro; | auto t = _Coro; | ||||
_Coro = nullptr; | _Coro = nullptr; | ||||
return t; | |||||
return t.promise().get_state(); | |||||
} | } | ||||
private: | private: |
size_t _State_size = _Align_size<state_type>(); | size_t _State_size = _Align_size<state_type>(); | ||||
assert(_Size >= sizeof(uint32_t) && _Size < std::numeric_limits<uint32_t>::max() - sizeof(_State_size)); | assert(_Size >= sizeof(uint32_t) && _Size < std::numeric_limits<uint32_t>::max() - sizeof(_State_size)); | ||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << "promise::new, size=" << (_Size + _State_size) << std::endl; | |||||
std::cout << "future_promise::new, size=" << (_Size + _State_size) << std::endl; | |||||
#endif | #endif | ||||
_Alloc_char _Al; | _Alloc_char _Al; |
protected: | protected: | ||||
void initialize(future_type&& f) | void initialize(future_type&& f) | ||||
{ | { | ||||
_state = new state_type(f.detach()); | |||||
_state = f.detach_state(); | |||||
} | } | ||||
}; | }; | ||||
void state_future_t::destroy_deallocate() | void state_future_t::destroy_deallocate() | ||||
{ | { | ||||
size_t _Size = this->_Alloc_size; | |||||
size_t _Size = this->_alloc_size; | |||||
#if RESUMEF_DEBUG_COUNTER | #if RESUMEF_DEBUG_COUNTER | ||||
std::cout << "destroy_deallocate, size=" << _Size << std::endl; | std::cout << "destroy_deallocate, size=" << _Size << std::endl; | ||||
#endif | #endif | ||||
void state_generator_t::destroy_deallocate() | void state_generator_t::destroy_deallocate() | ||||
{ | { | ||||
delete this; | |||||
size_t _Size = _Align_size<state_generator_t>(); | |||||
char* _Ptr = reinterpret_cast<char*>(this) + _Size; | |||||
_Size = *reinterpret_cast<uint32_t*>(_Ptr); | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "destroy_deallocate, size=" << _Size << std::endl; | |||||
#endif | |||||
this->~state_generator_t(); | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(reinterpret_cast<char*>(this), _Size); | |||||
} | } | ||||
void state_generator_t::resume() | void state_generator_t::resume() | ||||
_coro.resume(); | _coro.resume(); | ||||
if (_coro.done()) | if (_coro.done()) | ||||
{ | { | ||||
coroutine_handle<> handler = _coro; | |||||
_coro = nullptr; | _coro = nullptr; | ||||
_scheduler->del_final(this); | _scheduler->del_final(this); | ||||
handler.destroy(); | |||||
} | } | ||||
else | else | ||||
{ | { |
struct state_base_t | struct state_base_t | ||||
{ | { | ||||
using _Alloc_char = std::allocator<char>; | using _Alloc_char = std::allocator<char>; | ||||
RF_API virtual ~state_base_t(); | |||||
private: | private: | ||||
std::atomic<intptr_t> _count{0}; | std::atomic<intptr_t> _count{0}; | ||||
public: | public: | ||||
// 一、经过co_await操作后,_coro在初始时不会为nullptr。 | // 一、经过co_await操作后,_coro在初始时不会为nullptr。 | ||||
// 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。 | // 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。 | ||||
coroutine_handle<> _coro; | coroutine_handle<> _coro; | ||||
virtual ~state_base_t(); | |||||
private: | private: | ||||
virtual void destroy_deallocate() = 0; | virtual void destroy_deallocate() = 0; | ||||
public: | public: | ||||
struct state_generator_t : public state_base_t | struct state_generator_t : public state_base_t | ||||
{ | { | ||||
public: | |||||
state_generator_t(coroutine_handle<> handler) | state_generator_t(coroutine_handle<> handler) | ||||
{ | { | ||||
_coro = handler; | _coro = handler; | ||||
} | } | ||||
private: | |||||
virtual void destroy_deallocate() override; | virtual void destroy_deallocate() override; | ||||
public: | |||||
virtual void resume() override; | virtual void resume() override; | ||||
virtual bool has_handler() const override; | virtual bool has_handler() const override; | ||||
virtual bool is_ready() const override; | virtual bool is_ready() const override; | ||||
static state_generator_t * _Alloc_state(coroutine_handle<> handler) | |||||
{ | |||||
#if RESUMEF_DEBUG_COUNTER | |||||
std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl; | |||||
#endif | |||||
return new state_generator_t(handler); | |||||
} | |||||
}; | }; | ||||
struct state_future_t : public state_base_t | struct state_future_t : public state_base_t | ||||
intptr_t _id; | intptr_t _id; | ||||
#endif | #endif | ||||
std::exception_ptr _exception; | std::exception_ptr _exception; | ||||
uint32_t _Alloc_size; | |||||
uint32_t _alloc_size; | |||||
bool _has_value = false; | bool _has_value = false; | ||||
bool _is_awaitor; | bool _is_awaitor; | ||||
bool _is_initor = false; | bool _is_initor = false; | ||||
} | } | ||||
void set_alloc_size(uint32_t val) | void set_alloc_size(uint32_t val) | ||||
{ | { | ||||
_Alloc_size = val; | |||||
_alloc_size = val; | |||||
} | } | ||||
void set_exception(std::exception_ptr e); | void set_exception(std::exception_ptr e); | ||||
state_t() :state_future_t() | state_t() :state_future_t() | ||||
{ | { | ||||
_Alloc_size = sizeof(*this); | |||||
_alloc_size = sizeof(*this); | |||||
} | } | ||||
explicit state_t(bool awaitor) :state_future_t(awaitor) | explicit state_t(bool awaitor) :state_future_t(awaitor) | ||||
{ | { | ||||
_Alloc_size = sizeof(*this); | |||||
_alloc_size = sizeof(*this); | |||||
} | } | ||||
private: | private: | ||||
union union_value_type | union union_value_type | ||||
~union_value_type() {} | ~union_value_type() {} | ||||
}; | }; | ||||
union_value_type uv; | union_value_type uv; | ||||
public: | |||||
~state_t() | ~state_t() | ||||
{ | { | ||||
if (_has_value) | if (_has_value) | ||||
uv._value.~value_type(); | uv._value.~value_type(); | ||||
} | } | ||||
public: | |||||
auto future_await_resume() -> value_type; | auto future_await_resume() -> value_type; | ||||
template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | template<class _PromiseT, typename = std::enable_if_t<is_promise_v<_PromiseT>>> | ||||
void promise_yield_value(_PromiseT* promise, value_type val); | void promise_yield_value(_PromiseT* promise, value_type val); | ||||
state_t() :state_future_t() | state_t() :state_future_t() | ||||
{ | { | ||||
_Alloc_size = sizeof(*this); | |||||
_alloc_size = sizeof(*this); | |||||
} | } | ||||
explicit state_t(bool awaitor) :state_future_t(awaitor) | explicit state_t(bool awaitor) :state_future_t(awaitor) | ||||
{ | { | ||||
_Alloc_size = sizeof(*this); | |||||
_alloc_size = sizeof(*this); | |||||
} | } | ||||
public: | public: | ||||
void future_await_resume(); | void future_await_resume(); |
void resumable_main_yield_return() | void resumable_main_yield_return() | ||||
{ | { | ||||
for (int i : test_yield_int()) | |||||
{ | |||||
std::cout << i << " had return" << std::endl; | |||||
} | |||||
go test_yield_int(); | go test_yield_int(); | ||||
this_scheduler()->run_until_notask(); | this_scheduler()->run_until_notask(); | ||||
{ | { | ||||
(void)argc; | (void)argc; | ||||
(void)argv; | (void)argv; | ||||
resumable_main_routine(); | |||||
resumable_main_yield_return(); | |||||
//if (argc > 1) | //if (argc > 1) | ||||
// resumable_main_benchmark_asio_client(atoi(argv[1])); | // resumable_main_benchmark_asio_client(atoi(argv[1])); |