diff options
Diffstat (limited to 'src/libs/utils/tasktree.h')
-rw-r--r-- | src/libs/utils/tasktree.h | 385 |
1 files changed, 0 insertions, 385 deletions
diff --git a/src/libs/utils/tasktree.h b/src/libs/utils/tasktree.h deleted file mode 100644 index 54a0cfda53..0000000000 --- a/src/libs/utils/tasktree.h +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "utils_global.h" - -#include <QHash> -#include <QObject> -#include <QSharedPointer> - -namespace Utils { - -class StorageActivator; -class TaskContainer; -class TaskTreePrivate; - -namespace Tasking { - -class QTCREATOR_UTILS_EXPORT TaskInterface : public QObject -{ - Q_OBJECT - -public: - TaskInterface() = default; - virtual void start() = 0; - -signals: - void done(bool success); -}; - -class QTCREATOR_UTILS_EXPORT TreeStorageBase -{ -public: - bool isValid() const; - -protected: - using StorageConstructor = std::function<void *(void)>; - using StorageDestructor = std::function<void(void *)>; - - TreeStorageBase(StorageConstructor ctor, StorageDestructor dtor); - void *activeStorageVoid() const; - -private: - int createStorage() const; - void deleteStorage(int id) const; - void activateStorage(int id) const; - - friend bool operator==(const TreeStorageBase &first, const TreeStorageBase &second) - { return first.m_storageData == second.m_storageData; } - - friend bool operator!=(const TreeStorageBase &first, const TreeStorageBase &second) - { return first.m_storageData != second.m_storageData; } - - friend size_t qHash(const TreeStorageBase &storage, uint seed = 0) - { return size_t(storage.m_storageData.get()) ^ seed; } - - struct StorageData { - ~StorageData(); - StorageConstructor m_constructor = {}; - StorageDestructor m_destructor = {}; - QHash<int, void *> m_storageHash = {}; - int m_activeStorage = 0; // 0 means no active storage - int m_storageCounter = 0; - }; - QSharedPointer<StorageData> m_storageData; - friend TaskContainer; - friend TaskTreePrivate; - friend StorageActivator; -}; - -template <typename StorageStruct> -class TreeStorage : public TreeStorageBase -{ -public: - TreeStorage() : TreeStorageBase(TreeStorage::ctor(), TreeStorage::dtor()) {} - StorageStruct *operator->() const noexcept { return activeStorage(); } - StorageStruct *activeStorage() const { - return static_cast<StorageStruct *>(activeStorageVoid()); - } - -private: - static StorageConstructor ctor() { return [] { return new StorageStruct; }; } - static StorageDestructor dtor() { - return [](void *storage) { delete static_cast<StorageStruct *>(storage); }; - } -}; - -// 4 policies: -// 1. When all children finished with done -> report done, otherwise: -// a) Report error on first error and stop executing other children (including their subtree) -// b) On first error - wait for all children to be finished and report error afterwards -// 2. When all children finished with error -> report error, otherwise: -// a) Report done on first done and stop executing other children (including their subtree) -// b) On first done - wait for all children to be finished and report done afterwards - -enum class WorkflowPolicy { - StopOnError, // 1a - Will report error on any child error, otherwise done (if all children were done) - ContinueOnError, // 1b - the same. When no children it reports done. - StopOnDone, // 2a - Will report done on any child done, otherwise error (if all children were error) - ContinueOnDone, // 2b - the same. When no children it reports done. (?) - Optional // Returns always done after all children finished -}; - -enum class TaskAction -{ - Continue, - StopWithDone, - StopWithError -}; - -class QTCREATOR_UTILS_EXPORT TaskItem -{ -public: - // Internal, provided by QTC_DECLARE_CUSTOM_TASK - using TaskCreateHandler = std::function<TaskInterface *(void)>; - // Called prior to task start, just after createHandler - using TaskSetupHandler = std::function<TaskAction(TaskInterface &)>; - // Called on task done / error - using TaskEndHandler = std::function<void(const TaskInterface &)>; - // Called when group entered - using GroupSetupHandler = std::function<TaskAction()>; - // Called when group done / error - using GroupEndHandler = std::function<void()>; - - struct TaskHandler { - TaskCreateHandler m_createHandler; - TaskSetupHandler m_setupHandler; - TaskEndHandler m_doneHandler; - TaskEndHandler m_errorHandler; - }; - - struct GroupHandler { - GroupSetupHandler m_setupHandler; - GroupEndHandler m_doneHandler = {}; - GroupEndHandler m_errorHandler = {}; - }; - - int parallelLimit() const { return m_parallelLimit; } - WorkflowPolicy workflowPolicy() const { return m_workflowPolicy; } - TaskHandler taskHandler() const { return m_taskHandler; } - GroupHandler groupHandler() const { return m_groupHandler; } - QList<TaskItem> children() const { return m_children; } - QList<TreeStorageBase> storageList() const { return m_storageList; } - -protected: - enum class Type { - Group, - Storage, - Limit, - Policy, - TaskHandler, - GroupHandler - }; - - TaskItem() = default; - TaskItem(int parallelLimit) - : m_type(Type::Limit) - , m_parallelLimit(parallelLimit) {} - TaskItem(WorkflowPolicy policy) - : m_type(Type::Policy) - , m_workflowPolicy(policy) {} - TaskItem(const TaskHandler &handler) - : m_type(Type::TaskHandler) - , m_taskHandler(handler) {} - TaskItem(const GroupHandler &handler) - : m_type(Type::GroupHandler) - , m_groupHandler(handler) {} - TaskItem(const TreeStorageBase &storage) - : m_type(Type::Storage) - , m_storageList{storage} {} - void addChildren(const QList<TaskItem> &children); - -private: - Type m_type = Type::Group; - int m_parallelLimit = 1; // 0 means unlimited - WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError; - TaskHandler m_taskHandler; - GroupHandler m_groupHandler; - QList<TreeStorageBase> m_storageList; - QList<TaskItem> m_children; -}; - -class QTCREATOR_UTILS_EXPORT Group : public TaskItem -{ -public: - Group(const QList<TaskItem> &children) { addChildren(children); } - Group(std::initializer_list<TaskItem> children) { addChildren(children); } -}; - -class QTCREATOR_UTILS_EXPORT Storage : public TaskItem -{ -public: - Storage(const TreeStorageBase &storage) : TaskItem(storage) { } -}; - -class QTCREATOR_UTILS_EXPORT ParallelLimit : public TaskItem -{ -public: - ParallelLimit(int parallelLimit) : TaskItem(qMax(parallelLimit, 0)) {} -}; - -class QTCREATOR_UTILS_EXPORT Workflow : public TaskItem -{ -public: - Workflow(WorkflowPolicy policy) : TaskItem(policy) {} -}; - -class QTCREATOR_UTILS_EXPORT OnGroupSetup : public TaskItem -{ -public: - template <typename SetupFunction> - OnGroupSetup(SetupFunction &&function) - : TaskItem({wrapSetup(std::forward<SetupFunction>(function))}) {} - -private: - template<typename SetupFunction> - static TaskItem::GroupSetupHandler wrapSetup(SetupFunction &&function) { - static constexpr bool isDynamic = std::is_same_v<TaskAction, - std::invoke_result_t<std::decay_t<SetupFunction>>>; - constexpr bool isVoid = std::is_same_v<void, - std::invoke_result_t<std::decay_t<SetupFunction>>>; - static_assert(isDynamic || isVoid, - "Group setup handler needs to take no arguments and has to return " - "void or TaskAction. The passed handler doesn't fulfill these requirements."); - return [=] { - if constexpr (isDynamic) - return std::invoke(function); - std::invoke(function); - return TaskAction::Continue; - }; - }; -}; - -class QTCREATOR_UTILS_EXPORT OnGroupDone : public TaskItem -{ -public: - OnGroupDone(const GroupEndHandler &handler) : TaskItem({{}, handler}) {} -}; - -class QTCREATOR_UTILS_EXPORT OnGroupError : public TaskItem -{ -public: - OnGroupError(const GroupEndHandler &handler) : TaskItem({{}, {}, handler}) {} -}; - -QTCREATOR_UTILS_EXPORT extern ParallelLimit sequential; -QTCREATOR_UTILS_EXPORT extern ParallelLimit parallel; -QTCREATOR_UTILS_EXPORT extern Workflow stopOnError; -QTCREATOR_UTILS_EXPORT extern Workflow continueOnError; -QTCREATOR_UTILS_EXPORT extern Workflow stopOnDone; -QTCREATOR_UTILS_EXPORT extern Workflow continueOnDone; -QTCREATOR_UTILS_EXPORT extern Workflow optional; - -template <typename Task> -class TaskAdapter : public TaskInterface -{ -public: - using Type = Task; - TaskAdapter() = default; - Task *task() { return &m_task; } - const Task *task() const { return &m_task; } -private: - Task m_task; -}; - -template <typename Adapter> -class CustomTask : public TaskItem -{ -public: - using Task = typename Adapter::Type; - using EndHandler = std::function<void(const Task &)>; - static Adapter *createAdapter() { return new Adapter; } - template <typename SetupFunction> - CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {}) - : TaskItem({&createAdapter, wrapSetup(std::forward<SetupFunction>(function)), - wrapEnd(done), wrapEnd(error)}) {} - -private: - template<typename SetupFunction> - static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) { - static constexpr bool isDynamic = std::is_same_v<TaskAction, - std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>; - constexpr bool isVoid = std::is_same_v<void, - std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>; - static_assert(isDynamic || isVoid, - "Task setup handler needs to take (Task &) as an argument and has to return " - "void or TaskAction. The passed handler doesn't fulfill these requirements."); - return [=](TaskInterface &taskInterface) { - Adapter &adapter = static_cast<Adapter &>(taskInterface); - if constexpr (isDynamic) - return std::invoke(function, *adapter.task()); - std::invoke(function, *adapter.task()); - return TaskAction::Continue; - }; - }; - - static TaskEndHandler wrapEnd(const EndHandler &handler) { - if (!handler) - return {}; - return [handler](const TaskInterface &taskInterface) { - const Adapter &adapter = static_cast<const Adapter &>(taskInterface); - handler(*adapter.task()); - }; - }; -}; - -} // namespace Tasking - -class TaskTreePrivate; - -class QTCREATOR_UTILS_EXPORT TaskTree : public QObject -{ - Q_OBJECT - -public: - TaskTree(); - TaskTree(const Tasking::Group &root); - ~TaskTree(); - - void setupRoot(const Tasking::Group &root); - - void start(); - void stop(); - bool isRunning() const; - - int taskCount() const; - int progressMaximum() const { return taskCount(); } - int progressValue() const; // all finished / skipped / stopped tasks, groups itself excluded - - template <typename StorageStruct, typename StorageHandler> - void onStorageSetup(const Tasking::TreeStorage<StorageStruct> &storage, - StorageHandler &&handler) { - setupStorageHandler(storage, - wrapHandler<StorageStruct>(std::forward<StorageHandler>(handler)), {}); - } - template <typename StorageStruct, typename StorageHandler> - void onStorageDone(const Tasking::TreeStorage<StorageStruct> &storage, - StorageHandler &&handler) { - setupStorageHandler(storage, - {}, wrapHandler<StorageStruct>(std::forward<StorageHandler>(handler))); - } - -signals: - void started(); - void done(); - void errorOccurred(); - void progressValueChanged(int value); // updated whenever task finished / skipped / stopped - -private: - using StorageVoidHandler = std::function<void(void *)>; - void setupStorageHandler(const Tasking::TreeStorageBase &storage, - StorageVoidHandler setupHandler, - StorageVoidHandler doneHandler); - template <typename StorageStruct, typename StorageHandler> - StorageVoidHandler wrapHandler(StorageHandler &&handler) { - return [=](void *voidStruct) { - StorageStruct *storageStruct = static_cast<StorageStruct *>(voidStruct); - std::invoke(handler, storageStruct); - }; - } - - friend class TaskTreePrivate; - TaskTreePrivate *d; -}; - -class QTCREATOR_UTILS_EXPORT TaskTreeAdapter : public Tasking::TaskAdapter<TaskTree> -{ -public: - TaskTreeAdapter(); - void start() final; -}; - -} // namespace Utils - -#define QTC_DECLARE_CUSTOM_TASK(CustomTaskName, TaskAdapterClass)\ -namespace Utils::Tasking { using CustomTaskName = CustomTask<TaskAdapterClass>; } - -#define QTC_DECLARE_CUSTOM_TEMPLATE_TASK(CustomTaskName, TaskAdapterClass)\ -namespace Utils::Tasking {\ -template <typename ...Args>\ -using CustomTaskName = CustomTask<TaskAdapterClass<Args...>>;\ -} // namespace Utils::Tasking - -QTC_DECLARE_CUSTOM_TASK(Tree, Utils::TaskTreeAdapter); |