From a271658154bb4cf452eddf29089e6ff2a1b955d5 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 23 Feb 2024 17:47:40 +0100 Subject: [PATCH] impr: Added once execution and task progress increment helpers --- lib/libimhex/include/hex/api/task_manager.hpp | 9 ++++ lib/libimhex/source/api/task_manager.cpp | 46 ++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/libimhex/include/hex/api/task_manager.hpp b/lib/libimhex/include/hex/api/task_manager.hpp index c3cb387bb..1a22ae847 100644 --- a/lib/libimhex/include/hex/api/task_manager.hpp +++ b/lib/libimhex/include/hex/api/task_manager.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace hex { @@ -33,6 +34,7 @@ namespace hex { */ void update(u64 value); void update() const; + void increment(); /** * @brief Sets the maximum value of the task @@ -149,6 +151,13 @@ namespace hex { */ static void doLater(const std::function &function); + /** + * @brief Creates a new synchronous task that will execute the given function at the start of the next frame + * @param function Function to be executed + * @param location Source location of the function call. This is used to make sure repeated calls to the function at the same location are only executed once + */ + static void doLaterOnce(const std::function &function, std::source_location location = std::source_location::current()); + /** * @brief Creates a callback that will be executed when all tasks are finished * @param function Function to be executed diff --git a/lib/libimhex/source/api/task_manager.cpp b/lib/libimhex/source/api/task_manager.cpp index 68b0b7a66..5c78b871a 100644 --- a/lib/libimhex/source/api/task_manager.cpp +++ b/lib/libimhex/source/api/task_manager.cpp @@ -16,14 +16,41 @@ #include #endif +namespace { + + struct SourceLocationWrapper { + std::source_location location; + + bool operator==(const SourceLocationWrapper &other) const { + return location.file_name() == other.location.file_name() && + location.function_name() == other.location.function_name() && + location.column() == other.location.column() && + location.line() == other.location.line(); + } + }; + +} + +template<> +struct std::hash { + std::size_t operator()(const SourceLocationWrapper& s) const noexcept { + auto h1 = std::hash{}(s.location.file_name()); + auto h2 = std::hash{}(s.location.function_name()); + auto h3 = std::hash{}(s.location.column()); + auto h4 = std::hash{}(s.location.line()); + return (h1 << 0) ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3); + } +}; + namespace hex { namespace { - std::mutex s_deferredCallsMutex, s_tasksFinishedMutex; + std::recursive_mutex s_deferredCallsMutex, s_tasksFinishedMutex; std::list> s_tasks, s_taskQueue; std::list> s_deferredCalls; + std::unordered_map> s_onceDeferredCalls; std::list> s_tasksFinishedCallbacks; std::mutex s_queueMutex; @@ -77,6 +104,13 @@ namespace hex { throw TaskInterruptor(); } + void Task::increment() { + m_currValue.fetch_add(1, std::memory_order_relaxed); + + if (m_shouldInterrupt.load(std::memory_order_relaxed)) [[unlikely]] + throw TaskInterruptor(); + } + void Task::setMaxValue(u64 value) { m_maxValue = value; @@ -289,6 +323,7 @@ namespace hex { s_taskQueue.clear(); s_deferredCalls.clear(); + s_onceDeferredCalls.clear(); s_tasksFinishedCallbacks.clear(); } @@ -368,13 +403,22 @@ namespace hex { s_deferredCalls.push_back(function); } + void TaskManager::doLaterOnce(const std::function &function, std::source_location location) { + std::scoped_lock lock(s_deferredCallsMutex); + + s_onceDeferredCalls[SourceLocationWrapper{ location }] = function; + } + void TaskManager::runDeferredCalls() { std::scoped_lock lock(s_deferredCallsMutex); for (const auto &call : s_deferredCalls) call(); + for (const auto &[location, call] : s_onceDeferredCalls) + call(); s_deferredCalls.clear(); + s_onceDeferredCalls.clear(); } void TaskManager::runWhenTasksFinished(const std::function &function) {