template<typename _PromiseT = void> | template<typename _PromiseT = void> | ||||
using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; | ||||
template <typename _Ty, typename _Alloc = std::allocator<char>> | |||||
template <typename _Ty = std::nullptr_t, typename _Alloc = std::allocator<char>> | |||||
using generator_t = std::experimental::generator<_Ty, _Alloc>; | using generator_t = std::experimental::generator<_Ty, _Alloc>; | ||||
enum struct error_code | enum struct error_code |
void *operator new(size_t _Size) | void *operator new(size_t _Size) | ||||
{ | { | ||||
_Alloc_of_char_type _Al; | |||||
_Alloc_char _Al; | |||||
return _Al.allocate(_Size); | return _Al.allocate(_Size); | ||||
} | } | ||||
void operator delete(void *_Ptr, size_t _Size) | void operator delete(void *_Ptr, size_t _Size) | ||||
{ | { | ||||
_Alloc_of_char_type _Al; | |||||
_Alloc_char _Al; | |||||
return _Al.deallocate(static_cast<char *>(_Ptr), _Size); | return _Al.deallocate(static_cast<char *>(_Ptr), _Size); | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
} | } | ||||
coroutine_handle<promise_type> detach() | |||||
{ | |||||
auto t = _Coro; | |||||
_Coro = nullptr; | |||||
return t; | |||||
} | |||||
private: | private: | ||||
coroutine_handle<promise_type> _Coro = nullptr; | coroutine_handle<promise_type> _Coro = nullptr; | ||||
}; | }; |
RF_API task_base_t(); | RF_API task_base_t(); | ||||
RF_API virtual ~task_base_t(); | RF_API virtual ~task_base_t(); | ||||
virtual state_base_t * get_state() const = 0; | |||||
state_base_t* get_state() const | |||||
{ | |||||
return _state.get(); | |||||
} | |||||
protected: | |||||
counted_ptr<state_base_t> _state; | |||||
public: | |||||
task_base_t* _next_node; | task_base_t* _next_node; | ||||
task_base_t* _prev_node; | task_base_t* _prev_node; | ||||
}; | }; | ||||
using future_type = future_t<value_type>; | using future_type = future_t<value_type>; | ||||
using state_type = state_t<value_type>; | using state_type = state_t<value_type>; | ||||
counted_ptr<state_type> _state; | |||||
task_t() = default; | task_t() = default; | ||||
task_t(future_type && f) | task_t(future_type && f) | ||||
: _state(std::move(f._state)) | |||||
{ | { | ||||
initialize(std::forward<future_type>(f)); | |||||
} | } | ||||
protected: | |||||
void initialize(future_type&& f) | |||||
{ | |||||
_state = f._state.get(); | |||||
} | |||||
}; | |||||
virtual state_base_t * get_state() const | |||||
template<class _Ty> | |||||
struct task_t<generator_t<_Ty>> : public task_base_t | |||||
{ | |||||
using value_type = _Ty; | |||||
using future_type = generator_t<value_type>; | |||||
using state_type = state_generator_t; | |||||
task_t() = default; | |||||
task_t(future_type&& f) | |||||
{ | { | ||||
return _state.get(); | |||||
initialize(std::forward<future_type>(f)); | |||||
} | |||||
protected: | |||||
void initialize(future_type&& f) | |||||
{ | |||||
_state = new state_type(f.detach()); | |||||
} | } | ||||
}; | }; | ||||
//这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型 | //这个'函数对象'被调用后,返回generator<_Ty>/future_t<_Ty>类型 | ||||
//然后'函数对象'作为异步执行的上下文状态保存起来 | //然后'函数对象'作为异步执行的上下文状态保存起来 | ||||
template<class _Ctx> | template<class _Ctx> | ||||
struct ctx_task_t : public task_base_t | |||||
struct ctx_task_t : public task_t<typename std::remove_cvref<decltype(std::declval<_Ctx>()())>::type> | |||||
{ | { | ||||
using context_type = _Ctx; | using context_type = _Ctx; | ||||
using future_type = typename std::remove_cvref<decltype(std::declval<_Ctx>()())>::type; | |||||
using value_type = typename future_type::value_type; | |||||
using state_type = state_t<value_type>; | |||||
context_type _context; | context_type _context; | ||||
counted_ptr<state_type> _state; | |||||
ctx_task_t(context_type ctx) | ctx_task_t(context_type ctx) | ||||
: _context(std::move(ctx)) | : _context(std::move(ctx)) | ||||
{ | { | ||||
_state = _context()._state; | |||||
} | |||||
virtual state_base_t* get_state() const | |||||
{ | |||||
return _state.get(); | |||||
this->initialize(_context()); | |||||
} | } | ||||
}; | }; | ||||
} | } |
RF_API void run(); | RF_API void run(); | ||||
//RF_API void break_all(); | //RF_API void break_all(); | ||||
template<class _Ty, typename = std::enable_if_t<std::is_callable_v<_Ty> || is_future_v<_Ty>>> | |||||
template<class _Ty, typename = std::enable_if_t<std::is_callable_v<_Ty> || is_future_v<_Ty> || is_generator_v<_Ty> >> | |||||
inline void operator + (_Ty && t_) | inline void operator + (_Ty && t_) | ||||
{ | { | ||||
if constexpr(is_future_v<_Ty>) | |||||
new_task(new task_t<_Ty>(std::forward<_Ty>(t_))); | |||||
else | |||||
if constexpr(std::is_callable_v<_Ty>) | |||||
new_task(new ctx_task_t<_Ty>(std::forward<_Ty>(t_))); | new_task(new ctx_task_t<_Ty>(std::forward<_Ty>(t_))); | ||||
else | |||||
new_task(new task_t<_Ty>(std::forward<_Ty>(t_))); | |||||
} | } | ||||
inline bool empty() const | inline bool empty() const |
{ | { | ||||
_coro.resume(); | _coro.resume(); | ||||
if (_coro.done()) | if (_coro.done()) | ||||
{ | |||||
_coro = nullptr; | _coro = nullptr; | ||||
_scheduler->del_final(this); | |||||
} | |||||
else | else | ||||
{ | |||||
_scheduler->add_generator(this); | _scheduler->add_generator(this); | ||||
} | |||||
} | } | ||||
} | } | ||||
coroutine_handle<> _coro; | coroutine_handle<> _coro; | ||||
public: | public: | ||||
virtual void resume() = 0; | virtual void resume() = 0; | ||||
virtual bool is_ready() const = 0; | |||||
virtual bool has_handler() const = 0; | virtual bool has_handler() const = 0; | ||||
virtual bool is_ready() const = 0; | |||||
void set_scheduler(scheduler_t* sch) | void set_scheduler(scheduler_t* sch) | ||||
{ | { | ||||
struct state_generator_t : public state_base_t | struct state_generator_t : public state_base_t | ||||
{ | { | ||||
public: | |||||
state_generator_t(coroutine_handle<> handler) | |||||
{ | |||||
_coro = handler; | |||||
} | |||||
virtual void resume() override; | virtual void resume() override; | ||||
virtual bool is_ready() const override; | |||||
virtual bool has_handler() const override; | virtual bool has_handler() const override; | ||||
virtual bool is_ready() const override; | |||||
}; | }; | ||||
struct state_future_t : public state_base_t | struct state_future_t : public state_base_t |
{ | { | ||||
for (intptr_t i = 0; i < N / coro; ++i) | for (intptr_t i = 0; i < N / coro; ++i) | ||||
co_yield i; | co_yield i; | ||||
return N / coro; | |||||
co_return N / coro; | |||||
}; | }; | ||||
} | } | ||||
auto middle = std::chrono::steady_clock::now(); | auto middle = std::chrono::steady_clock::now(); |
using namespace resumef; | using namespace resumef; | ||||
//std::experimental::generator<int> | |||||
auto test_yield_int() -> std::experimental::generator<int> | |||||
auto test_yield_int() -> generator_t<int> | |||||
{ | { | ||||
std::cout << "1 will yield return" << std::endl; | std::cout << "1 will yield return" << std::endl; | ||||
co_yield 1; | co_yield 1; | ||||
} | } | ||||
*/ | */ | ||||
auto test_yield_void() -> std::experimental::generator<std::nullptr_t> | |||||
auto test_yield_void() -> generator_t<> | |||||
{ | { | ||||
std::cout << "block 1 will yield return" << std::endl; | std::cout << "block 1 will yield return" << std::endl; | ||||
co_yield_void; | co_yield_void; |
{ | { | ||||
//resumable_main_cb(); | //resumable_main_cb(); | ||||
//resumable_main_suspend_always(); | //resumable_main_suspend_always(); | ||||
resumable_main_routine(); | |||||
//resumable_main_yield_return(); | |||||
resumable_main_resumable(); | |||||
//resumable_main_routine(); | |||||
//resumable_main_exception(); | //resumable_main_exception(); | ||||
/* | /* | ||||
resumable_main_resumable(); | |||||
resumable_main_benchmark_mem(); | resumable_main_benchmark_mem(); | ||||
if (argc > 1) | if (argc > 1) | ||||
resumable_main_benchmark_asio_client(atoi(argv[1])); | resumable_main_benchmark_asio_client(atoi(argv[1])); | ||||
resumable_main_when_all(); | resumable_main_when_all(); | ||||
resumable_main_multi_thread(); | resumable_main_multi_thread(); | ||||
resumable_main_yield_return(); | |||||
resumable_main_timer(); | resumable_main_timer(); | ||||
resumable_main_sleep(); | resumable_main_sleep(); | ||||
resumable_main_resumable(); | |||||
resumable_main_mutex(); | resumable_main_mutex(); | ||||
resumable_main_event(); | resumable_main_event(); | ||||
resumable_main_event_timeout(); | resumable_main_event_timeout(); |
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | ||||
</ClCompile> | </ClCompile> | ||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp"> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | |||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> | |||||
</ClCompile> | |||||
<ClCompile Include="..\tutorial\test_async_resumable.cpp" /> | |||||
<ClCompile Include="..\tutorial\test_async_routine.cpp" /> | <ClCompile Include="..\tutorial\test_async_routine.cpp" /> | ||||
<ClCompile Include="..\tutorial\test_async_sleep.cpp"> | <ClCompile Include="..\tutorial\test_async_sleep.cpp"> | ||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> | <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> |