From 7289258a751269de15f7e69d32a10f6b4ca6ab58 Mon Sep 17 00:00:00 2001 From: tearshark Date: Sun, 16 Feb 2020 10:27:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=86=E5=A4=87=E6=94=AF=E6=8C=81=E8=B0=83?= =?UTF-8?q?=E5=BA=A6generator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- librf/src/def.h | 9 +++ librf/src/generator.h | 52 ++++++++-------- librf/src/promise.inl | 4 +- librf/src/scheduler.cpp | 9 ++- librf/src/scheduler.h | 6 +- librf/src/state.cpp | 37 +++++++++++- librf/src/state.h | 90 +++++++++++++--------------- librf/src/state.inl | 10 ++-- tutorial/test_async_yield_return.cpp | 2 +- vs_proj/librf.vcxproj | 6 +- vs_proj/librf.vcxproj.filters | 3 + 11 files changed, 133 insertions(+), 95 deletions(-) diff --git a/librf/src/def.h b/librf/src/def.h index 1747e03..dc6241d 100644 --- a/librf/src/def.h +++ b/librf/src/def.h @@ -67,6 +67,8 @@ namespace resumef template using coroutine_handle = std::experimental::coroutine_handle<_PromiseT>; + template > + using generator_t = std::experimental::generator<_Ty, _Alloc>; enum struct error_code { @@ -151,6 +153,13 @@ namespace resumef template _INLINE_VAR constexpr bool is_future_v = is_future>::value; + template + struct is_generator : std::false_type {}; + template + struct is_generator> : std::true_type {}; + template + _INLINE_VAR constexpr bool is_generator_v = is_generator>::value; + //获得当前线程下的调度器 scheduler_t* this_scheduler(); } diff --git a/librf/src/generator.h b/librf/src/generator.h index 1a8bbfa..08f15cb 100644 --- a/librf/src/generator.h +++ b/librf/src/generator.h @@ -20,7 +20,10 @@ #include -#pragma pack(push, _CRT_PACKING) +#pragma pack(push,_CRT_PACKING) +#pragma warning(push,_STL_WARNING_LEVEL) +#pragma warning(disable: _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new @@ -49,23 +52,18 @@ namespace experimental { generator_iterator &operator++() { + _Coro.resume(); if (_Coro.done()) _Coro = nullptr; - else - _Coro.resume(); return *this; } - generator_iterator operator++(int) = delete; - // generator iterator current_value - // is a reference to a temporary on the coroutine frame - // implementing postincrement will require storing a copy - // of the value in the iterator. - //{ - // auto _Result = *this; - // ++(*this); - // return _Result; - //} + void operator++(int) + { + // This postincrement operator meets the requirements of the Ranges TS + // InputIterator concept, but not those of Standard C++ InputIterator. + ++* this; + } bool operator==(generator_iterator const &right_) const { @@ -92,6 +90,10 @@ namespace experimental { template struct generator_iterator : public generator_iterator { + using value_type = _Ty; + using reference = _Ty const&; + using pointer = _Ty const*; + generator_iterator(nullptr_t) : generator_iterator(nullptr) { } @@ -99,14 +101,14 @@ namespace experimental { { } - _Ty const &operator*() const + reference operator*() const { - return *this->_Coro.promise()._CurrentValue; + return *_Coro.promise()._CurrentValue; } - _Ty const *operator->() const + pointer operator->() const { - return _STD addressof(operator*()); + return _Coro.promise()._CurrentValue; } }; @@ -156,9 +158,11 @@ namespace experimental { return _STD forward<_Uty>(_Whatever); } - using _Alloc_traits = allocator_traits<_Alloc>; - using _Alloc_of_char_type = - typename _Alloc_traits::template rebind_alloc; + using _Alloc_char = _Rebind_alloc_t<_Alloc, char>; + static_assert(is_same_v::pointer>, + "generator does not support allocators with fancy pointer types"); + static_assert(allocator_traits<_Alloc_char>::is_always_equal::value, + "generator only supports stateless allocators"); void *operator new(size_t _Size) { @@ -179,10 +183,9 @@ namespace experimental { { if (_Coro) { + _Coro.resume(); if (_Coro.done()) return{ nullptr }; - - _Coro.resume(); } return { _Coro }; } @@ -193,8 +196,7 @@ namespace experimental { } explicit generator(promise_type &_Prom) - : _Coro(coroutine_handle::from_promise( - _Prom)) + : _Coro(coroutine_handle::from_promise(_Prom)) { } @@ -212,7 +214,7 @@ namespace experimental { generator &operator=(generator &&right_) noexcept { - if (&right_ != this) { + if (this != _STD addressof(right_)) { _Coro = right_._Coro; right_._Coro = nullptr; } diff --git a/librf/src/promise.inl b/librf/src/promise.inl index fd03223..80d5a6c 100644 --- a/librf/src/promise.inl +++ b/librf/src/promise.inl @@ -7,7 +7,7 @@ namespace resumef { struct suspend_on_initial { - state_base_t* _state; + state_future_t* _state; inline bool await_ready() noexcept { @@ -25,7 +25,7 @@ namespace resumef }; struct suspend_on_final { - state_base_t* _state; + state_future_t* _state; inline bool await_ready() noexcept { diff --git a/librf/src/scheduler.cpp b/librf/src/scheduler.cpp index 76fa7e2..a75e4c7 100644 --- a/librf/src/scheduler.cpp +++ b/librf/src/scheduler.cpp @@ -113,7 +113,6 @@ namespace resumef void scheduler_t::add_ready(state_base_t* sptr) { - assert(sptr->get_scheduler() == this); assert(sptr->is_ready()); if (sptr->has_handler()) @@ -123,10 +122,14 @@ namespace resumef } } + void scheduler_t::add_generator(state_base_t* sptr) + { + scoped_lock __guard(_lock_running); + _runing_states.emplace_back(sptr); + } + void scheduler_t::del_final(state_base_t* sptr) { - assert(sptr->get_scheduler() == this); - { scoped_lock __guard(_lock_ready); this->_ready_task.erase(sptr); diff --git a/librf/src/scheduler.h b/librf/src/scheduler.h index 267d0a2..a68e91f 100644 --- a/librf/src/scheduler.h +++ b/librf/src/scheduler.h @@ -49,11 +49,6 @@ namespace resumef new_task(new ctx_task_t<_Ty>(std::forward<_Ty>(t_))); } - inline void push_task_internal(task_base_t * t_) - { - new_task(t_); - } - inline bool empty() const { scoped_lock __guard(_lock_ready, _lock_running); @@ -68,6 +63,7 @@ namespace resumef void add_initial(state_base_t* sptr); void add_await(state_base_t* sptr); void add_ready(state_base_t* sptr); + void add_generator(state_base_t* sptr); void del_final(state_base_t* sptr); friend struct task_base; diff --git a/librf/src/state.cpp b/librf/src/state.cpp index b6f4f77..d9a26af 100644 --- a/librf/src/state.cpp +++ b/librf/src/state.cpp @@ -9,7 +9,29 @@ namespace resumef { } - void state_base_t::resume() + void state_generator_t::resume() + { + if (_coro != nullptr) + { + _coro.resume(); + if (_coro.done()) + _coro = nullptr; + else + _scheduler->add_generator(this); + } + } + + bool state_generator_t::is_ready() const + { + return _coro != nullptr && !_coro.done(); + } + + bool state_generator_t::has_handler() const + { + return _coro != nullptr; + } + + void state_future_t::resume() { coroutine_handle<> handler; @@ -28,7 +50,12 @@ namespace resumef } } - void state_base_t::set_exception(std::exception_ptr e) + bool state_future_t::has_handler() const + { + return _initor != nullptr || _coro != nullptr; + } + + void state_future_t::set_exception(std::exception_ptr e) { scoped_lock __guard(this->_mtx); @@ -37,6 +64,12 @@ namespace resumef if (sch != nullptr) sch->add_ready(this); } + + bool state_t::is_ready() const + { + scoped_lock __guard(this->_mtx); + return _is_awaitor == false || _has_value || _exception != nullptr; + } void state_t::future_await_resume() { diff --git a/librf/src/state.h b/librf/src/state.h index 5076ad7..a8a3b80 100644 --- a/librf/src/state.h +++ b/librf/src/state.h @@ -10,25 +10,50 @@ namespace resumef { struct state_base_t : public counted_t { - typedef std::recursive_mutex lock_type; - + RF_API virtual ~state_base_t(); protected: - mutable lock_type _mtx; scheduler_t* _scheduler = nullptr; - coroutine_handle<> _initor; //可能来自协程里的promise产生的,则经过co_await操作后,_coro在初始时不会为nullptr。 //也可能来自awaitable_t,如果 // 一、经过co_await操作后,_coro在初始时不会为nullptr。 // 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。 coroutine_handle<> _coro; + public: + virtual void resume() = 0; + virtual bool is_ready() const = 0; + virtual bool has_handler() const = 0; + + void set_scheduler(scheduler_t* sch) + { + _scheduler = sch; + } + coroutine_handle<> get_handler() const + { + return _coro; + } + }; + + struct state_generator_t : public state_base_t + { + virtual void resume() override; + virtual bool is_ready() const override; + virtual bool has_handler() const override; + }; + + struct state_future_t : public state_base_t + { + typedef std::recursive_mutex lock_type; + protected: + mutable lock_type _mtx; + coroutine_handle<> _initor; std::exception_ptr _exception; - state_base_t* _parent = nullptr; + state_future_t* _parent = nullptr; #if RESUMEF_DEBUG_COUNTER intptr_t _id; #endif bool _is_awaitor; public: - state_base_t(bool awaitor) + state_future_t(bool awaitor) { #if RESUMEF_DEBUG_COUNTER _id = ++g_resumef_state_id; @@ -36,41 +61,13 @@ namespace resumef _is_awaitor = awaitor; } - RF_API virtual ~state_base_t(); - virtual bool has_value() const = 0; - void resume(); - - bool is_ready() const - { - return _is_awaitor == false || has_value() || _exception != nullptr; - } - - coroutine_handle<> get_handler() const - { - return _coro; - } - bool has_handler() const - { - return _initor != nullptr || _coro != nullptr; - } + virtual void resume() override; + virtual bool has_handler() const override; scheduler_t* get_scheduler() const { return _parent ? _parent->get_scheduler() : _scheduler; } - void set_scheduler(scheduler_t* sch) - { - scoped_lock __guard(_mtx); - _scheduler = sch; - } - void set_scheduler_handler(scheduler_t* sch, coroutine_handle<> handler) - { - scoped_lock __guard(_mtx); - _scheduler = sch; - - assert(_coro == nullptr); - _coro = handler; - } state_base_t * get_parent() const { @@ -90,18 +87,18 @@ namespace resumef }; template - struct state_t : public state_base_t + struct state_t : public state_future_t { - using state_base_t::state_base_t; - using state_base_t::lock_type; + using state_future_t::state_future_t; + using state_future_t::lock_type; using value_type = _Ty; protected: std::optional _value; public: - virtual bool has_value() const override + virtual bool is_ready() const override { scoped_lock __guard(this->_mtx); - return _value.has_value(); + return _is_awaitor == false || _value.has_value() || _exception != nullptr; } bool future_await_ready() @@ -116,17 +113,14 @@ namespace resumef }; template<> - struct state_t : public state_base_t + struct state_t : public state_future_t { - using state_base_t::state_base_t; - using state_base_t::lock_type; + using state_future_t::state_future_t; + using state_future_t::lock_type; protected: std::atomic _has_value{ false }; public: - virtual bool has_value() const override - { - return _has_value; - } + virtual bool is_ready() const override; bool future_await_ready() { diff --git a/librf/src/state.inl b/librf/src/state.inl index ad282b8..65c1f89 100644 --- a/librf/src/state.inl +++ b/librf/src/state.inl @@ -3,7 +3,7 @@ namespace resumef { template - inline void state_base_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) + inline void state_future_t::promise_initial_suspend(coroutine_handle<_PromiseT> handler) { _PromiseT& promise = handler.promise(); @@ -14,12 +14,12 @@ namespace resumef this->_initor = handler; } - inline void state_base_t::promise_await_resume() + inline void state_future_t::promise_await_resume() { } template - inline void state_base_t::promise_final_suspend(coroutine_handle<_PromiseT> handler) + inline void state_future_t::promise_final_suspend(coroutine_handle<_PromiseT> handler) { scoped_lock __guard(this->_mtx); @@ -34,13 +34,13 @@ namespace resumef } template - inline void state_base_t::future_await_suspend(coroutine_handle<_PromiseT> handler) + inline void state_future_t::future_await_suspend(coroutine_handle<_PromiseT> handler) { scoped_lock __guard(this->_mtx); _PromiseT& promise = handler.promise(); - state_base_t* parent_state = promise._state.get(); + auto* parent_state = promise._state.get(); scheduler_t* sch = parent_state->get_scheduler(); if (this != parent_state) { diff --git a/tutorial/test_async_yield_return.cpp b/tutorial/test_async_yield_return.cpp index ca0c3b4..aec2a32 100644 --- a/tutorial/test_async_yield_return.cpp +++ b/tutorial/test_async_yield_return.cpp @@ -19,7 +19,7 @@ auto test_yield_int() -> std::experimental::generator std::cout << "3 will yield return" << std::endl; co_yield 3; std::cout << "4 will return" << std::endl; - return 4; + co_return 4; std::cout << "5 will never yield return" << std::endl; co_yield 5; diff --git a/vs_proj/librf.vcxproj b/vs_proj/librf.vcxproj index 82e1241..32f3c87 100644 --- a/vs_proj/librf.vcxproj +++ b/vs_proj/librf.vcxproj @@ -263,10 +263,7 @@ true true - - true - true - + Default false @@ -282,6 +279,7 @@ + diff --git a/vs_proj/librf.vcxproj.filters b/vs_proj/librf.vcxproj.filters index 3327ba3..d654d18 100644 --- a/vs_proj/librf.vcxproj.filters +++ b/vs_proj/librf.vcxproj.filters @@ -174,6 +174,9 @@ librf\src + + librf\src +