From ac885a51ef97ed28b47054347aca41540091d69d Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 13 Dec 2018 01:13:14 +0700 Subject: [PATCH] remove invoke module. use jobber and scheduler from promise.hpp. --- .gitmodules | 3 - .../{invoke.hpp => promise.hpp}/invoke.hpp | 2 +- headers/3rdparty/promise.hpp/jobber.hpp | 2 +- headers/3rdparty/promise.hpp/promise.hpp | 251 +----------------- headers/3rdparty/promise.hpp/scheduler.hpp | 2 +- headers/enduro2d/base/_base.hpp | 6 +- headers/enduro2d/base/stdex.hpp | 14 +- headers/enduro2d/core/engine.hpp | 4 +- headers/enduro2d/core/vfs.hpp | 2 +- headers/enduro2d/utils/_all.hpp | 2 - headers/enduro2d/utils/_utils.hpp | 2 - headers/enduro2d/utils/jobber.hpp | 237 ----------------- headers/enduro2d/utils/scheduler.hpp | 196 -------------- modules/invoke.hpp | 1 - scripts/update_modules.sh | 4 +- sources/enduro2d/core/engine.cpp | 10 +- sources/enduro2d/core/vfs.cpp | 5 +- sources/enduro2d/utils/jobber.cpp | 108 -------- sources/enduro2d/utils/scheduler.cpp | 51 ---- untests/sources/untests_utils/jobber.cpp | 167 ------------ untests/sources/untests_utils/scheduler.cpp | 80 ------ 21 files changed, 24 insertions(+), 1125 deletions(-) rename headers/3rdparty/{invoke.hpp => promise.hpp}/invoke.hpp (99%) delete mode 100644 headers/enduro2d/utils/jobber.hpp delete mode 100644 headers/enduro2d/utils/scheduler.hpp delete mode 160000 modules/invoke.hpp delete mode 100644 sources/enduro2d/utils/jobber.cpp delete mode 100644 sources/enduro2d/utils/scheduler.cpp delete mode 100644 untests/sources/untests_utils/jobber.cpp delete mode 100644 untests/sources/untests_utils/scheduler.cpp diff --git a/.gitmodules b/.gitmodules index 9942b400..dc65c402 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,9 +25,6 @@ [submodule "toolset/model_converter/modules/assimp"] path = toolset/model_converter/modules/assimp url = https://github.com/assimp/assimp -[submodule "modules/invoke.hpp"] - path = modules/invoke.hpp - url = https://github.com/BlackMATov/invoke.hpp [submodule "modules/promise.hpp"] path = modules/promise.hpp url = https://github.com/BlackMATov/promise.hpp diff --git a/headers/3rdparty/invoke.hpp/invoke.hpp b/headers/3rdparty/promise.hpp/invoke.hpp similarity index 99% rename from headers/3rdparty/invoke.hpp/invoke.hpp rename to headers/3rdparty/promise.hpp/invoke.hpp index 4df38aa4..01d2f138 100644 --- a/headers/3rdparty/invoke.hpp/invoke.hpp +++ b/headers/3rdparty/promise.hpp/invoke.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "invoke.hpp" + * This file is part of the "https://github.com/blackmatov/invoke.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ diff --git a/headers/3rdparty/promise.hpp/jobber.hpp b/headers/3rdparty/promise.hpp/jobber.hpp index 4cef5289..4a21c119 100644 --- a/headers/3rdparty/promise.hpp/jobber.hpp +++ b/headers/3rdparty/promise.hpp/jobber.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ diff --git a/headers/3rdparty/promise.hpp/promise.hpp b/headers/3rdparty/promise.hpp/promise.hpp index 62678a80..79a5663b 100644 --- a/headers/3rdparty/promise.hpp/promise.hpp +++ b/headers/3rdparty/promise.hpp/promise.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ @@ -23,254 +23,7 @@ #include #include -// -// invoke.hpp -// https://github.com/BlackMATov/invoke.hpp -// - -namespace promise_hpp -{ - #define INVOKE_HPP_NOEXCEPT_RETURN(...) \ - noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; } - - #define INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \ - noexcept(noexcept(__VA_ARGS__)) -> decltype (__VA_ARGS__) { return __VA_ARGS__; } - - // - // void_t - // - - namespace invoke_hpp - { - namespace impl - { - template < typename... Args > - struct make_void { - using type = void; - }; - } - - template < typename... Args > - using void_t = typename impl::make_void::type; - } - - // - // is_reference_wrapper - // - - namespace invoke_hpp - { - namespace impl - { - template < typename T > - struct is_reference_wrapper_impl - : std::false_type {}; - - template < typename U > - struct is_reference_wrapper_impl> - : std::true_type {}; - } - - template < typename T > - struct is_reference_wrapper - : impl::is_reference_wrapper_impl> {}; - } - - // - // invoke - // - - namespace invoke_hpp - { - namespace impl - { - // - // invoke_member_object_impl - // - - template - < - typename Base, typename F, typename Derived, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_object_impl(F Base::* f, Derived&& ref) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - std::forward(ref).*f) - - template - < - typename Base, typename F, typename RefWrap, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_object_impl(F Base::* f, RefWrap&& ref) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - ref.get().*f) - - template - < - typename Base, typename F, typename Pointer, - typename std::enable_if_t< - !std::is_base_of>::value && - !is_reference_wrapper>::value - , int> = 0 - > - constexpr auto invoke_member_object_impl(F Base::* f, Pointer&& ptr) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - (*std::forward(ptr)).*f) - - // - // invoke_member_function_impl - // - - template - < - typename Base, typename F, typename Derived, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_function_impl(F Base::* f, Derived&& ref, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - (std::forward(ref).*f)(std::forward(args)...)) - - template - < - typename Base, typename F, typename RefWrap, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke_member_function_impl(F Base::* f, RefWrap&& ref, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - (ref.get().*f)(std::forward(args)...)) - - template - < - typename Base, typename F, typename Pointer, typename... Args, - typename std::enable_if_t< - !std::is_base_of>::value && - !is_reference_wrapper>::value - , int> = 0 - > - constexpr auto invoke_member_function_impl(F Base::* f, Pointer&& ptr, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - ((*std::forward(ptr)).*f)(std::forward(args)...)) - } - - template - < - typename F, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke(F&& f, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - std::forward(f)(std::forward(args)...)) - - template - < - typename F, typename T, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke(F&& f, T&& t) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - impl::invoke_member_object_impl(std::forward(f), std::forward(t))) - - template - < - typename F, typename... Args, - typename std::enable_if_t>::value, int> = 0 - > - constexpr auto invoke(F&& f, Args&&... args) - INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN( - impl::invoke_member_function_impl(std::forward(f), std::forward(args)...)) - } - - // - // invoke_result - // - - namespace invoke_hpp - { - namespace impl - { - struct invoke_result_impl_tag {}; - - template < typename Void, typename F, typename... Args > - struct invoke_result_impl {}; - - template < typename F, typename... Args > - struct invoke_result_impl(), std::declval()...))>, F, Args...> { - using type = decltype(invoke_hpp::invoke(std::declval(), std::declval()...)); - }; - } - - template < typename F, typename... Args > - struct invoke_result - : impl::invoke_result_impl {}; - - template < typename F, typename... Args > - using invoke_result_t = typename invoke_result::type; - } - - // - // is_invocable - // - - namespace invoke_hpp - { - namespace impl - { - struct is_invocable_r_impl_tag {}; - - template < typename Void, typename R, typename F, typename... Args > - struct is_invocable_r_impl - : std::false_type {}; - - template < typename R, typename F, typename... Args > - struct is_invocable_r_impl>, R, F, Args...> - : std::conditional_t< - std::is_void::value, - std::true_type, - std::is_convertible, R>> {}; - } - - template < typename R, typename F, typename... Args > - struct is_invocable_r - : impl::is_invocable_r_impl {}; - - template < typename F, typename... Args > - using is_invocable = is_invocable_r; - } - - // - // apply - // - - namespace invoke_hpp - { - namespace impl - { - template < typename F, typename Tuple, std::size_t... I > - constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence) - INVOKE_HPP_NOEXCEPT_RETURN( - invoke_hpp::invoke( - std::forward(f), - std::get(std::forward(args))...)) - } - - template < typename F, typename Tuple > - constexpr decltype(auto) apply(F&& f, Tuple&& args) - INVOKE_HPP_NOEXCEPT_RETURN( - impl::apply_impl( - std::forward(f), - std::forward(args), - std::make_index_sequence>::value>())) - } - - #undef INVOKE_HPP_NOEXCEPT_RETURN - #undef INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN -} - -// -// promise.hpp -// https://github.com/BlackMATov/promise.hpp -// +#include "invoke.hpp" namespace promise_hpp { diff --git a/headers/3rdparty/promise.hpp/scheduler.hpp b/headers/3rdparty/promise.hpp/scheduler.hpp index 303fa577..97af654a 100644 --- a/headers/3rdparty/promise.hpp/scheduler.hpp +++ b/headers/3rdparty/promise.hpp/scheduler.hpp @@ -1,5 +1,5 @@ /******************************************************************************* - * This file is part of the "promise.hpp" + * This file is part of the "https://github.com/blackmatov/promise.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018 Matvey Cherevko ******************************************************************************/ diff --git a/headers/enduro2d/base/_base.hpp b/headers/enduro2d/base/_base.hpp index d26276aa..b183f366 100644 --- a/headers/enduro2d/base/_base.hpp +++ b/headers/enduro2d/base/_base.hpp @@ -43,6 +43,8 @@ #include #include -#include <3rdparty/invoke.hpp/invoke.hpp> -#include <3rdparty/promise.hpp/promise.hpp> #include <3rdparty/variant/variant.hpp> +#include <3rdparty/promise.hpp/invoke.hpp> +#include <3rdparty/promise.hpp/jobber.hpp> +#include <3rdparty/promise.hpp/promise.hpp> +#include <3rdparty/promise.hpp/scheduler.hpp> diff --git a/headers/enduro2d/base/stdex.hpp b/headers/enduro2d/base/stdex.hpp index 0b2809b0..5dd6b629 100644 --- a/headers/enduro2d/base/stdex.hpp +++ b/headers/enduro2d/base/stdex.hpp @@ -9,7 +9,7 @@ #include "macros.hpp" // -// variant +// https://github.com/mpark/variant // namespace e2d { namespace stdex @@ -18,21 +18,15 @@ namespace e2d { namespace stdex }} // -// invoke +// https://github.com/blackmatov/promise.hpp // namespace e2d { namespace stdex { using namespace invoke_hpp; -}} - -// -// promise -// - -namespace e2d { namespace stdex -{ + using namespace jobber_hpp; using namespace promise_hpp; + using namespace scheduler_hpp; }} // diff --git a/headers/enduro2d/core/engine.hpp b/headers/enduro2d/core/engine.hpp index 34da425e..ad29a134 100644 --- a/headers/enduro2d/core/engine.hpp +++ b/headers/enduro2d/core/engine.hpp @@ -126,8 +126,8 @@ namespace e2d u32 frame_count() const noexcept; f32 realtime_time() const noexcept; - scheduler& main_thread_scheduler() noexcept; - const scheduler& main_thread_scheduler() const noexcept; + stdex::scheduler& main_thread_scheduler() noexcept; + const stdex::scheduler& main_thread_scheduler() const noexcept; private: class internal_state; std::unique_ptr state_; diff --git a/headers/enduro2d/core/vfs.hpp b/headers/enduro2d/core/vfs.hpp index efba595c..8342c4c8 100644 --- a/headers/enduro2d/core/vfs.hpp +++ b/headers/enduro2d/core/vfs.hpp @@ -46,7 +46,7 @@ namespace e2d input_stream_uptr open(const url& url) const; std::pair load(const url& url) const; output_stream_uptr write(const url& url, bool append) const; - std::future> load_async(const url& url) const; + stdex::promise> load_async(const url& url) const; template < typename Iter > bool extract(const url& url, Iter result_iter) const; diff --git a/headers/enduro2d/utils/_all.hpp b/headers/enduro2d/utils/_all.hpp index 7df6d4d6..a1a97ade 100644 --- a/headers/enduro2d/utils/_all.hpp +++ b/headers/enduro2d/utils/_all.hpp @@ -14,11 +14,9 @@ #include "filesystem.hpp" #include "filesystem.inl" #include "image.hpp" -#include "jobber.hpp" #include "mesh.hpp" #include "module.hpp" #include "path.hpp" -#include "scheduler.hpp" #include "streams.hpp" #include "strfmts.hpp" #include "strings.hpp" diff --git a/headers/enduro2d/utils/_utils.hpp b/headers/enduro2d/utils/_utils.hpp index 7506c251..5e3e3778 100644 --- a/headers/enduro2d/utils/_utils.hpp +++ b/headers/enduro2d/utils/_utils.hpp @@ -15,9 +15,7 @@ namespace e2d class color; class color32; class image; - class jobber; class mesh; - class scheduler; class input_stream; class output_stream; class input_sequence; diff --git a/headers/enduro2d/utils/jobber.hpp b/headers/enduro2d/utils/jobber.hpp deleted file mode 100644 index edd6f323..00000000 --- a/headers/enduro2d/utils/jobber.hpp +++ /dev/null @@ -1,237 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018 Matvey Cherevko - ******************************************************************************/ - -#pragma once - -#include "_utils.hpp" -#include "time.hpp" - -namespace e2d -{ - class jobber final : private noncopyable { - public: - enum class priority { - lowest, - below_normal, - normal, - above_normal, - highest - }; - public: - explicit jobber(u32 threads); - ~jobber() noexcept; - - template < typename F, typename... Args > - using async_invoke_result_t = stdex::invoke_result_t< - std::decay_t, - std::decay_t...>; - - template < typename F, typename... Args - , typename R = async_invoke_result_t > - std::future async(F&& f, Args&&... args); - - template < typename F, typename... Args - , typename R = async_invoke_result_t > - std::future async(priority priority, F&& f, Args&&... args); - - void pause() noexcept; - void resume() noexcept; - bool is_paused() const noexcept; - - void wait_all() const noexcept; - void active_wait_all() noexcept; - - template < typename T, typename TimeTag > - void wait_for(const unit& time_for) const noexcept; - - template < typename T, typename TimeTag > - void wait_until(const unit& time_until) const noexcept; - - template < typename T, typename TimeTag > - void active_wait_for(const unit& time_for) noexcept; - - template < typename T, typename TimeTag > - void active_wait_until(const unit& time_until) noexcept; - private: - class task; - using task_ptr = std::unique_ptr; - template < typename R, typename F, typename... Args > - class concrete_task; - private: - void push_task_(priority priority, task_ptr task); - task_ptr pop_task_() noexcept; - void shutdown_() noexcept; - void worker_main_() noexcept; - void process_task_(std::unique_lock lock) noexcept; - private: - vector threads_; - vector> tasks_; - std::mutex tasks_mutex_; - std::condition_variable cond_var_; - std::atomic paused_{false}; - std::atomic cancelled_{false}; - std::atomic active_task_count_{0}; - }; - - class jobber::task : private noncopyable { - public: - virtual ~task() noexcept = default; - virtual void run() noexcept = 0; - }; - - template < typename R, typename F, typename... Args > - class jobber::concrete_task : public task { - F f_; - std::tuple args_; - std::promise promise_; - public: - template < typename U > - concrete_task(U&& u, std::tuple&& args); - void run() noexcept final; - std::future future() noexcept; - }; - - template < typename F, typename... Args > - class jobber::concrete_task : public task { - F f_; - std::tuple args_; - std::promise promise_; - public: - template < typename U > - concrete_task(U&& u, std::tuple&& args); - void run() noexcept final; - std::future future() noexcept; - }; -} - -namespace e2d -{ - // - // async - // - - template < typename F, typename... Args, typename R > - std::future jobber::async(F&& f, Args&&... args) { - return async( - priority::normal, - std::forward(f), - std::forward(args)...); - } - - template < typename F, typename... Args, typename R > - std::future jobber::async(priority priority, F&& f, Args&&... args) { - using task_t = concrete_task< - R, - std::decay_t, - std::decay_t...>; - std::unique_ptr task = std::make_unique( - std::forward(f), - std::make_tuple(std::forward(args)...)); - std::future future = task->future(); - std::lock_guard guard(tasks_mutex_); - push_task_(priority, std::move(task)); - return future; - } - - // - // wait - // - - template < typename T, typename TimeTag > - void jobber::wait_for(const unit& time_for) const noexcept { - if ( time_for.value > T(0) ) { - wait_until( - time::now() + - time_for.template cast_to()); - } - } - - template < typename T, typename TimeTag > - void jobber::wait_until(const unit& time_until) const noexcept { - while ( active_task_count_ ) { - const auto time_now = time::now(); - if ( time_now >= time_until.template cast_to() ) { - break; - } - std::this_thread::yield(); - } - } - - // - // active_wait - // - - template < typename T, typename TimeTag > - void jobber::active_wait_for(const unit& time_for) noexcept { - if ( time_for.value > T(0) ) { - active_wait_until( - time::now() + - time_for.template cast_to()); - } - } - - template < typename T, typename TimeTag > - void jobber::active_wait_until(const unit& time_until) noexcept { - while ( active_task_count_ ) { - const auto time_now = time::now(); - if ( time_now >= time_until.template cast_to() ) { - break; - } - std::unique_lock lock(tasks_mutex_); - process_task_(std::move(lock)); - } - } - - // - // concrete_task - // - - template < typename R, typename F, typename... Args > - template < typename U > - jobber::concrete_task::concrete_task(U&& u, std::tuple&& args) - : f_(std::forward(u)) - , args_(std::move(args)) {} - - template < typename R, typename F, typename... Args > - void jobber::concrete_task::run() noexcept { - try { - R value = stdex::apply(std::move(f_), std::move(args_)); - promise_.set_value(std::move(value)); - } catch (...) { - promise_.set_exception(std::current_exception()); - } - } - - template < typename R, typename F, typename... Args > - std::future jobber::concrete_task::future() noexcept { - return promise_.get_future(); - } - - // - // concrete_task - // - - template < typename F, typename... Args > - template < typename U > - jobber::concrete_task::concrete_task(U&& u, std::tuple&& args) - : f_(std::forward(u)) - , args_(std::move(args)) {} - - template < typename F, typename... Args > - void jobber::concrete_task::run() noexcept { - try { - stdex::apply(std::move(f_), std::move(args_)); - promise_.set_value(); - } catch (...) { - promise_.set_exception(std::current_exception()); - } - } - - template < typename F, typename... Args > - std::future jobber::concrete_task::future() noexcept { - return promise_.get_future(); - } -} diff --git a/headers/enduro2d/utils/scheduler.hpp b/headers/enduro2d/utils/scheduler.hpp deleted file mode 100644 index d71d9f93..00000000 --- a/headers/enduro2d/utils/scheduler.hpp +++ /dev/null @@ -1,196 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018 Matvey Cherevko - ******************************************************************************/ - -#pragma once - -#include "_utils.hpp" -#include "time.hpp" - -namespace e2d -{ - class scheduler final : private noncopyable { - public: - enum class priority { - lowest, - below_normal, - normal, - above_normal, - highest - }; - public: - scheduler(); - ~scheduler() noexcept; - - template < typename F, typename... Args > - using schedule_invoke_result_t = stdex::invoke_result_t< - std::decay_t, - std::decay_t...>; - - template < typename F, typename... Args - , typename R = schedule_invoke_result_t > - std::future schedule(F&& f, Args&&... args); - - template < typename F, typename... Args - , typename R = schedule_invoke_result_t > - std::future schedule(priority priority, F&& f, Args&&... args); - - void process_all_tasks() noexcept; - - template < typename T, typename TimeTag > - void process_tasks_for(const unit& time_for) noexcept; - - template < typename T, typename TimeTag > - void process_tasks_until(const unit& time_until) noexcept; - private: - class task; - using task_ptr = std::unique_ptr; - template < typename R, typename F, typename... Args > - class concrete_task; - private: - void push_task_(priority priority, task_ptr task); - task_ptr pop_task_() noexcept; - void process_task_(std::unique_lock lock) noexcept; - private: - std::mutex tasks_mutex_; - std::atomic active_task_count_{0}; - vector> tasks_; - }; - - class scheduler::task : private noncopyable { - public: - virtual ~task() noexcept = default; - virtual void run() noexcept = 0; - }; - - template < typename R, typename F, typename... Args > - class scheduler::concrete_task : public task { - F f_; - std::tuple args_; - std::promise promise_; - public: - template < typename U > - concrete_task(U&& u, std::tuple&& args); - void run() noexcept final; - std::future future() noexcept; - }; - - template < typename F, typename... Args > - class scheduler::concrete_task : public task { - F f_; - std::tuple args_; - std::promise promise_; - public: - template < typename U > - concrete_task(U&& u, std::tuple&& args); - void run() noexcept final; - std::future future() noexcept; - }; -} - -namespace e2d -{ - // - // schedule - // - - template < typename F, typename... Args, typename R > - std::future scheduler::schedule(F&& f, Args&&... args) { - return schedule( - priority::normal, - std::forward(f), - std::forward(args)...); - } - - template < typename F, typename... Args, typename R > - std::future scheduler::schedule(priority priority, F&& f, Args&&... args) { - using task_t = concrete_task< - R, - std::decay_t, - std::decay_t...>; - std::unique_ptr task = std::make_unique( - std::forward(f), - std::make_tuple(std::forward(args)...)); - std::future future = task->future(); - std::lock_guard guard(tasks_mutex_); - push_task_(priority, std::move(task)); - return future; - } - - // - // process_all_tasks - // - - template < typename T, typename TimeTag > - void scheduler::process_tasks_for(const unit& time_for) noexcept { - if ( time_for.value > T(0) ) { - process_tasks_until( - time::now() + - time_for.template cast_to()); - } - } - - template < typename T, typename TimeTag > - void scheduler::process_tasks_until(const unit& time_until) noexcept { - while ( active_task_count_ ) { - const auto time_now = time::now(); - if ( time_now >= time_until.template cast_to() ) { - break; - } - std::unique_lock lock(tasks_mutex_); - process_task_(std::move(lock)); - } - } - - // - // concrete_task - // - - template < typename R, typename F, typename... Args > - template < typename U > - scheduler::concrete_task::concrete_task(U&& u, std::tuple&& args) - : f_(std::forward(u)) - , args_(std::move(args)) {} - - template < typename R, typename F, typename... Args > - void scheduler::concrete_task::run() noexcept { - try { - R value = stdex::apply(std::move(f_), std::move(args_)); - promise_.set_value(std::move(value)); - } catch (...) { - promise_.set_exception(std::current_exception()); - } - } - - template < typename R, typename F, typename... Args > - std::future scheduler::concrete_task::future() noexcept { - return promise_.get_future(); - } - - // - // concrete_task - // - - template < typename F, typename... Args > - template < typename U > - scheduler::concrete_task::concrete_task(U&& u, std::tuple&& args) - : f_(std::forward(u)) - , args_(std::move(args)) {} - - template < typename F, typename... Args > - void scheduler::concrete_task::run() noexcept { - try { - stdex::apply(std::move(f_), std::move(args_)); - promise_.set_value(); - } catch (...) { - promise_.set_exception(std::current_exception()); - } - } - - template < typename F, typename... Args > - std::future scheduler::concrete_task::future() noexcept { - return promise_.get_future(); - } -} diff --git a/modules/invoke.hpp b/modules/invoke.hpp deleted file mode 160000 index de0183fe..00000000 --- a/modules/invoke.hpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit de0183febef4910d6d550a1a86562705cc779552 diff --git a/scripts/update_modules.sh b/scripts/update_modules.sh index 9bdf1804..55c0d0d4 100755 --- a/scripts/update_modules.sh +++ b/scripts/update_modules.sh @@ -22,10 +22,8 @@ git submodule update --remote --recursive mkdir -p $UNTESTS_DIR/catch cp -fv $MODULES_DIR/catch2/single_include/catch2/catch.hpp $UNTESTS_DIR/catch/catch.hpp -mkdir -p $HEADERS_RDPARTY_DIR/invoke.hpp -cp -rfv $MODULES_DIR/invoke.hpp/invoke.hpp $HEADERS_RDPARTY_DIR/invoke.hpp/invoke.hpp - mkdir -p $HEADERS_RDPARTY_DIR/promise.hpp +cp -rfv $MODULES_DIR/promise.hpp/invoke.hpp $HEADERS_RDPARTY_DIR/promise.hpp/invoke.hpp cp -rfv $MODULES_DIR/promise.hpp/jobber.hpp $HEADERS_RDPARTY_DIR/promise.hpp/jobber.hpp cp -rfv $MODULES_DIR/promise.hpp/promise.hpp $HEADERS_RDPARTY_DIR/promise.hpp/promise.hpp cp -rfv $MODULES_DIR/promise.hpp/scheduler.hpp $HEADERS_RDPARTY_DIR/promise.hpp/scheduler.hpp diff --git a/sources/enduro2d/core/engine.cpp b/sources/enduro2d/core/engine.cpp index 21646155..327500c0 100644 --- a/sources/enduro2d/core/engine.cpp +++ b/sources/enduro2d/core/engine.cpp @@ -251,11 +251,11 @@ namespace e2d return time::to_seconds(delta_us.cast_to()).value; } - scheduler& main_thread_scheduler() noexcept { + stdex::scheduler& main_thread_scheduler() noexcept { return main_thread_scheduler_; } - const scheduler& main_thread_scheduler() const noexcept { + const stdex::scheduler& main_thread_scheduler() const noexcept { return main_thread_scheduler_; } public: @@ -298,7 +298,7 @@ namespace e2d } private: timer_parameters timer_params_; - scheduler main_thread_scheduler_; + stdex::scheduler main_thread_scheduler_; microseconds init_time_{time::now_us()}; microseconds prev_frame_time_{time::now_us()}; microseconds prev_frame_rate_time_{time::now_us()}; @@ -422,11 +422,11 @@ namespace e2d return state_->realtime_time(); } - scheduler& engine::main_thread_scheduler() noexcept { + stdex::scheduler& engine::main_thread_scheduler() noexcept { return state_->main_thread_scheduler(); } - const scheduler& engine::main_thread_scheduler() const noexcept { + const stdex::scheduler& engine::main_thread_scheduler() const noexcept { return state_->main_thread_scheduler(); } } diff --git a/sources/enduro2d/core/vfs.cpp b/sources/enduro2d/core/vfs.cpp index 7091ac99..07cd5957 100644 --- a/sources/enduro2d/core/vfs.cpp +++ b/sources/enduro2d/core/vfs.cpp @@ -79,7 +79,7 @@ namespace e2d class vfs::state final : private e2d::noncopyable { public: std::mutex mutex; - jobber worker{1}; + stdex::jobber worker{1}; hash_map aliases; hash_map schemes; public: @@ -164,7 +164,7 @@ namespace e2d }, output_stream_uptr()); } - std::future> vfs::load_async(const url& url) const { + stdex::promise> vfs::load_async(const url& url) const { return state_->worker.async([](input_stream_uptr stream){ buffer buf; return streams::try_read_tail(buf, stream) @@ -196,7 +196,6 @@ namespace e2d using stream_ptr = std::shared_ptr; archive_ptr archive; stream_ptr stream; - jobber worker{1}; public: state(input_stream_uptr nstream) : archive(open_archive_(nstream)) diff --git a/sources/enduro2d/utils/jobber.cpp b/sources/enduro2d/utils/jobber.cpp deleted file mode 100644 index c309b140..00000000 --- a/sources/enduro2d/utils/jobber.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018 Matvey Cherevko - ******************************************************************************/ - -#include - -namespace e2d -{ - jobber::jobber(u32 threads) { - try { - threads_.resize(math::max(1u, threads)); - for ( std::thread& thread : threads_ ) { - thread = std::thread(&jobber::worker_main_, this); - } - } catch (...) { - shutdown_(); - throw; - } - } - - jobber::~jobber() noexcept { - shutdown_(); - } - - void jobber::pause() noexcept { - paused_.store(true); - } - - void jobber::resume() noexcept { - paused_.store(false); - { - std::lock_guard guard(tasks_mutex_); - cond_var_.notify_all(); - } - } - - bool jobber::is_paused() const noexcept { - return paused_; - } - - void jobber::wait_all() const noexcept { - while ( active_task_count_ ) { - std::this_thread::yield(); - } - } - - void jobber::active_wait_all() noexcept { - while ( active_task_count_ ) { - std::unique_lock lock(tasks_mutex_); - process_task_(std::move(lock)); - } - } - - void jobber::push_task_(priority priority, task_ptr task) { - tasks_.emplace_back(priority, std::move(task)); - std::push_heap(tasks_.begin(), tasks_.end()); - ++active_task_count_; - cond_var_.notify_one(); - } - - jobber::task_ptr jobber::pop_task_() noexcept { - if ( !tasks_.empty() ) { - std::pop_heap(tasks_.begin(), tasks_.end()); - task_ptr task = std::move(tasks_.back().second); - tasks_.pop_back(); - return task; - } - return nullptr; - } - - void jobber::shutdown_() noexcept { - cancelled_.store(true); - { - std::lock_guard guard(tasks_mutex_); - cond_var_.notify_all(); - } - for ( std::thread& thread : threads_ ) { - if ( thread.joinable() ) { - thread.join(); - } - } - } - - void jobber::worker_main_() noexcept { - for (;;) { - std::unique_lock lock(tasks_mutex_); - cond_var_.wait(lock, [this](){ - return cancelled_ || (!paused_ && !tasks_.empty()); - }); - if ( cancelled_ ) { - break; - } - process_task_(std::move(lock)); - } - } - - void jobber::process_task_(std::unique_lock lock) noexcept { - E2D_ASSERT(lock.owns_lock()); - task_ptr task = pop_task_(); - if ( task ) { - lock.unlock(); - task->run(); - --active_task_count_; - } - } -} diff --git a/sources/enduro2d/utils/scheduler.cpp b/sources/enduro2d/utils/scheduler.cpp deleted file mode 100644 index 240423e8..00000000 --- a/sources/enduro2d/utils/scheduler.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018 Matvey Cherevko - ******************************************************************************/ - -#include - -namespace -{ - using namespace e2d; -} - -namespace e2d -{ - scheduler::scheduler() = default; - scheduler::~scheduler() noexcept = default; - - void scheduler::process_all_tasks() noexcept { - while ( active_task_count_ ) { - std::unique_lock lock(tasks_mutex_); - process_task_(std::move(lock)); - } - } - - void scheduler::push_task_(priority priority, task_ptr task) { - tasks_.emplace_back(priority, std::move(task)); - std::push_heap(tasks_.begin(), tasks_.end()); - ++active_task_count_; - } - - scheduler::task_ptr scheduler::pop_task_() noexcept { - if ( !tasks_.empty() ) { - std::pop_heap(tasks_.begin(), tasks_.end()); - task_ptr task = std::move(tasks_.back().second); - tasks_.pop_back(); - return task; - } - return nullptr; - } - - void scheduler::process_task_(std::unique_lock lock) noexcept { - E2D_ASSERT(lock.owns_lock()); - task_ptr task = pop_task_(); - if ( task ) { - lock.unlock(); - task->run(); - --active_task_count_; - } - } -} diff --git a/untests/sources/untests_utils/jobber.cpp b/untests/sources/untests_utils/jobber.cpp deleted file mode 100644 index 8748cf73..00000000 --- a/untests/sources/untests_utils/jobber.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018 Matvey Cherevko - ******************************************************************************/ - -#include "_utils.hpp" -using namespace e2d; - -TEST_CASE("jobber") { - { - jobber j(1); - auto pv0 = j.async([](){ - throw exception(); - }); - REQUIRE_THROWS_AS(pv0.get(), exception); - } - { - i32 v5 = 5; - - jobber j(1); - auto pv0 = j.async([](i32 v){ - REQUIRE(v == 5); - throw exception(); - }, v5); - REQUIRE_THROWS_AS(pv0.get(), exception); - - auto pv1 = j.async([](int& v){ - REQUIRE(v == 5); - return v != 5 - ? 0 - : throw exception(); - }, std::ref(v5)); - REQUIRE_THROWS_AS(pv1.get(), exception); - - auto pv3 = j.async([](int& v){ - v = 4; - return v; - }, std::ref(v5)); - REQUIRE(pv3.get() == v5); - REQUIRE(v5 == 4); - } - { - jobber j(1); - auto p0 = j.async([](rad angle){ - return math::sin(angle); - }, math::pi()); - auto p1 = j.async([](rad angle){ - return math::cos(angle); - }, math::two_pi()); - REQUIRE(math::approximately(p0.get(), 0.f)); - REQUIRE(math::approximately(p1.get(), 1.f)); - } - { - jobber j(1); - j.pause(); - jobber::priority max_priority = jobber::priority::highest; - j.async([](){ - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - }); - for ( std::size_t i = 0; i < 10; ++i ) { - jobber::priority p = static_cast( - i % static_cast(jobber::priority::highest)); - j.async(p, [&max_priority](jobber::priority priority) { - REQUIRE(priority <= max_priority); - max_priority = priority; - }, p); - } - j.resume(); - j.wait_all(); - } - { - jobber j(1); - i32 counter = 0; - j.pause(); - for ( std::size_t i = 0; i < 50; ++i ) { - j.async([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - - const auto b = time::now_ms(); - - j.wait_for(make_milliseconds(15)); - REQUIRE(time::now_ms() - b > make_milliseconds(10)); - REQUIRE(counter == 0); - - j.wait_until(time::now_ms() + make_milliseconds(15)); - REQUIRE(time::now_ms() - b > make_milliseconds(20)); - REQUIRE(counter == 0); - - j.active_wait_for(make_milliseconds(60)); - REQUIRE(time::now_ms() - b > make_milliseconds(70)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - - j.active_wait_until(time::now_s() + make_seconds(3)); - REQUIRE(counter == 50); - } - { - jobber j(2); - jobber g(2); - - std::vector> jp(50); - for ( std::size_t i = 0; i < jp.size(); ++i ) { - jp[i] = j.async([&g](){ - std::vector> gp(50); - for ( std::size_t ii = 0; ii < gp.size(); ++ii ) { - gp[ii] = g.async([](rad angle){ - return math::sin(angle); - }, make_rad(ii).cast_to()); - } - return std::accumulate(gp.begin(), gp.end(), 0.f, - [](f32 r, std::future& f){ - return r + f.get(); - }); - }); - } - f32 r0 = std::accumulate(jp.begin(), jp.end(), 0.f, - [](f32 r, std::future& f){ - return r + f.get(); - }); - f32 r1 = 0.f; - for ( std::size_t i = 0; i < 50; ++i ) { - r1 += math::sin(make_rad(i).cast_to()); - } - REQUIRE(math::approximately(r0, r1 * 50.f)); - } - SECTION("performance") { - std::printf("-= jobber::performance tests =-\n"); - #if defined(E2D_BUILD_MODE) && E2D_BUILD_MODE == E2D_BUILD_MODE_DEBUG - const std::size_t task_n = 100'000; - #else - const std::size_t task_n = 1'000'000; - #endif - const auto big_task = [](std::size_t b, std::size_t n){ - f32 result = 0.f; - for ( std::size_t i = 0; i < n; ++i ) { - result += math::sin(make_rad(b + i).cast_to()); - result += math::cos(make_rad(b + i).cast_to()); - } - return result; - }; - const auto multi_task = [&](u32 threads, std::size_t tasks){ - e2d_untests::verbose_profiler_ms p( - str("cores: ") + std::to_string(threads) + - str(", tasks: ") + std::to_string(tasks)); - jobber j(threads); - std::vector> rs(tasks); - for ( std::size_t i = 0; i < tasks; ++i ) { - const std::size_t n = task_n / tasks; - rs[i] = j.async(big_task, i * n, n); - } - f32 result = std::accumulate(rs.begin(), rs.end(), 0.f, - [](f32 r, std::future& f){ - return r + f.get(); - }); - p.done(result); - }; - for ( u32 i = 1; i <= 4; ++i ) { - multi_task(i, 10); - multi_task(i, 100); - multi_task(i, 1000); - } - } -} diff --git a/untests/sources/untests_utils/scheduler.cpp b/untests/sources/untests_utils/scheduler.cpp deleted file mode 100644 index 8fb07c9a..00000000 --- a/untests/sources/untests_utils/scheduler.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018 Matvey Cherevko - ******************************************************************************/ - -#include "_utils.hpp" -using namespace e2d; - -TEST_CASE("scheduler") { - { - scheduler s; - i32 counter = 0; - s.schedule([&counter](){ ++counter; }); - REQUIRE(counter == 0); - s.process_all_tasks(); - REQUIRE(counter == 1); - s.schedule([&counter](){ ++counter; }); - REQUIRE(counter == 1); - s.process_all_tasks(); - REQUIRE(counter == 2); - } - { - scheduler s; - i32 counter = 0; - for ( std::size_t i = 0; i < 50; ++i ) { - s.schedule([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - s.process_tasks_for(make_milliseconds(-1)); - s.process_tasks_for(make_milliseconds(0)); - REQUIRE(counter == 0); - s.process_tasks_for(make_milliseconds(60)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - s.process_tasks_for(make_seconds(3)); - REQUIRE(counter == 50); - } - { - scheduler s; - i32 counter = 0; - for ( std::size_t i = 0; i < 50; ++i ) { - s.schedule([&counter](){ - ++counter; - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - }); - } - s.process_tasks_until(time::now_ms() - make_milliseconds(1)); - s.process_tasks_until(time::now_ms()); - REQUIRE(counter == 0); - s.process_tasks_until(time::now_ms() + make_milliseconds(60)); - REQUIRE(counter > 2); - REQUIRE(counter < 50); - s.process_tasks_until(time::now_s() + make_seconds(3)); - REQUIRE(counter == 50); - } - { - scheduler s; - str accumulator; - s.schedule(scheduler::priority::lowest, [](str& acc){ - acc.append("o"); - }, std::ref(accumulator)); - s.schedule(scheduler::priority::below_normal, [](str& acc){ - acc.append("l"); - }, std::ref(accumulator)); - s.schedule(scheduler::priority::highest, [](str& acc){ - acc.append("h"); - }, std::ref(accumulator)); - s.schedule(scheduler::priority::above_normal, [](str& acc){ - acc.append("e"); - }, std::ref(accumulator)); - s.schedule(scheduler::priority::normal, [](str& acc){ - acc.append("l"); - }, std::ref(accumulator)); - s.process_all_tasks(); - REQUIRE(accumulator == "hello"); - } -}