5#ifndef TASKING_TASKTREE_H
6#define TASKING_TASKTREE_H
21#include <QtCore/QList>
22#include <QtCore/QObject>
56Q_ENUM_NS(WorkflowPolicy)
103 template <
typename Task,
typename Deleter>
friend class TaskAdapter;
105 TaskInterface() =
default;
122 Loop(
int count,
const ValueGetter &valueGetter = {});
123 Loop(
const Condition &condition);
152class LoopList
final :
public Loop
155 LoopList(
const QList<T> &list) :
Loop(list.size(), [list](
int i) {
return &list.at(i); }) {}
167 StorageBase(
const StorageConstructor &ctor,
const StorageDestructor &dtor);
169 void *activeStorageVoid()
const;
172 {
return first.m_storageData == second.m_storageData; }
175 {
return first.m_storageData != second.m_storageData; }
178 {
return size_t(storage.m_storageData.get()) ^ seed; }
182 template <
typename StorageStruct>
friend class Storage;
190template <
typename StorageStruct>
198 return static_cast<StorageStruct *>(activeStorageVoid());
202 static StorageConstructor ctor() {
return [] {
return new StorageStruct(); }; }
203 static StorageDestructor dtor() {
204 return [](
void *storage) {
delete static_cast<StorageStruct *>(storage); };
216 template <
typename StorageStruct>
270 void addChildren(
const QList<GroupItem> &children);
275 template <
typename Result,
typename Function,
typename ...Args,
280 if constexpr (std::is_invocable_r_v<Result, DecayedFunction, Args...>)
281 return std::is_same_v<Result, std::invoke_result_t<DecayedFunction, Args...>>;
293 QList<GroupItem> m_children;
295 QList<StorageBase> m_storageList;
303 const std::function<
void()> &handler = {})
const;
305 template <
typename SenderSignalPairGetter>
308 const auto connectWrapper = [getter](QObject *guard,
const std::function<
void()> &trigger) {
309 const auto senderSignalPair = getter();
310 QObject::connect(senderSignalPair.first, senderSignalPair.second, guard, [trigger] {
312 },
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
314 return withCancelImpl(connectWrapper);
331 const std::function<
void(QObject *,
const std::function<
void()> &)> &connectWrapper)
const;
337 Group(
const QList<GroupItem> &children) { addChildren(children); }
338 Group(std::initializer_list<GroupItem> children) { addChildren(children); }
341 template <
typename Handler>
345 template <
typename Handler>
347 return groupHandler({{}, wrapGroupDone(
std::forward<Handler>(handler)), callDoneIf}
);
351 template <
typename Handler>
352 static GroupSetupHandler wrapGroupSetup(Handler &&handler)
355 static constexpr bool isR = isInvocable<
SetupResult, Handler>();
356 static constexpr bool isV = isInvocable<
void, Handler>();
357 static_assert(isR || isV,
358 "Group setup handler needs to take no arguments and has to return void or SetupResult. "
359 "The passed handler doesn't fulfill these requirements.");
362 return std::invoke(handler);
363 std::invoke(handler);
367 template <
typename Handler>
368 static GroupDoneHandler wrapGroupDone(Handler &&handler)
370 static constexpr bool isDoneResultType =
std::is_same_v<Handler,
DoneResult>;
373 static constexpr bool isR = isInvocable<
DoneResult, Handler>();
374 static constexpr bool isBD = isInvocable<
bool, Handler,
DoneWith>();
375 static constexpr bool isB = isInvocable<
bool, Handler>();
376 static constexpr bool isVD = isInvocable<
void, Handler,
DoneWith>();
377 static constexpr bool isV = isInvocable<
void, Handler>();
378 static_assert(isDoneResultType || isRD || isR || isBD || isB || isVD || isV,
379 "Group done handler needs to take (DoneWith) or (void) as an argument and has to "
380 "return void, bool or DoneResult. Alternatively, it may be of DoneResult type. "
381 "The passed handler doesn't fulfill these requirements.");
383 if constexpr (isDoneResultType)
386 return std::invoke(handler, result);
388 return std::invoke(handler);
390 return toDoneResult(std::invoke(handler, result));
392 return toDoneResult(std::invoke(handler));
394 std::invoke(handler, result);
395 else if constexpr (isV)
396 std::invoke(handler);
402template <
typename Handler>
405 return Group::onGroupSetup(
std::forward<Handler>(handler));
408template <
typename Handler>
411 return Group::onGroupDone(
std::forward<Handler>(handler), callDoneIf);
450 template <
typename ...Args>
452 :
Group(withLoop(loop, args...)) { }
455 For(
const Loop &loop,
const QList<GroupItem> &children) :
Group({loop, children}) {}
456 For(
const Loop &loop, std::initializer_list<GroupItem> children) :
Group({loop, children}) {}
459 template <
typename ...Args>
460 QList<GroupItem> withLoop(
const Loop &loop,
const Args &...args) {
462 appendChildren(
std::make_tuple(args...), &children);
466 template <
typename Tuple,
std::size_t N = 0>
467 void appendChildren(
const Tuple &tuple, QList<GroupItem> *children) {
468 constexpr auto TupleSize =
std::tuple_size_v<Tuple>;
469 if constexpr (TupleSize > 0) {
471 children->append(
std::get<N>(tuple));
472 if constexpr (N + 1 < TupleSize)
473 appendChildren<Tuple, N + 1>(tuple, children);
481 Forever(
const QList<GroupItem> &children) :
For(LoopForever
(), children) {}
482 Forever(std::initializer_list<GroupItem> children) :
For(LoopForever
(), children) {}
489 template <
typename Handler>
491 addChildren({ onGroupDone(wrapHandler(std::forward<Handler>(handler))) });
495 template <
typename Handler>
496 static auto wrapHandler(Handler &&handler) {
498 static constexpr bool isR = isInvocable<
DoneResult, Handler>();
499 static constexpr bool isB = isInvocable<
bool, Handler>();
500 static constexpr bool isV = isInvocable<
void, Handler>();
501 static_assert(isR || isB || isV,
502 "Sync handler needs to take no arguments and has to return void, bool or DoneResult. "
503 "The passed handler doesn't fulfill these requirements.");
508template <
typename Task,
typename Deleter =
std::default_delete<Task>>
513 Task *
task() {
return m_task.get(); }
514 const Task *
task()
const {
return m_task.get(); }
517 using TaskType = Task;
518 using DeleterType = Deleter;
520 std::unique_ptr<Task, Deleter> m_task;
523template <
typename Adapter>
527 using Task =
typename Adapter::TaskType;
528 using Deleter =
typename Adapter::DeleterType;
529 static_assert(
std::is_base_of_v<
TaskAdapter<Task, Deleter>, Adapter>,
530 "The Adapter type for the CustomTask<Adapter> needs to be derived from "
531 "TaskAdapter<Task>.");
536 CustomTask(SetupHandler &&setup = TaskSetupHandler(), DoneHandler &&done = TaskDoneHandler(),
539 wrapDone(
std::forward<DoneHandler>(done)), callDoneIf})
543 static Adapter *createAdapter() {
return new Adapter; }
545 template <
typename Handler>
546 static InterfaceSetupHandler wrapSetup(Handler &&handler) {
547 if constexpr (std::is_same_v<Handler, TaskSetupHandler>)
550 static constexpr bool isR = isInvocable<
SetupResult, Handler, Task &>();
551 static constexpr bool isV = isInvocable<
void, Handler, Task &>();
552 static_assert(isR || isV,
553 "Task setup handler needs to take (Task &) as an argument and has to return void or "
554 "SetupResult. The passed handler doesn't fulfill these requirements.");
556 Adapter &adapter =
static_cast<Adapter &>(taskInterface);
558 return std::invoke(handler, *adapter.task());
559 std::invoke(handler, *adapter.task());
564 template <
typename Handler>
565 static InterfaceDoneHandler wrapDone(Handler &&handler) {
566 if constexpr (std::is_same_v<Handler, TaskDoneHandler>)
568 static constexpr bool isDoneResultType =
std::is_same_v<Handler,
DoneResult>;
570 static constexpr bool isRTD = isInvocable<
DoneResult, Handler,
const Task &,
DoneWith>();
571 static constexpr bool isRT = isInvocable<
DoneResult, Handler,
const Task &>();
573 static constexpr bool isR = isInvocable<
DoneResult, Handler>();
574 static constexpr bool isBTD = isInvocable<
bool, Handler,
const Task &,
DoneWith>();
575 static constexpr bool isBT = isInvocable<
bool, Handler,
const Task &>();
576 static constexpr bool isBD = isInvocable<
bool, Handler,
DoneWith>();
577 static constexpr bool isB = isInvocable<
bool, Handler>();
578 static constexpr bool isVTD = isInvocable<
void, Handler,
const Task &,
DoneWith>();
579 static constexpr bool isVT = isInvocable<
void, Handler,
const Task &>();
580 static constexpr bool isVD = isInvocable<
void, Handler,
DoneWith>();
581 static constexpr bool isV = isInvocable<
void, Handler>();
582 static_assert(isDoneResultType || isRTD || isRT || isRD || isR
583 || isBTD || isBT || isBD || isB
584 || isVTD || isVT || isVD || isV,
585 "Task done handler needs to take (const Task &, DoneWith), (const Task &), "
586 "(DoneWith) or (void) as arguments and has to return void, bool or DoneResult. "
587 "Alternatively, it may be of DoneResult type. "
588 "The passed handler doesn't fulfill these requirements.");
590 if constexpr (isDoneResultType)
592 const Adapter &adapter =
static_cast<
const Adapter &>(taskInterface);
594 return std::invoke(handler, *adapter.task(), result);
596 return std::invoke(handler, *adapter.task());
598 return std::invoke(handler, result);
600 return std::invoke(handler);
602 return toDoneResult(std::invoke(handler, *adapter.task(), result));
604 return toDoneResult(std::invoke(handler, *adapter.task()));
606 return toDoneResult(std::invoke(handler, result));
608 return toDoneResult(std::invoke(handler));
610 std::invoke(handler, *adapter.task(), result);
611 else if constexpr (isVT)
612 std::invoke(handler, *adapter.task());
613 else if constexpr (isVD)
614 std::invoke(handler, result);
615 else if constexpr (isV)
616 std::invoke(handler);
652 template <
typename StorageStruct,
typename Handler>
654 static_assert(std::is_invocable_v<std::decay_t<Handler>, StorageStruct &>,
655 "Storage setup handler needs to take (Storage &) as an argument. "
656 "The passed handler doesn't fulfill this requirement.");
657 setupStorageHandler(storage,
658 wrapHandler<StorageStruct>(std::forward<Handler>(handler)), {});
660 template <
typename StorageStruct,
typename Handler>
662 static_assert(std::is_invocable_v<std::decay_t<Handler>,
const StorageStruct &>,
663 "Storage done handler needs to take (const Storage &) as an argument. "
664 "The passed handler doesn't fulfill this requirement.");
665 setupStorageHandler(storage, {},
666 wrapHandler<
const StorageStruct>(std::forward<Handler>(handler)));
676 void setupStorageHandler(
const StorageBase &storage,
677 StorageBase::StorageHandler setupHandler,
678 StorageBase::StorageHandler doneHandler);
679 template <
typename StorageStruct,
typename Handler>
680 StorageBase::StorageHandler wrapHandler(Handler &&handler) {
681 return [handler](
void *voidStruct) {
682 auto *storageStruct =
static_cast<StorageStruct *>(voidStruct);
683 std::invoke(handler, *storageStruct);
707 std::optional<
int> m_timerId;
void setupDownload(NetworkQuery *query, const QString &progressText)
QDir m_preferredLocalDownloadDir
void setLocalDownloadDir(const QDir &dir)
void setProgress(int progressValue, int progressMaximum, const QString &progressText)
QUrl m_offlineAssetsFilePath
AssetDownloaderPrivate(AssetDownloader *q)
void clearProgress(const QString &progressText)
TaskTreeRunner m_taskTreeRunner
QString m_lastProgressText
void updateProgress(int progressValue, int progressMaximum)
std::unique_ptr< QNetworkAccessManager > m_manager
std::unique_ptr< QTemporaryDir > m_temporaryDir
void progressChanged(int progressValue, int progressMaximum, const QString &progressText)
void localDownloadDirChanged(const QUrl &url)
void setOfflineAssetsFilePath(const QUrl &offlineAssetsFilePath)
QUrl preferredLocalDownloadDir() const
QUrl downloadBase() const
virtual QUrl resolvedUrl(const QUrl &url) const
void setJsonFileName(const QString &jsonFileName)
void jsonFileNameChanged(const QString &)
void downloadBaseChanged(const QUrl &)
void setPreferredLocalDownloadDir(const QUrl &localDir)
void offlineAssetsFilePathChanged(const QUrl &)
QString jsonFileName() const
QUrl offlineAssetsFilePath() const
void setDownloadBase(const QUrl &downloadBase)
QString zipFileName() const
void setZipFileName(const QString &zipFileName)
void finished(bool success)
QUrl localDownloadDir() const
void zipFileNameChanged(const QString &)
void preferredLocalDownloadDirChanged(const QUrl &url)
void start() final
This method is called by the running TaskTree for starting the Task instance.
~ConcurrentCallTaskAdapter()
void setThreadPool(QThreadPool *pool)
QFuture< ResultType > future() const
QList< ResultType > results() const
ResultType result() const
void setConcurrentCallData(Function &&function, Args &&...args)
CustomTask(SetupHandler &&setup=TaskSetupHandler(), DoneHandler &&done=TaskDoneHandler(), CallDoneIf callDoneIf=CallDoneIf::SuccessOrError)
\typealias Tasking::CustomTask::Task
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
ExecutableItem withTimeout(std::chrono::milliseconds timeout, const std::function< void()> &handler={}) const
Attaches TimeoutTask to a copy of this ExecutableItem, elapsing after timeout in milliseconds,...
ExecutableItem withLog(const QString &logName) const
Attaches a custom debug printout to a copy of this ExecutableItem, issued on task startup and after t...
ExecutableItem(const TaskHandler &handler)
ExecutableItem withCancel(SenderSignalPairGetter &&getter) const
For(const Loop &loop, const Args &...args)
For(const Loop &loop, const QList< GroupItem > &children)
For(const Loop &loop, std::initializer_list< GroupItem > children)
Forever(std::initializer_list< GroupItem > children)
Forever(const QList< GroupItem > &children)
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
GroupItem(const Loop &loop)
GroupItem(std::initializer_list< GroupItem > children)
This is an overloaded member function, provided for convenience. It differs from the above function o...
GroupItem(const TaskHandler &handler)
void addChildren(const QList< GroupItem > &children)
GroupItem(const GroupData &data)
GroupItem(const QList< GroupItem > &children)
Constructs a GroupItem element with a given list of items.
GroupItem(const Storage< StorageStruct > &storage)
Constructs a GroupItem element holding the storage object.
static GroupItem groupHandler(const GroupHandler &handler)
static constexpr bool isInvocable()
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
static GroupItem onGroupSetup(Handler &&handler)
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf=CallDoneIf::SuccessOrError)
Group(std::initializer_list< GroupItem > children)
Constructs a group from std::initializer_list given by children.
Group(const QList< GroupItem > &children)
Constructs a group with a given list of children.
const T & operator*() const
LoopList(const QList< T > &list)
const T * operator->() const
LoopUntil(const Condition &condition)
Loop(int count, const ValueGetter &valueGetter={})
Loop(const Condition &condition)
const void * valuePtr() const
GroupItem operator()(int limit) const
Constructs a group's element describing the \l{Execution Mode}{execution mode}.
friend bool operator==(const StorageBase &first, const StorageBase &second)
friend size_t qHash(const StorageBase &storage, uint seed=0)
friend bool operator!=(const StorageBase &first, const StorageBase &second)
StorageStruct * operator->() const noexcept
Returns a pointer to the active StorageStruct object, created by the running task tree.
StorageStruct & operator*() const noexcept
Returns a reference to the active StorageStruct object, created by the running task tree.
Storage()
Creates a storage for the given StorageStruct type.
StorageStruct * activeStorage() const
Returns a pointer to the active StorageStruct object, created by the running task tree.
Sync(Handler &&handler)
Constructs an element that executes a passed handler synchronously.
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
const Task * task() const
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
virtual void start()=0
This method is called by the running TaskTree for starting the Task instance.
void start() final
This method is called by the running TaskTree for starting the Task instance.
void done(DoneWith result)
This signal is emitted when the task tree finished, passing the final result of the execution.
DoneWith runBlocking(const QFuture< void > &future)
int progressMaximum() const
Returns the maximum progressValue().
TaskTree()
Constructs an empty task tree.
int taskCount() const
Returns the number of asynchronous tasks contained in the stored recipe.
void cancel()
Cancels the execution of the running task tree.
void start()
Starts the task tree.
void onStorageSetup(const Storage< StorageStruct > &storage, Handler &&handler)
Installs a storage setup handler for the storage to pass the initial data dynamically to the running ...
~TaskTree()
Destroys the task tree.
bool isRunning() const
Returns true if the task tree is currently running; otherwise returns false.
void onStorageDone(const Storage< StorageStruct > &storage, Handler &&handler)
Installs a storage done handler for the storage to retrieve the final data dynamically from the runni...
void setRecipe(const Group &recipe)
Sets a given recipe for the task tree.
void asyncCountChanged(int count)
This signal is emitted when the running task tree is about to return control to the caller's event lo...
static DoneWith runBlocking(const Group &recipe, const QFuture< void > &future, std::chrono::milliseconds timeout=std::chrono::milliseconds::max())
TaskTree(const Group &recipe)
This is an overloaded member function, provided for convenience. It differs from the above function o...
int progressValue() const
Returns the current progress value, which is between the 0 and progressMaximum().
DoneWith runBlocking()
Executes a local event loop with QEventLoop::ExcludeUserInputEvents and starts the task tree.
static DoneWith runBlocking(const Group &recipe, std::chrono::milliseconds timeout=std::chrono::milliseconds::max())
void progressValueChanged(int value)
This signal is emitted when the running task tree finished, canceled, or skipped some tasks.
int asyncCount() const
Returns the current real count of asynchronous chains of invocations.
void start() final
This method is called by the running TaskTree for starting the Task instance.
GroupItem operator()(WorkflowPolicy policy) const
Constructs a group's \l {Workflow Policy} {workflow policy} element for a given policy.
static void unzip(QPromise< void > &promise, const QByteArray &content, const QDir &directory, const QString &fileName)
static bool sameFileContent(const QFileInfo &first, const QFileInfo &second)
static void writeAsset(QPromise< void > &promise, const QByteArray &content, const QString &filePath)
static void precheckLocalFile(const QUrl &url)
static QDir baseLocalDir(const QDir &preferredLocalDir)
static QString pathFromUrl(const QUrl &url)
static bool allAssetsPresent(const QList< QUrl > &assetFiles, const QDir &expectedDir)
static void copyAndCheck(QPromise< void > &promise, const QString &sourcePath, const QString &destPath)
static bool canBeALocalBaseDir(const QDir &dir)
static QList< QUrl > filterDownloadableAssets(const QList< QUrl > &assetFiles, const QDir &expectedDir)
static void readAssetsFileContent(QPromise< DownloadableAssets > &promise, const QByteArray &content)
static bool createDirectory(const QDir &dir)
static bool isWritableDir(const QDir &dir)
Combined button and popup list for selecting options.
\inmodule TaskingSolution
const ExecutableItem successItem
const GroupItem sequential
const GroupItem continueOnSuccess
const GroupItem stopOnError
const GroupItem finishAllAndError
ExecutableItem operator&&(const ExecutableItem &first, const ExecutableItem &second)
const ExecutableItem errorItem
const ParallelLimitFunctor parallelLimit
ExecutableItem operator||(const ExecutableItem &item, DoneResult result)
const GroupItem finishAllAndSuccess
ExecutableItem operator!(const ExecutableItem &item)
DoneResult toDoneResult(bool success)
const GroupItem parallelIdealThreadCountLimit
ExecutableItem operator||(const ExecutableItem &first, const ExecutableItem &second)
const GroupItem stopOnSuccessOrError
ExecutableItem operator&&(const ExecutableItem &item, DoneResult result)
static GroupItem onGroupSetup(Handler &&handler)
\typealias Tasking::GroupItem::GroupSetupHandler
const GroupItem continueOnError
const WorkflowPolicyFunctor workflowPolicy
const GroupItem stopOnSuccess
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf=CallDoneIf::SuccessOrError)
Constructs a group's element holding the group done handler.
GroupHandler m_groupHandler
std::optional< WorkflowPolicy > m_workflowPolicy
std::optional< int > m_parallelLimit
std::optional< Loop > m_loop
GroupDoneHandler m_doneHandler
GroupSetupHandler m_setupHandler
InterfaceSetupHandler m_setupHandler
InterfaceCreateHandler m_createHandler
InterfaceDoneHandler m_doneHandler