TaskTree: Introduce For element

Improve code readability by requiring iteratable Group
to be named For.

The For's c'tor requires an iterator element as a first arg.

The For's c'tor allows for passing exactly one iterator element.

It's not possible to place iterators inside Group element anymore.

Change-Id: I9dfe2c0da058abac161f66c4e336da2417c383f1
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2024-07-09 21:36:17 +02:00
parent c841a99db9
commit 779390829c
19 changed files with 110 additions and 76 deletions

View File

@@ -207,13 +207,12 @@ public:
: m_type(Type::Storage) : m_type(Type::Storage)
, m_storageList{storage} {} , m_storageList{storage} {}
GroupItem(const Loop &loop) : GroupItem(GroupData{{}, {}, {}, loop}) {}
// TODO: Add tests. // TODO: Add tests.
GroupItem(const QList<GroupItem> &children) : m_type(Type::List) { addChildren(children); } GroupItem(const QList<GroupItem> &children) : m_type(Type::List) { addChildren(children); }
GroupItem(std::initializer_list<GroupItem> children) : m_type(Type::List) { addChildren(children); } GroupItem(std::initializer_list<GroupItem> children) : m_type(Type::List) { addChildren(children); }
protected: protected:
GroupItem(const Loop &loop) : GroupItem(GroupData{{}, {}, {}, loop}) {}
// Internal, provided by CustomTask // Internal, provided by CustomTask
using InterfaceCreateHandler = std::function<TaskInterface *(void)>; using InterfaceCreateHandler = std::function<TaskInterface *(void)>;
// Called prior to task start, just after createHandler // Called prior to task start, just after createHandler
@@ -274,6 +273,7 @@ protected:
private: private:
friend class ContainerNode; friend class ContainerNode;
friend class For;
friend class TaskNode; friend class TaskNode;
friend class TaskTreePrivate; friend class TaskTreePrivate;
friend class ParallelLimitFunctor; friend class ParallelLimitFunctor;
@@ -433,11 +433,42 @@ TASKING_EXPORT extern const GroupItem nullItem;
TASKING_EXPORT extern const ExecutableItem successItem; TASKING_EXPORT extern const ExecutableItem successItem;
TASKING_EXPORT extern const ExecutableItem errorItem; TASKING_EXPORT extern const ExecutableItem errorItem;
class TASKING_EXPORT Forever final : public Group class TASKING_EXPORT For : public Group
{ {
public: public:
Forever(const QList<GroupItem> &children) : Group({LoopForever(), children}) {} template <typename ...Args>
Forever(std::initializer_list<GroupItem> children) : Group({LoopForever(), children}) {} For(const Loop &loop, const Args &...args)
: Group(withLoop(loop, args...)) { }
protected:
For(const Loop &loop, const QList<GroupItem> &children) : Group({loop, children}) {}
For(const Loop &loop, std::initializer_list<GroupItem> children) : Group({loop, children}) {}
private:
template <typename ...Args>
QList<GroupItem> withLoop(const Loop &loop, const Args &...args) {
QList<GroupItem> children{GroupItem(loop)};
appendChildren(std::make_tuple(args...), &children);
return children;
}
template <typename Tuple, std::size_t N = 0>
void appendChildren(const Tuple &tuple, QList<GroupItem> *children) {
constexpr auto TupleSize = std::tuple_size_v<Tuple>;
if constexpr (TupleSize > 0) {
// static_assert(workflowPolicyCount<Tuple>() <= 1, "Too many workflow policies in one group.");
children->append(std::get<N>(tuple));
if constexpr (N + 1 < TupleSize)
appendChildren<Tuple, N + 1>(tuple, children);
}
}
};
class TASKING_EXPORT Forever final : public For
{
public:
Forever(const QList<GroupItem> &children) : For(LoopForever(), children) {}
Forever(std::initializer_list<GroupItem> children) : For(LoopForever(), children) {}
}; };
// Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount()

View File

@@ -830,9 +830,9 @@ AndroidDeviceManagerInstance::AndroidDeviceManagerInstance(QObject *parent)
// otherwise, Android Studio would give an error during parsing also. So this fix // otherwise, Android Studio would give an error during parsing also. So this fix
// aim to keep support for Qt Creator and Android Studio. // aim to keep support for Qt Creator and Android Studio.
m_avdListRecipe = Group { m_avdListRecipe = For {
storage,
iterator, iterator,
storage,
ProcessTask(onProcessSetup, onProcessDone) ProcessTask(onProcessSetup, onProcessDone)
}; };
} }

View File

@@ -179,20 +179,19 @@ void AndroidQmlPreviewWorker::startPidWatcher()
const TimeoutTask timeout([](std::chrono::milliseconds &timeout) { timeout = 2s; }); const TimeoutTask timeout([](std::chrono::milliseconds &timeout) { timeout = 2s; });
const Group root { const Group recipe {
Group { For {
pidIterator, pidIterator,
ProcessTask(onPidSetup, onPidDone, CallDoneIf::Success), ProcessTask(onPidSetup, onPidDone, CallDoneIf::Success),
timeout timeout
}.withTimeout(20s), }.withTimeout(20s),
Group { For {
alivePidIterator, alivePidIterator,
ProcessTask(onPidSetup, onAlivePidDone), ProcessTask(onPidSetup, onAlivePidDone),
timeout timeout
} }
}; };
m_pidRunner.start(recipe);
m_pidRunner.start(root);
} }
void AndroidQmlPreviewWorker::startLogcat() void AndroidQmlPreviewWorker::startLogcat()

View File

@@ -294,14 +294,14 @@ static GroupItem installationRecipe(const Storage<DialogStorage> &dialogStorage,
return Group { return Group {
onGroupSetup(onSetup), onGroupSetup(onSetup),
Group { For {
finishAllAndSuccess,
uninstallIterator, uninstallIterator,
finishAllAndSuccess,
ProcessTask(onUninstallSetup, onDone) ProcessTask(onUninstallSetup, onDone)
}, },
Group { For {
finishAllAndSuccess,
installIterator, installIterator,
finishAllAndSuccess,
ProcessTask(onInstallSetup, onDone) ProcessTask(onInstallSetup, onDone)
} }
}; };

View File

@@ -417,14 +417,14 @@ void TestCodeParser::scanForTests(const QSet<FilePath> &filePaths,
if (!results.isEmpty()) if (!results.isEmpty())
emit testParseResultsReady(results); emit testParseResultsReady(results);
}; };
const Group root { const For recipe {
LoopRepeat(filteredFiles.size()),
parallelLimit(limit), parallelLimit(limit),
storage, storage,
onGroupSetup([storage, filteredFiles] { *storage = filteredFiles.cbegin(); }), onGroupSetup([storage, filteredFiles] { *storage = filteredFiles.cbegin(); }),
LoopRepeat(filteredFiles.size()),
AsyncTask<TestParseResultPtr>(onSetup, onDone, CallDoneIf::Success) AsyncTask<TestParseResultPtr>(onSetup, onDone, CallDoneIf::Success)
}; };
m_taskTreeRunner.start(root); m_taskTreeRunner.start(recipe);
} }
void TestCodeParser::onTaskStarted(Id type) void TestCodeParser::onTaskStarted(Id type)

View File

@@ -459,15 +459,15 @@ void TestRunner::runTestsHelper()
} }
}; };
const Group root { const For recipe {
finishAllAndSuccess,
iterator, iterator,
finishAllAndSuccess,
Group { Group {
storage, storage,
ProcessTask(onSetup, onDone) ProcessTask(onSetup, onDone)
} }
}; };
m_taskTreeRunner.start(root); m_taskTreeRunner.start(recipe);
} }
static void processOutput(TestOutputReader *outputreader, const QString &msg, OutputFormat format) static void processOutput(TestOutputReader *outputreader, const QString &msg, OutputFormat format)

View File

@@ -691,7 +691,7 @@ static Group authorizationRecipe()
*serverUrlStorage = unauthorizedDashboardStorage->url; *serverUrlStorage = unauthorizedDashboardStorage->url;
}), }),
}, },
Group { For {
LoopUntil(onCredentialLoopCondition), LoopUntil(onCredentialLoopCondition),
CredentialQueryTask(onGetCredentialSetup, onGetCredentialDone), CredentialQueryTask(onGetCredentialSetup, onGetCredentialDone),
Group { Group {

View File

@@ -224,10 +224,10 @@ GroupItem clangToolTask(const AnalyzeUnits &units,
error}); error});
}; };
return Group { return For {
iterator,
parallelLimit(qMax(1, input.runSettings.parallelJobs())), parallelLimit(qMax(1, input.runSettings.parallelJobs())),
finishAllAndSuccess, finishAllAndSuccess,
iterator,
Group { Group {
storage, storage,
onGroupSetup(onSetup), onGroupSetup(onSetup),

View File

@@ -383,9 +383,9 @@ void LocatorMatcher::start()
parallel, parallel,
collectorStorage, collectorStorage,
AsyncTask<LocatorFilterEntries>(onCollectorSetup, onCollectorDone), AsyncTask<LocatorFilterEntries>(onCollectorSetup, onCollectorDone),
Group { For {
parallelLimit(d->m_parallelLimit),
iterator, iterator,
parallelLimit(d->m_parallelLimit),
TaskTreeTask(onTaskTreeSetup) TaskTreeTask(onTaskTreeSetup)
} }
}; };

View File

@@ -142,16 +142,16 @@ DiffFilesController::DiffFilesController(IDocument *document)
setDiffFiles(finalList); setDiffFiles(finalList);
}; };
const Group root { const For recipe {
iterator,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
finishAllAndSuccess, finishAllAndSuccess,
storage, storage,
iterator,
onGroupSetup(onSetup), onGroupSetup(onSetup),
AsyncTask<FileData>(onDiffSetup, onDiffDone, CallDoneIf::Success), AsyncTask<FileData>(onDiffSetup, onDiffDone, CallDoneIf::Success),
onGroupDone(onDone) onGroupDone(onDone)
}; };
setReloadRecipe(root); setReloadRecipe(recipe);
} }
class DiffCurrentFileController : public DiffFilesController class DiffCurrentFileController : public DiffFilesController

View File

@@ -506,10 +506,10 @@ ShowController::ShowController(IDocument *document, const QString &id)
updateDescription(*data); updateDescription(*data);
}; };
const Group recipe { const For recipe {
iterator,
parallel, parallel,
continueOnSuccess, continueOnSuccess,
iterator,
ProcessTask(onFollowSetup, onFollowDone, CallDoneIf::Success), ProcessTask(onFollowSetup, onFollowDone, CallDoneIf::Success),
onGroupDone(onDone, CallDoneIf::Error) onGroupDone(onDone, CallDoneIf::Error)
}; };

View File

@@ -196,10 +196,10 @@ static Group installRecipe(
return DoneResult::Success; return DoneResult::Success;
}; };
return Group{ return For {
installOptionsIt,
storage, storage,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
installOptionsIt,
Group{ Group{
onGroupSetup([emitResult, storage, installOptionsIt] { onGroupSetup([emitResult, storage, installOptionsIt] {
const QString fileName = installOptionsIt->url.fileName(); const QString fileName = installOptionsIt->url.fileName();

View File

@@ -237,12 +237,12 @@ static QList<FileNode *> scanForFilesHelper(
} }
}; };
const Group group{ const For recipe {
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
iterator, iterator,
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone) Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone)
}; };
TaskTree::runBlocking(group); TaskTree::runBlocking(recipe);
} }
return fileNodes; return fileNodes;
} }

View File

@@ -1679,21 +1679,21 @@ private:
} }
}; };
const Group group{ const Group recipe {
Group{ For {
parallelIdealThreadCountLimit,
iteratorParentDirs, iteratorParentDirs,
parallelIdealThreadCountLimit,
AsyncTask<expected_str<void>>(onCreateDirSetup, onCreateDirDone), AsyncTask<expected_str<void>>(onCreateDirSetup, onCreateDirDone),
}, },
Group{ For {
parallelLimit(2),
iterator, iterator,
parallelLimit(2),
counterStorage, counterStorage,
AsyncTask<expected_str<void>>(onCopySetup, onCopyDone), AsyncTask<expected_str<void>>(onCopySetup, onCopyDone),
}, },
}; };
m_taskTree.start(group, {}, [this](DoneWith result) { m_taskTree.start(recipe, {}, [this](DoneWith result) {
ProcessResultData resultData; ProcessResultData resultData;
if (result != DoneWith::Success) { if (result != DoneWith::Success) {
resultData.m_exitCode = -1; resultData.m_exitCode = -1;

View File

@@ -278,15 +278,14 @@ GroupItem GenericLinuxDeviceTesterPrivate::commandTasks() const
emit q->errorMessage(message); emit q->errorMessage(message);
}; };
const Group root { return For {
iterator,
continueOnError, continueOnError,
onGroupSetup([this] { onGroupSetup([this] {
emit q->progressMessage(Tr::tr("Checking if required commands are available...")); emit q->progressMessage(Tr::tr("Checking if required commands are available..."));
}), }),
iterator,
ProcessTask(onSetup, onDone) ProcessTask(onSetup, onDone)
}; };
return root;
} }
} // namespace Internal } // namespace Internal

View File

@@ -2735,12 +2735,12 @@ void tst_Tasking::testTree_data()
{ {
const QList<GroupItem> successItems { const QList<GroupItem> successItems {
storage, storage,
LoopRepeat(2),
createSuccessTask(1), createSuccessTask(1),
createSuccessTask(2) createSuccessTask(2)
}; };
const Group rootSequentialSuccess { const For rootSequentialSuccess {
LoopRepeat(2),
sequential, sequential,
successItems successItems
}; };
@@ -2755,7 +2755,8 @@ void tst_Tasking::testTree_data()
{2, Handler::Success} {2, Handler::Success}
}; };
const Group rootParallelSuccess { const For rootParallelSuccess {
LoopRepeat(2),
parallel, parallel,
successItems successItems
}; };
@@ -2770,7 +2771,8 @@ void tst_Tasking::testTree_data()
{2, Handler::Success} {2, Handler::Success}
}; };
const Group rootParallelLimitSuccess { const For rootParallelLimitSuccess {
LoopRepeat(2),
parallelLimit(2), parallelLimit(2),
successItems successItems
}; };
@@ -2787,12 +2789,12 @@ void tst_Tasking::testTree_data()
const QList<GroupItem> errorItems { const QList<GroupItem> errorItems {
storage, storage,
LoopRepeat(2),
createSuccessTask(1), createSuccessTask(1),
createFailingTask(2) createFailingTask(2)
}; };
const Group rootSequentialError { const For rootSequentialError {
LoopRepeat(2),
sequential, sequential,
errorItems errorItems
}; };
@@ -2803,7 +2805,8 @@ void tst_Tasking::testTree_data()
{2, Handler::Error} {2, Handler::Error}
}; };
const Group rootParallelError { const For rootParallelError {
LoopRepeat(2),
parallel, parallel,
errorItems errorItems
}; };
@@ -2818,7 +2821,8 @@ void tst_Tasking::testTree_data()
{2, Handler::Canceled} {2, Handler::Canceled}
}; };
const Group rootParallelLimitError { const For rootParallelLimitError {
LoopRepeat(2),
parallelLimit(2), parallelLimit(2),
errorItems errorItems
}; };
@@ -2873,12 +2877,12 @@ void tst_Tasking::testTree_data()
const QList<GroupItem> items { const QList<GroupItem> items {
storage, storage,
loop,
TestTask(onSetupContinue(1), onDone(1)), TestTask(onSetupContinue(1), onDone(1)),
TestTask(onSetupStop(2), onDone(2)) TestTask(onSetupStop(2), onDone(2))
}; };
const Group rootSequential { const For rootSequential {
loop,
sequential, sequential,
items items
}; };
@@ -2896,7 +2900,8 @@ void tst_Tasking::testTree_data()
{22, Handler::Setup} {22, Handler::Setup}
}; };
const Group rootParallel { const For rootParallel {
loop,
parallel, parallel,
items items
}; };
@@ -2914,7 +2919,8 @@ void tst_Tasking::testTree_data()
{21, Handler::Success} {21, Handler::Success}
}; };
const Group rootParallelLimit { const For rootParallelLimit {
loop,
parallelLimit(2), parallelLimit(2),
items items
}; };
@@ -2942,9 +2948,9 @@ void tst_Tasking::testTree_data()
{ {
// Check if task tree finishes with the right progress value when LoopUntil(false). // Check if task tree finishes with the right progress value when LoopUntil(false).
const Group root { const For root {
storage,
LoopUntil([](int) { return false; }), LoopUntil([](int) { return false; }),
storage,
createSuccessTask(1) createSuccessTask(1)
}; };
QTest::newRow("ProgressWithLoopUntilFalse") QTest::newRow("ProgressWithLoopUntilFalse")
@@ -2953,10 +2959,10 @@ void tst_Tasking::testTree_data()
{ {
// Check if task tree finishes with the right progress value when nested LoopUntil(false). // Check if task tree finishes with the right progress value when nested LoopUntil(false).
const Group root { const For root {
storage,
LoopUntil([](int index) { return index < 2; }), LoopUntil([](int index) { return index < 2; }),
Group { storage,
For {
LoopUntil([](int) { return false; }), LoopUntil([](int) { return false; }),
createSuccessTask(1) createSuccessTask(1)
} }
@@ -2978,9 +2984,9 @@ void tst_Tasking::testTree_data()
{ {
// Check if task tree finishes with the right progress value when nested LoopUntil(false). // Check if task tree finishes with the right progress value when nested LoopUntil(false).
const Group root { const For root {
storage,
LoopUntil([](int index) { return index < 2; }), LoopUntil([](int index) { return index < 2; }),
storage,
Group { Group {
onGroupSetup([] { return SetupResult::StopWithSuccess; }), onGroupSetup([] { return SetupResult::StopWithSuccess; }),
createSuccessTask(1) createSuccessTask(1)
@@ -3157,10 +3163,10 @@ void tst_Tasking::testTree_data()
return DoneResult::Error; return DoneResult::Error;
}; };
const Group root { const For root {
iterator,
storage, storage,
parallel, parallel,
iterator,
TestTask(onSetup, onDone) TestTask(onSetup, onDone)
}; };

View File

@@ -509,9 +509,9 @@ void AssetDownloader::start()
onGroupSetup(onSkipIfAllAssetsPresent), onGroupSetup(onSkipIfAllAssetsPresent),
NetworkQueryTask(onZipDownloadSetup, onZipDownloadDone), NetworkQueryTask(onZipDownloadSetup, onZipDownloadDone),
ConcurrentCallTask<void>(onUnzipSetup, onUnzipDone), ConcurrentCallTask<void>(onUnzipSetup, onUnzipDone),
Group { For {
parallelIdealThreadCountLimit,
downloadIterator, downloadIterator,
parallelIdealThreadCountLimit,
onGroupSetup(onAssetsDownloadGroupSetup), onGroupSetup(onAssetsDownloadGroupSetup),
Group { Group {
assetStorage, assetStorage,
@@ -519,9 +519,9 @@ void AssetDownloader::start()
ConcurrentCallTask<void>(onAssetWriteSetup, onAssetWriteDone) ConcurrentCallTask<void>(onAssetWriteSetup, onAssetWriteDone)
} }
}, },
Group { For {
parallelIdealThreadCountLimit,
copyIterator, copyIterator,
parallelIdealThreadCountLimit,
onGroupSetup(onAssetsCopyGroupSetup), onGroupSetup(onAssetsCopyGroupSetup),
ConcurrentCallTask<void>(onAssetCopySetup, onAssetCopyDone) ConcurrentCallTask<void>(onAssetCopySetup, onAssetCopyDone)
} }

View File

@@ -74,7 +74,7 @@ Group recipe(const Storage<ExternalData> &externalStorage)
internalStorage, internalStorage,
NetworkQueryTask(onDownloadSetup, onDownloadDone), NetworkQueryTask(onDownloadSetup, onDownloadDone),
ConcurrentCallTask<QImage>(onReadSetup, onReadDone), ConcurrentCallTask<QImage>(onReadSetup, onReadDone),
Group { For {
repeater, repeater,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
ConcurrentCallTask<QImage>(onScaleSetup, onScaleDone) ConcurrentCallTask<QImage>(onScaleSetup, onScaleDone)

View File

@@ -93,10 +93,10 @@ void Images::process()
labels[it]->setText(tr("Image\nData\nError.")); labels[it]->setText(tr("Image\nData\nError."));
}; };
const QList<GroupItem> tasks { const For recipe {
iterator,
finishAllAndSuccess, finishAllAndSuccess,
parallel, parallel,
iterator,
onGroupSetup(onRootSetup), onGroupSetup(onRootSetup),
Group { Group {
storage, storage,
@@ -105,8 +105,7 @@ void Images::process()
}, },
onGroupDone(onRootDone, CallDoneIf::Success) onGroupDone(onRootDone, CallDoneIf::Success)
}; };
taskTreeRunner.start(recipe);
taskTreeRunner.start(tasks);
} }
void Images::initLayout(qsizetype count) void Images::initLayout(qsizetype count)