#pragma once #include #include #include #include #include #include #include #include #include namespace hex { class TaskHolder; class TaskManager; /** * @brief A type representing a running asynchronous task */ class Task { public: Task() = default; Task(Lang name, u64 maxValue, bool background, std::function function); Task(const Task&) = delete; Task(Task &&other) noexcept; ~Task(); /** * @brief Updates the current process value of the task * @param value Current value */ void update(u64 value); void update() const; void increment(); /** * @brief Sets the maximum value of the task * @param value Maximum value of the task */ void setMaxValue(u64 value); /** * @brief Interrupts the task * For regular Tasks, this just throws an exception to stop the task. * If a custom interrupt callback is set, an exception is thrown and the callback is called. */ void interrupt(); /** * @brief Sets a callback that is called when the task is interrupted * @param callback Callback to be called */ void setInterruptCallback(std::function callback); [[nodiscard]] bool isBackgroundTask() const; [[nodiscard]] bool isFinished() const; [[nodiscard]] bool hadException() const; [[nodiscard]] bool wasInterrupted() const; [[nodiscard]] bool shouldInterrupt() const; void clearException(); [[nodiscard]] std::string getExceptionMessage() const; [[nodiscard]] const Lang &getName(); [[nodiscard]] u64 getValue() const; [[nodiscard]] u64 getMaxValue() const; private: void finish(); void interruption(); void exception(const char *message); private: mutable std::mutex m_mutex; Lang m_name; std::atomic m_currValue = 0, m_maxValue = 0; std::function m_interruptCallback; std::function m_function; std::atomic m_shouldInterrupt = false; std::atomic m_background = true; std::atomic m_interrupted = false; std::atomic m_finished = false; std::atomic m_hadException = false; std::string m_exceptionMessage; struct TaskInterruptor { virtual ~TaskInterruptor() = default; }; friend class TaskHolder; friend class TaskManager; }; /** * @brief A type holding a weak reference to a Task */ class TaskHolder { public: TaskHolder() = default; explicit TaskHolder(std::weak_ptr task) : m_task(std::move(task)) { } [[nodiscard]] bool isRunning() const; [[nodiscard]] bool hadException() const; [[nodiscard]] bool wasInterrupted() const; [[nodiscard]] bool shouldInterrupt() const; [[nodiscard]] u32 getProgress() const; void interrupt() const; private: std::weak_ptr m_task; }; /** * @brief The Task Manager is responsible for running and managing asynchronous tasks */ class TaskManager { public: TaskManager() = delete; static void init(); static void exit(); constexpr static auto NoProgress = 0; /** * @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer * @param name Name of the task * @param maxValue Maximum value of the task * @param function Function to be executed * @return A TaskHolder holding a weak reference to the task */ static TaskHolder createTask(Lang name, u64 maxValue, std::function function); /** * @brief Creates a new asynchronous task that does not get displayed in the Task Manager * @param name Name of the task * @param function Function to be executed * @return A TaskHolder holding a weak reference to the task */ static TaskHolder createBackgroundTask(Lang name, 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 */ 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 */ static void runWhenTasksFinished(const std::function &function); /** * @brief Sets the name of the current thread * @param name Name of the thread */ static void setCurrentThreadName(const std::string &name); /** * @brief Gets the name of the current thread * @return Name of the thread */ static std::string getCurrentThreadName(); /** * @brief Cleans up finished tasks */ static void collectGarbage(); static Task& getCurrentTask(); static size_t getRunningTaskCount(); static size_t getRunningBackgroundTaskCount(); static const std::list>& getRunningTasks(); static void runDeferredCalls(); private: static TaskHolder createTask(Lang name, u64 maxValue, bool background, std::function function); }; }