diff --git a/src/entt/process/scheduler.hpp b/src/entt/process/scheduler.hpp index c6bd97eb2f..6d4dc79280 100644 --- a/src/entt/process/scheduler.hpp +++ b/src/entt/process/scheduler.hpp @@ -2,16 +2,71 @@ #define ENTT_PROCESS_SCHEDULER_HPP #include +#include #include #include #include #include -#include #include "fwd.hpp" #include "process.hpp" namespace entt { +/** + * @cond TURN_OFF_DOXYGEN + * Internal details not to be documented. + */ + +namespace internal { + +template +struct process_handler { + using instance_type = std::unique_ptr; + using update_fn_type = bool(process_handler &, const Delta, void *); + using abort_fn_type = void(process_handler &, bool); + using next_type = std::unique_ptr; + + template + static process_handler from(Proc &&proc) { + return { + {new Proc{std::forward(proc)}, +[](void *proc) { delete static_cast(proc); }}, + +[](process_handler &handler, const Delta delta, void *data) { + auto *process = static_cast(handler.instance.get()); + process->tick(delta, data); + + if(process->rejected()) { + return true; + } else if(process->finished()) { + if(handler.next) { + handler = std::move(*handler.next); + // forces the process to exit the uninitialized state + return handler.update(handler, {}, nullptr); + } + + return true; + } + + return false; + }, + +[](process_handler &handler, const bool immediately) { + static_cast(handler.instance.get())->abort(immediately); + }, + nullptr}; + } + + instance_type instance; + update_fn_type *update; + abort_fn_type *abort; + next_type next; +}; + +} // namespace internal + +/** + * Internal details not to be documented. + * @endcond + */ + /** * @brief Cooperative scheduler for processes. * @@ -40,27 +95,16 @@ namespace entt { */ template class basic_scheduler { - struct process_handler { - using instance_type = std::unique_ptr; - using update_fn_type = bool(basic_scheduler &, std::size_t, Delta, void *); - using abort_fn_type = void(basic_scheduler &, std::size_t, bool); - using next_type = std::unique_ptr; - - instance_type instance; - update_fn_type *update; - abort_fn_type *abort; - next_type next; - }; + using handler_type = internal::process_handler; struct continuation { - continuation(process_handler *ref) noexcept + continuation(handler_type *ref) noexcept : handler{ref} {} template continuation then(Args &&...args) { static_assert(std::is_base_of_v, Proc>, "Invalid process type"); - auto proc = typename process_handler::instance_type{new Proc{std::forward(args)...}, &basic_scheduler::deleter}; - handler->next.reset(new process_handler{std::move(proc), &basic_scheduler::update, &basic_scheduler::abort, nullptr}); + handler->next.reset(new handler_type{handler_type::from(Proc{std::forward(args)...})}); handler = handler->next.get(); return *this; } @@ -71,39 +115,9 @@ class basic_scheduler { } private: - process_handler *handler; + handler_type *handler; }; - template - [[nodiscard]] static bool update(basic_scheduler &owner, std::size_t pos, const Delta delta, void *data) { - auto *process = static_cast(owner.handlers[pos].instance.get()); - process->tick(delta, data); - - if(process->rejected()) { - return true; - } else if(process->finished()) { - if(auto &&handler = owner.handlers[pos]; handler.next) { - handler = std::move(*handler.next); - // forces the process to exit the uninitialized state - return handler.update(owner, pos, {}, nullptr); - } - - return true; - } - - return false; - } - - template - static void abort(basic_scheduler &owner, std::size_t pos, const bool immediately) { - static_cast(owner.handlers[pos].instance.get())->abort(immediately); - } - - template - static void deleter(void *proc) { - delete static_cast(proc); - } - public: /*! @brief Unsigned integer type. */ using delta_type = Delta; @@ -112,7 +126,8 @@ class basic_scheduler { /*! @brief Default constructor. */ basic_scheduler() - : handlers{} {} + : handlers{} { + } /*! @brief Default move constructor. */ basic_scheduler(basic_scheduler &&) = default; @@ -174,10 +189,9 @@ class basic_scheduler { template auto attach(Args &&...args) { static_assert(std::is_base_of_v, Proc>, "Invalid process type"); - auto proc = typename process_handler::instance_type{new Proc{std::forward(args)...}, &basic_scheduler::deleter}; - auto &&ref = handlers.emplace_back(process_handler{std::move(proc), &basic_scheduler::update, &basic_scheduler::abort, nullptr}); + auto &ref = handlers.emplace_back(handler_type::from(Proc{std::forward(args)...})); // forces the process to exit the uninitialized state - ref.update(*this, handlers.size() - 1u, {}, nullptr); + ref.update(ref, {}, nullptr); return continuation{&handlers.back()}; } @@ -251,10 +265,10 @@ class basic_scheduler { */ void update(const delta_type delta, void *data = nullptr) { for(auto pos = handlers.size(); pos; --pos) { - const auto curr = pos - 1u; + auto &curr = handlers[pos - 1u]; - if(const auto dead = handlers[curr].update(*this, curr, delta, data); dead) { - std::swap(handlers[curr], handlers.back()); + if(const auto dead = curr.update(curr, delta, data); dead) { + std::swap(curr, handlers.back()); handlers.pop_back(); } } @@ -272,13 +286,13 @@ class basic_scheduler { */ void abort(const bool immediately = false) { for(auto pos = handlers.size(); pos; --pos) { - const auto curr = pos - 1u; - handlers[curr].abort(*this, curr, immediately); + auto &curr = handlers[pos - 1u]; + curr.abort(curr, immediately); } } private: - std::vector handlers{}; + std::deque handlers{}; }; } // namespace entt