TaskTree: Refactor For loops

Make the syntax more consistent with conditional API.

Change-Id: I52353d0a0044252e1e3bac0b424ac7c22d927262
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Jarek Kobus
2024-09-14 00:50:35 +02:00
parent 6853e47fb8
commit 45157e7c42
26 changed files with 82 additions and 121 deletions

View File

@@ -1280,6 +1280,11 @@ const GroupItem nullItem = GroupItem({});
const ExecutableItem successItem = Group { finishAllAndSuccess }; const ExecutableItem successItem = Group { finishAllAndSuccess };
const ExecutableItem errorItem = Group { finishAllAndError }; const ExecutableItem errorItem = Group { finishAllAndError };
Group operator>>(const For &forItem, const Do &doItem)
{
return {forItem.m_loop, doItem.m_children};
}
// Please note the thread_local keyword below guarantees a separate instance per thread. // Please note the thread_local keyword below guarantees a separate instance per thread.
// The s_activeTaskTrees is currently used internally only and is not exposed in the public API. // The s_activeTaskTrees is currently used internally only and is not exposed in the public API.
// It serves for withLog() implementation now. Add a note here when a new usage is introduced. // It serves for withLog() implementation now. Add a note here when a new usage is introduced.

View File

@@ -196,6 +196,10 @@ private:
} }
}; };
class Do;
class For;
class Group;
class TASKING_EXPORT GroupItem class TASKING_EXPORT GroupItem
{ {
public: public:
@@ -274,8 +278,8 @@ protected:
} }
private: private:
TASKING_EXPORT friend Group operator>>(const For &forItem, const Do &doItem);
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;
@@ -435,42 +439,36 @@ 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 For : public Group class TASKING_EXPORT For final
{ {
public: public:
template <typename ...Args> explicit For(const Loop &loop) : m_loop(loop) {}
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: private:
template <typename ...Args> TASKING_EXPORT friend Group operator>>(const For &forItem, const Do &doItem);
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> Loop m_loop;
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 class TASKING_EXPORT Do final
{ {
public: public:
Forever(const QList<GroupItem> &children) : For(LoopForever(), children) {} explicit Do(const QList<GroupItem> &children) : m_children(children) {}
Forever(std::initializer_list<GroupItem> children) : For(LoopForever(), children) {} explicit Do(std::initializer_list<GroupItem> children) : m_children(children) {}
private:
TASKING_EXPORT friend Group operator>>(const For &forItem, const Do &doItem);
GroupItem m_children;
};
class TASKING_EXPORT Forever final : public ExecutableItem
{
public:
explicit Forever(const QList<GroupItem> &children)
{ addChildren({ For (LoopForever()) >> Do { children } } ); }
explicit Forever(std::initializer_list<GroupItem> children)
{ addChildren({ For (LoopForever()) >> Do { 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

@@ -138,8 +138,7 @@ static ExecutableItem serialNumberRecipe(const QString &avdName, const Storage<Q
return Group { return Group {
outputStorage, outputStorage,
AndroidConfig::devicesCommandOutputRecipe(outputStorage), AndroidConfig::devicesCommandOutputRecipe(outputStorage),
For { For (iterator) >> Do {
iterator,
parallel, parallel,
stopOnSuccess, stopOnSuccess,
Group { Group {

View File

@@ -417,13 +417,11 @@ GroupItem AndroidDeployQtStep::runRecipe()
onGroupDone(onSerialNumberGroupDone) onGroupDone(onSerialNumberGroupDone)
}, },
deployRecipe(), deployRecipe(),
For { For (iterator) >> Do {
iterator,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
AsyncTask<void>(onRemoveFileSetup) AsyncTask<void>(onRemoveFileSetup)
}, },
For { For (iterator) >> Do {
iterator,
ProcessTask(onAdbSetup, onAdbDone) ProcessTask(onAdbSetup, onAdbDone)
} }
}; };

View File

@@ -858,8 +858,7 @@ 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 = For { m_avdListRecipe = For (iterator) >> Do {
iterator,
storage, storage,
ProcessTask(onProcessSetup, onProcessDone) ProcessTask(onProcessSetup, onProcessDone)
}; };

View File

@@ -582,8 +582,7 @@ static ExecutableItem preStartRecipe(RunnerStorage *storage)
return Group { return Group {
argsStorage, argsStorage,
onGroupSetup(onArgsSetup), onGroupSetup(onArgsSetup),
For { For (iterator) >> Do {
iterator,
ProcessTask(onPreCommandSetup, onPreCommandDone, CallDoneIf::Error) ProcessTask(onPreCommandSetup, onPreCommandDone, CallDoneIf::Error)
}, },
Group { Group {
@@ -614,8 +613,7 @@ static ExecutableItem postDoneRecipe(RunnerStorage *storage)
return Group { return Group {
finishAllAndSuccess, finishAllAndSuccess,
For { For (iterator) >> Do {
iterator,
ProcessTask(onProcessSetup) ProcessTask(onProcessSetup)
}, },
onGroupDone(onDone) onGroupDone(onDone)
@@ -674,8 +672,7 @@ static ExecutableItem uploadDebugServerRecipe(RunnerStorage *storage, const QStr
return Group { return Group {
tempDebugServerPathStorage, tempDebugServerPathStorage,
For { For (iterator) >> Do {
iterator,
ProcessTask(onDeviceFileExistsSetup, onDeviceFileExistsDone) ProcessTask(onDeviceFileExistsSetup, onDeviceFileExistsDone)
}, },
Sync(onTempDebugServerPath), Sync(onTempDebugServerPath),

View File

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

View File

@@ -417,8 +417,7 @@ void TestCodeParser::scanForTests(const QSet<FilePath> &filePaths,
if (!results.isEmpty()) if (!results.isEmpty())
emit testParseResultsReady(results); emit testParseResultsReady(results);
}; };
const For recipe { const Group recipe = For (LoopRepeat(filteredFiles.size())) >> Do {
LoopRepeat(filteredFiles.size()),
parallelLimit(limit), parallelLimit(limit),
storage, storage,
onGroupSetup([storage, filteredFiles] { *storage = filteredFiles.cbegin(); }), onGroupSetup([storage, filteredFiles] { *storage = filteredFiles.cbegin(); }),

View File

@@ -461,8 +461,7 @@ void TestRunner::runTestsHelper()
} }
}; };
const For recipe { const Group recipe = For (iterator) >> Do {
iterator,
finishAllAndSuccess, finishAllAndSuccess,
Group { Group {
storage, storage,

View File

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

View File

@@ -181,8 +181,7 @@ GroupItem clangToolTask(CppEditor::ClangToolType toolType,
error}); error});
}; };
return For { return For (iterator) >> Do {
iterator,
parallelLimit(qMax(1, input.runSettings.parallelJobs())), parallelLimit(qMax(1, input.runSettings.parallelJobs())),
finishAllAndSuccess, finishAllAndSuccess,
Group { Group {

View File

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

View File

@@ -142,8 +142,7 @@ DiffFilesController::DiffFilesController(IDocument *document)
setDiffFiles(finalList); setDiffFiles(finalList);
}; };
const For recipe { const Group recipe = For (iterator) >> Do {
iterator,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
finishAllAndSuccess, finishAllAndSuccess,
storage, storage,

View File

@@ -534,8 +534,7 @@ ShowController::ShowController(IDocument *document, const QString &id)
updateDescription(*data); updateDescription(*data);
}; };
const For recipe { const Group recipe = For (iterator) >> Do {
iterator,
parallel, parallel,
continueOnSuccess, continueOnSuccess,
ProcessTask(onFollowSetup, onFollowDone, CallDoneIf::Success), ProcessTask(onFollowSetup, onFollowDone, CallDoneIf::Success),

View File

@@ -196,8 +196,7 @@ static Group installRecipe(
return DoneResult::Success; return DoneResult::Success;
}; };
return For { return For (installOptionsIt) >> Do {
installOptionsIt,
storage, storage,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
Group{ Group{

View File

@@ -246,8 +246,7 @@ static QList<FileNode *> scanForFilesHelper(
} }
}; };
const For recipe { const Group recipe = For (iterator) >> Do {
iterator,
Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit, Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone) Utils::AsyncTask<DirectoryScanResult>(onSetup, onDone)
}; };

View File

@@ -1646,13 +1646,11 @@ private:
}; };
const Group recipe { const Group recipe {
For { For (iteratorParentDirs) >> Do {
iteratorParentDirs,
parallelIdealThreadCountLimit, parallelIdealThreadCountLimit,
AsyncTask<expected_str<void>>(onCreateDirSetup, onCreateDirDone), AsyncTask<expected_str<void>>(onCreateDirSetup, onCreateDirDone),
}, },
For { For (iterator) >> Do {
iterator,
parallelLimit(2), parallelLimit(2),
counterStorage, counterStorage,
AsyncTask<expected_str<void>>(onCopySetup, onCopyDone), AsyncTask<expected_str<void>>(onCopySetup, onCopyDone),

View File

@@ -278,8 +278,7 @@ GroupItem GenericLinuxDeviceTesterPrivate::commandTasks() const
emit q->errorMessage(message); emit q->errorMessage(message);
}; };
return For { return For (iterator) >> Do {
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..."));

View File

@@ -2741,8 +2741,7 @@ void tst_Tasking::testTree_data()
createSuccessTask(2) createSuccessTask(2)
}; };
const For rootSequentialSuccess { const Group rootSequentialSuccess = For (LoopRepeat(2)) >> Do {
LoopRepeat(2),
sequential, sequential,
successItems successItems
}; };
@@ -2757,8 +2756,7 @@ void tst_Tasking::testTree_data()
{2, Handler::Success} {2, Handler::Success}
}; };
const For rootParallelSuccess { const Group rootParallelSuccess = For (LoopRepeat(2)) >> Do {
LoopRepeat(2),
parallel, parallel,
successItems successItems
}; };
@@ -2773,8 +2771,7 @@ void tst_Tasking::testTree_data()
{2, Handler::Success} {2, Handler::Success}
}; };
const For rootParallelLimitSuccess { const Group rootParallelLimitSuccess = For (LoopRepeat(2)) >> Do {
LoopRepeat(2),
parallelLimit(2), parallelLimit(2),
successItems successItems
}; };
@@ -2795,8 +2792,7 @@ void tst_Tasking::testTree_data()
createFailingTask(2) createFailingTask(2)
}; };
const For rootSequentialError { const Group rootSequentialError = For (LoopRepeat(2)) >> Do {
LoopRepeat(2),
sequential, sequential,
errorItems errorItems
}; };
@@ -2807,8 +2803,7 @@ void tst_Tasking::testTree_data()
{2, Handler::Error} {2, Handler::Error}
}; };
const For rootParallelError { const Group rootParallelError = For (LoopRepeat(2)) >> Do {
LoopRepeat(2),
parallel, parallel,
errorItems errorItems
}; };
@@ -2823,8 +2818,7 @@ void tst_Tasking::testTree_data()
{2, Handler::Canceled} {2, Handler::Canceled}
}; };
const For rootParallelLimitError { const Group rootParallelLimitError = For (LoopRepeat(2)) >> Do {
LoopRepeat(2),
parallelLimit(2), parallelLimit(2),
errorItems errorItems
}; };
@@ -2883,8 +2877,7 @@ void tst_Tasking::testTree_data()
TestTask(onSetupStop(2), onDone(2)) TestTask(onSetupStop(2), onDone(2))
}; };
const For rootSequential { const Group rootSequential = For(loop) >> Do {
loop,
sequential, sequential,
items items
}; };
@@ -2902,8 +2895,7 @@ void tst_Tasking::testTree_data()
{22, Handler::Setup} {22, Handler::Setup}
}; };
const For rootParallel { const Group rootParallel = For(loop) >> Do {
loop,
parallel, parallel,
items items
}; };
@@ -2921,8 +2913,7 @@ void tst_Tasking::testTree_data()
{21, Handler::Success} {21, Handler::Success}
}; };
const For rootParallelLimit { const Group rootParallelLimit = For(loop) >> Do {
loop,
parallelLimit(2), parallelLimit(2),
items items
}; };
@@ -2950,8 +2941,7 @@ 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 For root { const Group root = For(LoopUntil([](int) { return false; })) >> Do {
LoopUntil([](int) { return false; }),
storage, storage,
createSuccessTask(1) createSuccessTask(1)
}; };
@@ -2961,11 +2951,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 For root { const Group root = For (LoopUntil([](int index) { return index < 2; })) >> Do {
LoopUntil([](int index) { return index < 2; }),
storage, storage,
For { For (LoopUntil([](int) { return false; })) >> Do {
LoopUntil([](int) { return false; }),
createSuccessTask(1) createSuccessTask(1)
} }
}; };
@@ -2975,13 +2963,12 @@ void tst_Tasking::testTree_data()
{ {
// Check if LoopUntil is executed with empty loop body. // Check if LoopUntil is executed with empty loop body.
const For root { const LoopUntil iterator([storage](int iteration) {
LoopUntil([storage](int iteration) { storage->m_log.append({iteration, Handler::Iteration});
storage->m_log.append({iteration, Handler::Iteration}); return iteration < 3;
return iteration < 3; });
}),
storage const Group root = For(iterator) >> Do { storage };
};
const Log log { const Log log {
{0, Handler::Iteration}, {0, Handler::Iteration},
@@ -3007,8 +2994,7 @@ 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 For root { const Group root = For (LoopUntil([](int index) { return index < 2; })) >> Do {
LoopUntil([](int index) { return index < 2; }),
storage, storage,
Group { Group {
onGroupSetup([] { return SetupResult::StopWithSuccess; }), onGroupSetup([] { return SetupResult::StopWithSuccess; }),
@@ -3186,8 +3172,7 @@ void tst_Tasking::testTree_data()
return DoneResult::Error; return DoneResult::Error;
}; };
const For root { const Group root = For (iterator) >> Do {
iterator,
storage, storage,
parallel, parallel,
TestTask(onSetup, onDone) TestTask(onSetup, onDone)

View File

@@ -149,8 +149,7 @@ private slots:
parentDir.filePath(destDirName)); parentDir.filePath(destDirName));
}; };
const For recipe = { const Group recipe = For (iterator) >> Do {
iterator,
parallelIdealThreadCountLimit, // Parallelize tree generation parallelIdealThreadCountLimit, // Parallelize tree generation
AsyncTask<void>(onCopySetup) AsyncTask<void>(onCopySetup)
}; };
@@ -169,8 +168,7 @@ private slots:
parentDir.filePath(dirName(iterator.iteration() + 1))); parentDir.filePath(dirName(iterator.iteration() + 1)));
}; };
const For recipe = { const Group recipe = For (iterator) >> Do {
iterator,
parallelIdealThreadCountLimit, // Parallelize tree removal parallelIdealThreadCountLimit, // Parallelize tree removal
AsyncTask<void>(onSetup) AsyncTask<void>(onSetup)
}; };

View File

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

View File

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

View File

@@ -93,8 +93,7 @@ void Images::process()
labels[it]->setText(tr("Image\nData\nError.")); labels[it]->setText(tr("Image\nData\nError."));
}; };
const For recipe { const Group recipe = For (iterator) >> Do {
iterator,
finishAllAndSuccess, finishAllAndSuccess,
parallel, parallel,
onGroupSetup(onRootSetup), onGroupSetup(onRootSetup),

View File

@@ -16,7 +16,7 @@ int main(int argc, char **argv)
QApplication app(argc, argv); QApplication app(argc, argv);
GlueInterface iface; GlueInterface iface;
TaskTree taskTree(recipe(&iface)); TaskTree taskTree({recipe(&iface)});
TrafficLight widget(&iface); TrafficLight widget(&iface);
widget.show(); widget.show();

View File

@@ -11,7 +11,7 @@
using namespace Tasking; using namespace Tasking;
using namespace std::chrono; using namespace std::chrono;
Group recipe(GlueInterface *iface) ExecutableItem recipe(GlueInterface *iface)
{ {
return Forever { return Forever {
finishAllAndSuccess, finishAllAndSuccess,

View File

@@ -4,10 +4,10 @@
#ifndef RECIPE_H #ifndef RECIPE_H
#define RECIPE_H #define RECIPE_H
namespace Tasking { class Group; } namespace Tasking { class ExecutableItem; }
class GlueInterface; class GlueInterface;
Tasking::Group recipe(GlueInterface *iface); Tasking::ExecutableItem recipe(GlueInterface *iface);
#endif // RECIPE_H #endif // RECIPE_H