AssetDownloader: Sync TaskTree sources
Change-Id: Ib3727dbca7b27e796b6fab084cbaaa9890b78118 Reviewed-by: Kai Köhne <kai.koehne@qt.io> (cherry picked from commit f4db5ce8a8e6994b4dce407977f4e936dcd7f48e) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
d62a2decaf
commit
5fa620173e
@ -9,11 +9,13 @@ qt_internal_add_module(ExamplesAssetDownloaderPrivate
|
|||||||
assetdownloader.cpp assetdownloader.h
|
assetdownloader.cpp assetdownloader.h
|
||||||
tasking/barrier.cpp tasking/barrier.h
|
tasking/barrier.cpp tasking/barrier.h
|
||||||
tasking/concurrentcall.h
|
tasking/concurrentcall.h
|
||||||
|
tasking/conditional.cpp tasking/conditional.h
|
||||||
tasking/networkquery.cpp tasking/networkquery.h
|
tasking/networkquery.cpp tasking/networkquery.h
|
||||||
tasking/qprocesstask.cpp tasking/qprocesstask.h
|
tasking/qprocesstask.cpp tasking/qprocesstask.h
|
||||||
tasking/tasking_global.h
|
tasking/tasking_global.h
|
||||||
tasking/tasktree.cpp tasking/tasktree.h
|
tasking/tasktree.cpp tasking/tasktree.h
|
||||||
tasking/tasktreerunner.cpp tasking/tasktreerunner.h
|
tasking/tasktreerunner.cpp tasking/tasktreerunner.h
|
||||||
|
tasking/tcpsocket.cpp tasking/tcpsocket.h
|
||||||
DEFINES
|
DEFINES
|
||||||
QT_NO_CAST_FROM_ASCII
|
QT_NO_CAST_FROM_ASCII
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
|
@ -537,9 +537,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,
|
||||||
@ -547,9 +547,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, CallDoneIf::Success),
|
ConcurrentCallTask<void>(onAssetCopySetup, onAssetCopyDone, CallDoneIf::Success),
|
||||||
onGroupDone(onAssetsCopyGroupDone)
|
onGroupDone(onAssetsCopyGroupDone)
|
||||||
|
@ -82,7 +82,7 @@ using MultiBarrier = Storage<SharedBarrier<Limit>>;
|
|||||||
using SingleBarrier = MultiBarrier<1>;
|
using SingleBarrier = MultiBarrier<1>;
|
||||||
|
|
||||||
template <int Limit>
|
template <int Limit>
|
||||||
GroupItem waitForBarrierTask(const MultiBarrier<Limit> &sharedBarrier)
|
ExecutableItem waitForBarrierTask(const MultiBarrier<Limit> &sharedBarrier)
|
||||||
{
|
{
|
||||||
return BarrierTask([sharedBarrier](Barrier &barrier) {
|
return BarrierTask([sharedBarrier](Barrier &barrier) {
|
||||||
SharedBarrier<Limit> *activeBarrier = sharedBarrier.activeStorage();
|
SharedBarrier<Limit> *activeBarrier = sharedBarrier.activeStorage();
|
||||||
|
108
src/assets/downloader/tasking/conditional.cpp
Normal file
108
src/assets/downloader/tasking/conditional.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// Copyright (C) 2024 Jarek Kobus
|
||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
#include "conditional.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace Tasking {
|
||||||
|
|
||||||
|
static Group conditionRecipe(const Storage<bool> &bodyExecutedStorage,
|
||||||
|
const ConditionData &condition)
|
||||||
|
{
|
||||||
|
Storage<bool> skipContinuationStorage;
|
||||||
|
|
||||||
|
const auto onSetup = [bodyExecutedStorage] {
|
||||||
|
return *bodyExecutedStorage ? SetupResult::StopWithSuccess : SetupResult::Continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto onConditionDone = [skipContinuationStorage](DoneWith result) {
|
||||||
|
*skipContinuationStorage = result != DoneWith::Success;
|
||||||
|
return DoneResult::Success;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto onContinuationSetup = [skipContinuationStorage, bodyExecutedStorage] {
|
||||||
|
*bodyExecutedStorage = !*skipContinuationStorage;
|
||||||
|
return *skipContinuationStorage ? SetupResult::StopWithSuccess : SetupResult::Continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
skipContinuationStorage,
|
||||||
|
onGroupSetup(onSetup),
|
||||||
|
condition.m_condition ? Group {
|
||||||
|
*condition.m_condition,
|
||||||
|
onGroupDone(onConditionDone)
|
||||||
|
} : nullItem,
|
||||||
|
Group {
|
||||||
|
onGroupSetup(onContinuationSetup),
|
||||||
|
condition.m_body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ExecutableItem conditionsRecipe(const QList<ConditionData> &conditions)
|
||||||
|
{
|
||||||
|
Storage<bool> bodyExecutedStorage;
|
||||||
|
|
||||||
|
QList<GroupItem> recipes;
|
||||||
|
for (const ConditionData &condition : conditions)
|
||||||
|
recipes << conditionRecipe(bodyExecutedStorage, condition);
|
||||||
|
|
||||||
|
return Group { bodyExecutedStorage, recipes };
|
||||||
|
}
|
||||||
|
|
||||||
|
ThenItem::operator ExecutableItem() const
|
||||||
|
{
|
||||||
|
return conditionsRecipe(m_conditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThenItem::ThenItem(const If &ifItem, const Then &thenItem)
|
||||||
|
: m_conditions{{ifItem.m_condition, thenItem.m_body}}
|
||||||
|
{}
|
||||||
|
|
||||||
|
ThenItem::ThenItem(const ElseIfItem &elseIfItem, const Then &thenItem)
|
||||||
|
: m_conditions(elseIfItem.m_conditions)
|
||||||
|
{
|
||||||
|
m_conditions.append({elseIfItem.m_nextCondition, thenItem.m_body});
|
||||||
|
}
|
||||||
|
|
||||||
|
ElseItem::operator ExecutableItem() const
|
||||||
|
{
|
||||||
|
return conditionsRecipe(m_conditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElseItem::ElseItem(const ThenItem &thenItem, const Else &elseItem)
|
||||||
|
: m_conditions(thenItem.m_conditions)
|
||||||
|
{
|
||||||
|
m_conditions.append({{}, elseItem.m_body});
|
||||||
|
}
|
||||||
|
|
||||||
|
ElseIfItem::ElseIfItem(const ThenItem &thenItem, const ElseIf &elseIfItem)
|
||||||
|
: m_conditions(thenItem.m_conditions)
|
||||||
|
, m_nextCondition(elseIfItem.m_condition)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ThenItem operator>>(const If &ifItem, const Then &thenItem)
|
||||||
|
{
|
||||||
|
return {ifItem, thenItem};
|
||||||
|
}
|
||||||
|
|
||||||
|
ThenItem operator>>(const ElseIfItem &elseIfItem, const Then &thenItem)
|
||||||
|
{
|
||||||
|
return {elseIfItem, thenItem};
|
||||||
|
}
|
||||||
|
|
||||||
|
ElseIfItem operator>>(const ThenItem &thenItem, const ElseIf &elseIfItem)
|
||||||
|
{
|
||||||
|
return {thenItem, elseIfItem};
|
||||||
|
}
|
||||||
|
|
||||||
|
ElseItem operator>>(const ThenItem &thenItem, const Else &elseItem)
|
||||||
|
{
|
||||||
|
return {thenItem, elseItem};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tasking
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
142
src/assets/downloader/tasking/conditional.h
Normal file
142
src/assets/downloader/tasking/conditional.h
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// Copyright (C) 2024 Jarek Kobus
|
||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
#ifndef TASKING_CONDITIONAL_H
|
||||||
|
#define TASKING_CONDITIONAL_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists purely as an
|
||||||
|
// implementation detail. This header file may change from version to
|
||||||
|
// version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "tasking_global.h"
|
||||||
|
|
||||||
|
#include "tasktree.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace Tasking {
|
||||||
|
|
||||||
|
class Then;
|
||||||
|
class ThenItem;
|
||||||
|
class ElseItem;
|
||||||
|
class ElseIfItem;
|
||||||
|
|
||||||
|
class TASKING_EXPORT If
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit If(const ExecutableItem &condition) : m_condition(condition) {}
|
||||||
|
|
||||||
|
template <typename Handler,
|
||||||
|
std::enable_if_t<!std::is_base_of_v<ExecutableItem, std::decay_t<Handler>>, bool> = true>
|
||||||
|
explicit If(Handler &&handler) : m_condition(Sync(std::forward<Handler>(handler))) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TASKING_EXPORT friend ThenItem operator>>(const If &ifItem, const Then &thenItem);
|
||||||
|
|
||||||
|
friend class ThenItem;
|
||||||
|
ExecutableItem m_condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TASKING_EXPORT ElseIf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ElseIf(const ExecutableItem &condition) : m_condition(condition) {}
|
||||||
|
|
||||||
|
template <typename Handler,
|
||||||
|
std::enable_if_t<!std::is_base_of_v<ExecutableItem, std::decay_t<Handler>>, bool> = true>
|
||||||
|
explicit ElseIf(Handler &&handler) : m_condition(Sync(std::forward<Handler>(handler))) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ElseIfItem;
|
||||||
|
ExecutableItem m_condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TASKING_EXPORT Else
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Else(const QList<GroupItem> &children) : m_body({children}) {}
|
||||||
|
explicit Else(std::initializer_list<GroupItem> children) : m_body({children}) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ElseItem;
|
||||||
|
Group m_body;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TASKING_EXPORT Then
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Then(const QList<GroupItem> &children) : m_body({children}) {}
|
||||||
|
explicit Then(std::initializer_list<GroupItem> children) : m_body({children}) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ThenItem;
|
||||||
|
Group m_body;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConditionData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::optional<ExecutableItem> m_condition;
|
||||||
|
Group m_body;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ElseIfItem;
|
||||||
|
|
||||||
|
class TASKING_EXPORT ThenItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
operator ExecutableItem() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ThenItem(const If &ifItem, const Then &thenItem);
|
||||||
|
ThenItem(const ElseIfItem &elseIfItem, const Then &thenItem);
|
||||||
|
|
||||||
|
TASKING_EXPORT friend ElseItem operator>>(const ThenItem &thenItem, const Else &elseItem);
|
||||||
|
TASKING_EXPORT friend ElseIfItem operator>>(const ThenItem &thenItem, const ElseIf &elseIfItem);
|
||||||
|
TASKING_EXPORT friend ThenItem operator>>(const If &ifItem, const Then &thenItem);
|
||||||
|
TASKING_EXPORT friend ThenItem operator>>(const ElseIfItem &elseIfItem, const Then &thenItem);
|
||||||
|
|
||||||
|
friend class ElseItem;
|
||||||
|
friend class ElseIfItem;
|
||||||
|
QList<ConditionData> m_conditions;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TASKING_EXPORT ElseItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
operator ExecutableItem() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ElseItem(const ThenItem &thenItem, const Else &elseItem);
|
||||||
|
|
||||||
|
TASKING_EXPORT friend ElseItem operator>>(const ThenItem &thenItem, const Else &elseItem);
|
||||||
|
|
||||||
|
QList<ConditionData> m_conditions;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TASKING_EXPORT ElseIfItem
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ElseIfItem(const ThenItem &thenItem, const ElseIf &elseIfItem);
|
||||||
|
|
||||||
|
TASKING_EXPORT friend ThenItem operator>>(const ElseIfItem &elseIfItem, const Then &thenItem);
|
||||||
|
TASKING_EXPORT friend ElseIfItem operator>>(const ThenItem &thenItem, const ElseIf &elseIfItem);
|
||||||
|
|
||||||
|
friend class ThenItem;
|
||||||
|
QList<ConditionData> m_conditions;
|
||||||
|
ExecutableItem m_nextCondition;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Tasking
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // TASKING_CONDITIONAL_H
|
@ -629,19 +629,19 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias CustomTask::Task
|
\typealias Tasking::CustomTask::Task
|
||||||
|
|
||||||
Type alias for the task type associated with the custom task's \c Adapter.
|
Type alias for the task type associated with the custom task's \c Adapter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias CustomTask::Deleter
|
\typealias Tasking::CustomTask::Deleter
|
||||||
|
|
||||||
Type alias for the task's type deleter associated with the custom task's \c Adapter.
|
Type alias for the task's type deleter associated with the custom task's \c Adapter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias CustomTask::TaskSetupHandler
|
\typealias Tasking::CustomTask::TaskSetupHandler
|
||||||
|
|
||||||
Type alias for \c std::function<SetupResult(Task &)>.
|
Type alias for \c std::function<SetupResult(Task &)>.
|
||||||
|
|
||||||
@ -676,9 +676,9 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias CustomTask::TaskDoneHandler
|
\typealias Tasking::CustomTask::TaskDoneHandler
|
||||||
|
|
||||||
Type alias for \c std::function<DoneResult(const Task &, DoneWith)>.
|
Type alias for \c std::function<DoneResult(const Task &, DoneWith)> or DoneResult.
|
||||||
|
|
||||||
The \c TaskDoneHandler is an optional argument of a custom task element's constructor.
|
The \c TaskDoneHandler is an optional argument of a custom task element's constructor.
|
||||||
Any function with the above signature, when passed as a task done handler,
|
Any function with the above signature, when passed as a task done handler,
|
||||||
@ -703,6 +703,9 @@ private:
|
|||||||
the DoneWith argument. When the handler returns the DoneResult value,
|
the DoneWith argument. When the handler returns the DoneResult value,
|
||||||
the task's final result may be tweaked inside the done handler's body by the returned value.
|
the task's final result may be tweaked inside the done handler's body by the returned value.
|
||||||
|
|
||||||
|
For a \c TaskDoneHandler of the DoneResult type, no additional handling is executed,
|
||||||
|
and the task finishes unconditionally with the passed value of DoneResult.
|
||||||
|
|
||||||
\sa CustomTask(), TaskSetupHandler, GroupDoneHandler
|
\sa CustomTask(), TaskSetupHandler, GroupDoneHandler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -862,7 +865,83 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable sequential
|
\variable Tasking::nullItem
|
||||||
|
|
||||||
|
A convenient global group's element indicating a no-op item.
|
||||||
|
|
||||||
|
This is useful in conditional expressions to indicate the absence of an optional element:
|
||||||
|
|
||||||
|
\code
|
||||||
|
const ExecutableItem task = ...;
|
||||||
|
const std::optional<ExecutableItem> optionalTask = ...;
|
||||||
|
|
||||||
|
Group group {
|
||||||
|
task,
|
||||||
|
optionalTask ? *optionalTask : nullItem
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\variable Tasking::successItem
|
||||||
|
|
||||||
|
A convenient global executable element containing an empty, successful, synchronous task.
|
||||||
|
|
||||||
|
This is useful in if-statements to indicate that a branch ends with success:
|
||||||
|
|
||||||
|
\code
|
||||||
|
const ExecutableItem conditionalTask = ...;
|
||||||
|
|
||||||
|
Group group {
|
||||||
|
stopOnDone,
|
||||||
|
If (conditionalTask) >> Then {
|
||||||
|
...
|
||||||
|
} >> Else {
|
||||||
|
successItem
|
||||||
|
},
|
||||||
|
nextTask
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
In the above example, if the \c conditionalTask finishes with an error, the \c Else branch
|
||||||
|
is chosen, which finishes immediately with success. This causes the \c nextTask to be skipped
|
||||||
|
(because of the stopOnDone workflow policy of the \c group)
|
||||||
|
and the \c group finishes with success.
|
||||||
|
|
||||||
|
\sa errorItem
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\variable Tasking::errorItem
|
||||||
|
|
||||||
|
A convenient global executable element containing an empty, erroneous, synchronous task.
|
||||||
|
|
||||||
|
This is useful in if-statements to indicate that a branch ends with an error:
|
||||||
|
|
||||||
|
\code
|
||||||
|
const ExecutableItem conditionalTask = ...;
|
||||||
|
|
||||||
|
Group group {
|
||||||
|
stopOnError,
|
||||||
|
If (conditionalTask) >> Then {
|
||||||
|
...
|
||||||
|
} >> Else {
|
||||||
|
errorItem
|
||||||
|
},
|
||||||
|
nextTask
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
In the above example, if the \c conditionalTask finishes with an error, the \c Else branch
|
||||||
|
is chosen, which finishes immediately with an error. This causes the \c nextTask to be skipped
|
||||||
|
(because of the stopOnError workflow policy of the \c group)
|
||||||
|
and the \c group finishes with an error.
|
||||||
|
|
||||||
|
\sa successItem
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\variable Tasking::sequential
|
||||||
A convenient global group's element describing the sequential execution mode.
|
A convenient global group's element describing the sequential execution mode.
|
||||||
|
|
||||||
This is the default execution mode of the Group element.
|
This is the default execution mode of the Group element.
|
||||||
@ -877,7 +956,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable parallel
|
\variable Tasking::parallel
|
||||||
A convenient global group's element describing the parallel execution mode.
|
A convenient global group's element describing the parallel execution mode.
|
||||||
|
|
||||||
All the direct child tasks of a group are started after the group is started,
|
All the direct child tasks of a group are started after the group is started,
|
||||||
@ -888,7 +967,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable parallelIdealThreadCountLimit
|
\variable Tasking::parallelIdealThreadCountLimit
|
||||||
A convenient global group's element describing the parallel execution mode with a limited
|
A convenient global group's element describing the parallel execution mode with a limited
|
||||||
number of tasks running simultanously. The limit is equal to the ideal number of threads
|
number of tasks running simultanously. The limit is equal to the ideal number of threads
|
||||||
excluding the calling thread.
|
excluding the calling thread.
|
||||||
@ -902,39 +981,39 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable stopOnError
|
\variable Tasking::stopOnError
|
||||||
A convenient global group's element describing the StopOnError workflow policy.
|
A convenient global group's element describing the StopOnError workflow policy.
|
||||||
|
|
||||||
This is the default workflow policy of the Group element.
|
This is the default workflow policy of the Group element.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable continueOnError
|
\variable Tasking::continueOnError
|
||||||
A convenient global group's element describing the ContinueOnError workflow policy.
|
A convenient global group's element describing the ContinueOnError workflow policy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable stopOnSuccess
|
\variable Tasking::stopOnSuccess
|
||||||
A convenient global group's element describing the StopOnSuccess workflow policy.
|
A convenient global group's element describing the StopOnSuccess workflow policy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable continueOnSuccess
|
\variable Tasking::continueOnSuccess
|
||||||
A convenient global group's element describing the ContinueOnSuccess workflow policy.
|
A convenient global group's element describing the ContinueOnSuccess workflow policy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable stopOnSuccessOrError
|
\variable Tasking::stopOnSuccessOrError
|
||||||
A convenient global group's element describing the StopOnSuccessOrError workflow policy.
|
A convenient global group's element describing the StopOnSuccessOrError workflow policy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable finishAllAndSuccess
|
\variable Tasking::finishAllAndSuccess
|
||||||
A convenient global group's element describing the FinishAllAndSuccess workflow policy.
|
A convenient global group's element describing the FinishAllAndSuccess workflow policy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\variable finishAllAndError
|
\variable Tasking::finishAllAndError
|
||||||
A convenient global group's element describing the FinishAllAndError workflow policy.
|
A convenient global group's element describing the FinishAllAndError workflow policy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -1025,7 +1104,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias GroupItem::GroupSetupHandler
|
\typealias Tasking::GroupItem::GroupSetupHandler
|
||||||
|
|
||||||
Type alias for \c std::function<SetupResult()>.
|
Type alias for \c std::function<SetupResult()>.
|
||||||
|
|
||||||
@ -1055,9 +1134,9 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias GroupItem::GroupDoneHandler
|
\typealias Tasking::GroupItem::GroupDoneHandler
|
||||||
|
|
||||||
Type alias for \c std::function<DoneResult(DoneWith)>.
|
Type alias for \c std::function<DoneResult(DoneWith)> or DoneResult.
|
||||||
|
|
||||||
The \c GroupDoneHandler is an argument of the onGroupDone() element.
|
The \c GroupDoneHandler is an argument of the onGroupDone() element.
|
||||||
Any function with the above signature, when passed as a group done handler,
|
Any function with the above signature, when passed as a group done handler,
|
||||||
@ -1072,6 +1151,10 @@ private:
|
|||||||
the DoneWith argument. When the handler returns the DoneResult value,
|
the DoneWith argument. When the handler returns the DoneResult value,
|
||||||
the group's final result may be tweaked inside the done handler's body by the returned value.
|
the group's final result may be tweaked inside the done handler's body by the returned value.
|
||||||
|
|
||||||
|
For a \c GroupDoneHandler of the DoneResult type, no additional handling is executed,
|
||||||
|
and the group finishes unconditionally with the passed value of DoneResult,
|
||||||
|
ignoring the group's workflow policy.
|
||||||
|
|
||||||
\sa onGroupDone(), GroupSetupHandler, CustomTask::TaskDoneHandler
|
\sa onGroupDone(), GroupSetupHandler, CustomTask::TaskDoneHandler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -1159,9 +1242,9 @@ private:
|
|||||||
|
|
||||||
\sa sequential, parallel
|
\sa sequential, parallel
|
||||||
*/
|
*/
|
||||||
GroupItem parallelLimit(int limit)
|
GroupItem ParallelLimitFunctor::operator()(int limit) const
|
||||||
{
|
{
|
||||||
return Group::parallelLimit(qMax(limit, 0));
|
return GroupItem({{}, limit});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1172,12 +1255,13 @@ GroupItem parallelLimit(int limit)
|
|||||||
\sa stopOnError, continueOnError, stopOnSuccess, continueOnSuccess, stopOnSuccessOrError,
|
\sa stopOnError, continueOnError, stopOnSuccess, continueOnSuccess, stopOnSuccessOrError,
|
||||||
finishAllAndSuccess, finishAllAndError, WorkflowPolicy
|
finishAllAndSuccess, finishAllAndError, WorkflowPolicy
|
||||||
*/
|
*/
|
||||||
GroupItem workflowPolicy(WorkflowPolicy policy)
|
GroupItem WorkflowPolicyFunctor::operator()(WorkflowPolicy policy) const
|
||||||
{
|
{
|
||||||
return Group::workflowPolicy(policy);
|
return GroupItem({{}, {}, policy});
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupItem nullItem = GroupItem({});
|
const ParallelLimitFunctor parallelLimit = ParallelLimitFunctor();
|
||||||
|
const WorkflowPolicyFunctor workflowPolicy = WorkflowPolicyFunctor();
|
||||||
|
|
||||||
const GroupItem sequential = parallelLimit(1);
|
const GroupItem sequential = parallelLimit(1);
|
||||||
const GroupItem parallel = parallelLimit(0);
|
const GroupItem parallel = parallelLimit(0);
|
||||||
@ -1191,6 +1275,11 @@ const GroupItem stopOnSuccessOrError = workflowPolicy(WorkflowPolicy::StopOnSucc
|
|||||||
const GroupItem finishAllAndSuccess = workflowPolicy(WorkflowPolicy::FinishAllAndSuccess);
|
const GroupItem finishAllAndSuccess = workflowPolicy(WorkflowPolicy::FinishAllAndSuccess);
|
||||||
const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError);
|
const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError);
|
||||||
|
|
||||||
|
// Keep below the above in order to avoid static initialization fiasco.
|
||||||
|
const GroupItem nullItem = GroupItem({});
|
||||||
|
const ExecutableItem successItem = Group { finishAllAndSuccess };
|
||||||
|
const ExecutableItem errorItem = Group { finishAllAndError };
|
||||||
|
|
||||||
// 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.
|
||||||
@ -1292,7 +1381,7 @@ const void *Loop::valuePtr() const
|
|||||||
|
|
||||||
using StoragePtr = void *;
|
using StoragePtr = void *;
|
||||||
|
|
||||||
constexpr QLatin1StringView s_activeStorageWarning =
|
static constexpr QLatin1StringView s_activeStorageWarning =
|
||||||
"The referenced storage is not reachable in the running tree. "
|
"The referenced storage is not reachable in the running tree. "
|
||||||
"A nullptr will be returned which might lead to a crash in the calling code. "
|
"A nullptr will be returned which might lead to a crash in the calling code. "
|
||||||
"It is possible that no storage was added to the tree, "
|
"It is possible that no storage was added to the tree, "
|
||||||
@ -1503,6 +1592,128 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn ExecutableItem ExecutableItem::operator!(const ExecutableItem &item)
|
||||||
|
|
||||||
|
Returns an ExecutableItem with the DoneResult of \a item negated.
|
||||||
|
|
||||||
|
If \a item reports DoneResult::Success, the returned item reports DoneResult::Error.
|
||||||
|
If \a item reports DoneResult::Error, the returned item reports DoneResult::Success.
|
||||||
|
|
||||||
|
The returned item is equivalent to:
|
||||||
|
\code
|
||||||
|
Group {
|
||||||
|
item,
|
||||||
|
onGroupDone([](DoneWith doneWith) { return toDoneResult(doneWith == DoneWith::Error); })
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\sa operator&&(), operator||()
|
||||||
|
*/
|
||||||
|
ExecutableItem operator!(const ExecutableItem &item)
|
||||||
|
{
|
||||||
|
return Group {
|
||||||
|
item,
|
||||||
|
onGroupDone([](DoneWith doneWith) { return toDoneResult(doneWith == DoneWith::Error); })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn ExecutableItem ExecutableItem::operator&&(const ExecutableItem &first, const ExecutableItem &second)
|
||||||
|
|
||||||
|
Returns an ExecutableItem with \a first and \a second tasks merged with conjunction.
|
||||||
|
|
||||||
|
Both \a first and \a second tasks execute in sequence.
|
||||||
|
If both tasks report DoneResult::Success, the returned item reports DoneResult::Success.
|
||||||
|
Otherwise, the returned item reports DoneResult::Error.
|
||||||
|
|
||||||
|
The returned item is
|
||||||
|
\l {https://en.wikipedia.org/wiki/Short-circuit_evaluation}{short-circuiting}:
|
||||||
|
if the \a first task reports DoneResult::Error, the \a second task is skipped,
|
||||||
|
and the returned item reports DoneResult::Error immediately.
|
||||||
|
|
||||||
|
The returned item is equivalent to:
|
||||||
|
\code
|
||||||
|
Group { stopOnError, first, second }
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\note Parallel execution of conjunction in a short-circuit manner can be achieved with the
|
||||||
|
following code: \c {Group { parallel, stopOnError, first, second }}. In this case:
|
||||||
|
if the \e {first finished} task reports DoneResult::Error,
|
||||||
|
the \e other task is canceled, and the group reports DoneResult::Error immediately.
|
||||||
|
|
||||||
|
\sa operator||(), operator!()
|
||||||
|
*/
|
||||||
|
ExecutableItem operator&&(const ExecutableItem &first, const ExecutableItem &second)
|
||||||
|
{
|
||||||
|
return Group { stopOnError, first, second };
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn ExecutableItem ExecutableItem::operator||(const ExecutableItem &first, const ExecutableItem &second)
|
||||||
|
|
||||||
|
Returns an ExecutableItem with \a first and \a second tasks merged with disjunction.
|
||||||
|
|
||||||
|
Both \a first and \a second tasks execute in sequence.
|
||||||
|
If both tasks report DoneResult::Error, the returned item reports DoneResult::Error.
|
||||||
|
Otherwise, the returned item reports DoneResult::Success.
|
||||||
|
|
||||||
|
The returned item is
|
||||||
|
\l {https://en.wikipedia.org/wiki/Short-circuit_evaluation}{short-circuiting}:
|
||||||
|
if the \a first task reports DoneResult::Success, the \a second task is skipped,
|
||||||
|
and the returned item reports DoneResult::Success immediately.
|
||||||
|
|
||||||
|
The returned item is equivalent to:
|
||||||
|
\code
|
||||||
|
Group { stopOnSuccess, first, second }
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\note Parallel execution of disjunction in a short-circuit manner can be achieved with the
|
||||||
|
following code: \c {Group { parallel, stopOnSuccess, first, second }}. In this case:
|
||||||
|
if the \e {first finished} task reports DoneResult::Success,
|
||||||
|
the \e other task is canceled, and the group reports DoneResult::Success immediately.
|
||||||
|
|
||||||
|
\sa operator&&(), operator!()
|
||||||
|
*/
|
||||||
|
ExecutableItem operator||(const ExecutableItem &first, const ExecutableItem &second)
|
||||||
|
{
|
||||||
|
return Group { stopOnSuccess, first, second };
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn ExecutableItem ExecutableItem::operator&&(const ExecutableItem &item, DoneResult result)
|
||||||
|
\overload ExecutableItem::operator&&()
|
||||||
|
|
||||||
|
Returns the \a item task if the \a result is DoneResult::Success; otherwise returns
|
||||||
|
the \a item task with its done result tweaked to DoneResult::Error.
|
||||||
|
|
||||||
|
The \c {task && DoneResult::Error} is an eqivalent to tweaking the task's done result
|
||||||
|
into DoneResult::Error unconditionally.
|
||||||
|
*/
|
||||||
|
ExecutableItem operator&&(const ExecutableItem &item, DoneResult result)
|
||||||
|
{
|
||||||
|
if (result == DoneResult::Success)
|
||||||
|
return item;
|
||||||
|
return Group { finishAllAndError, item };
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn ExecutableItem ExecutableItem::operator||(const ExecutableItem &item, DoneResult result)
|
||||||
|
\overload ExecutableItem::operator||()
|
||||||
|
|
||||||
|
Returns the \a item task if the \a result is DoneResult::Error; otherwise returns
|
||||||
|
the \a item task with its done result tweaked to DoneResult::Success.
|
||||||
|
|
||||||
|
The \c {task || DoneResult::Success} is an eqivalent to tweaking the task's done result
|
||||||
|
into DoneResult::Success unconditionally.
|
||||||
|
*/
|
||||||
|
ExecutableItem operator||(const ExecutableItem &item, DoneResult result)
|
||||||
|
{
|
||||||
|
if (result == DoneResult::Error)
|
||||||
|
return item;
|
||||||
|
return Group { finishAllAndSuccess, item };
|
||||||
|
}
|
||||||
|
|
||||||
ExecutableItem ExecutableItem::withCancelImpl(
|
ExecutableItem ExecutableItem::withCancelImpl(
|
||||||
const std::function<void(QObject *, const std::function<void()> &)> &connectWrapper) const
|
const std::function<void(QObject *, const std::function<void()> &)> &connectWrapper) const
|
||||||
{
|
{
|
||||||
@ -1974,13 +2185,6 @@ SetupResult TaskTreePrivate::start(RuntimeContainer *container)
|
|||||||
container->m_successBit = startAction == SetupResult::StopWithSuccess;
|
container->m_successBit = startAction == SetupResult::StopWithSuccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startAction == SetupResult::Continue
|
|
||||||
&& (containerNode.m_children.empty()
|
|
||||||
|| (containerNode.m_loop && !invokeLoopHandler(container)))) {
|
|
||||||
if (isProgressive(container))
|
|
||||||
advanceProgress(containerNode.m_taskCount);
|
|
||||||
startAction = toSetupResult(container->m_successBit);
|
|
||||||
}
|
|
||||||
return continueStart(container, startAction);
|
return continueStart(container, startAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1988,23 +2192,24 @@ SetupResult TaskTreePrivate::continueStart(RuntimeContainer *container, SetupRes
|
|||||||
{
|
{
|
||||||
const SetupResult groupAction = startAction == SetupResult::Continue ? startChildren(container)
|
const SetupResult groupAction = startAction == SetupResult::Continue ? startChildren(container)
|
||||||
: startAction;
|
: startAction;
|
||||||
if (groupAction != SetupResult::Continue) {
|
if (groupAction == SetupResult::Continue)
|
||||||
const bool bit = container->updateSuccessBit(groupAction == SetupResult::StopWithSuccess);
|
return groupAction;
|
||||||
RuntimeIteration *parentIteration = container->parentIteration();
|
|
||||||
RuntimeTask *parentTask = container->m_parentTask;
|
const bool bit = container->updateSuccessBit(groupAction == SetupResult::StopWithSuccess);
|
||||||
QT_CHECK(parentTask);
|
RuntimeIteration *parentIteration = container->parentIteration();
|
||||||
const bool result = invokeDoneHandler(container, bit ? DoneWith::Success : DoneWith::Error);
|
RuntimeTask *parentTask = container->m_parentTask;
|
||||||
if (parentIteration) {
|
QT_CHECK(parentTask);
|
||||||
parentIteration->deleteChild(parentTask);
|
const bool result = invokeDoneHandler(container, bit ? DoneWith::Success : DoneWith::Error);
|
||||||
if (!parentIteration->m_container->isStarting())
|
if (parentIteration) {
|
||||||
childDone(parentIteration, result);
|
parentIteration->deleteChild(parentTask);
|
||||||
} else {
|
if (!parentIteration->m_container->isStarting())
|
||||||
QT_CHECK(m_runtimeRoot.get() == parentTask);
|
childDone(parentIteration, result);
|
||||||
m_runtimeRoot.reset();
|
} else {
|
||||||
emitDone(result ? DoneWith::Success : DoneWith::Error);
|
QT_CHECK(m_runtimeRoot.get() == parentTask);
|
||||||
}
|
m_runtimeRoot.reset();
|
||||||
|
emitDone(result ? DoneWith::Success : DoneWith::Error);
|
||||||
}
|
}
|
||||||
return groupAction;
|
return toSetupResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container)
|
SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container)
|
||||||
@ -2013,14 +2218,14 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container)
|
|||||||
const int childCount = int(containerNode.m_children.size());
|
const int childCount = int(containerNode.m_children.size());
|
||||||
|
|
||||||
if (container->m_iterationCount == 0) {
|
if (container->m_iterationCount == 0) {
|
||||||
|
if (container->m_shouldIterate && !invokeLoopHandler(container)) {
|
||||||
|
if (isProgressive(container))
|
||||||
|
advanceProgress(containerNode.m_taskCount);
|
||||||
|
return toSetupResult(container->m_successBit);
|
||||||
|
}
|
||||||
container->m_iterations.emplace_back(
|
container->m_iterations.emplace_back(
|
||||||
std::make_unique<RuntimeIteration>(container->m_iterationCount, container));
|
std::make_unique<RuntimeIteration>(container->m_iterationCount, container));
|
||||||
++container->m_iterationCount;
|
++container->m_iterationCount;
|
||||||
} else if (containerNode.m_parallelLimit == 0) {
|
|
||||||
container->deleteFinishedIterations();
|
|
||||||
if (container->m_iterations.empty())
|
|
||||||
return toSetupResult(container->m_successBit);
|
|
||||||
return SetupResult::Continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GuardLocker locker(container->m_startGuard);
|
GuardLocker locker(container->m_startGuard);
|
||||||
@ -2029,17 +2234,20 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container)
|
|||||||
|| container->m_runningChildren < containerNode.m_parallelLimit) {
|
|| container->m_runningChildren < containerNode.m_parallelLimit) {
|
||||||
container->deleteFinishedIterations();
|
container->deleteFinishedIterations();
|
||||||
if (container->m_nextToStart == childCount) {
|
if (container->m_nextToStart == childCount) {
|
||||||
if (container->m_shouldIterate && invokeLoopHandler(container)) {
|
if (invokeLoopHandler(container)) {
|
||||||
container->m_nextToStart = 0;
|
container->m_nextToStart = 0;
|
||||||
container->m_iterations.emplace_back(
|
container->m_iterations.emplace_back(
|
||||||
std::make_unique<RuntimeIteration>(container->m_iterationCount, container));
|
std::make_unique<RuntimeIteration>(container->m_iterationCount, container));
|
||||||
++container->m_iterationCount;
|
++container->m_iterationCount;
|
||||||
|
} else if (container->m_iterations.empty()) {
|
||||||
|
return toSetupResult(container->m_successBit);
|
||||||
} else {
|
} else {
|
||||||
if (container->m_iterations.empty())
|
|
||||||
return toSetupResult(container->m_successBit);
|
|
||||||
return SetupResult::Continue;
|
return SetupResult::Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (containerNode.m_children.size() == 0) // Empty loop body.
|
||||||
|
continue;
|
||||||
|
|
||||||
RuntimeIteration *iteration = container->m_iterations.back().get();
|
RuntimeIteration *iteration = container->m_iterations.back().get();
|
||||||
RuntimeTask *newTask = new RuntimeTask{containerNode.m_children.at(container->m_nextToStart),
|
RuntimeTask *newTask = new RuntimeTask{containerNode.m_children.at(container->m_nextToStart),
|
||||||
iteration};
|
iteration};
|
||||||
@ -2436,7 +2644,7 @@ bool TaskTreePrivate::invokeDoneHandler(RuntimeTask *node, DoneWith doneWith)
|
|||||||
\section2 Task's Done Handler
|
\section2 Task's Done Handler
|
||||||
|
|
||||||
When a running task finishes, the task tree invokes an optionally provided done handler.
|
When a running task finishes, the task tree invokes an optionally provided done handler.
|
||||||
The handler should always take a \c const \e reference to the associated task class object:
|
The handler should take a \c const \e reference to the associated task class object:
|
||||||
|
|
||||||
\code
|
\code
|
||||||
const auto onSetup = [](QProcess &process) {
|
const auto onSetup = [](QProcess &process) {
|
||||||
@ -3399,13 +3607,13 @@ void TimeoutTaskAdapter::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias TaskTreeTask
|
\typealias Tasking::TaskTreeTask
|
||||||
|
|
||||||
Type alias for the CustomTask, to be used inside recipes, associated with the TaskTree task.
|
Type alias for the CustomTask, to be used inside recipes, associated with the TaskTree task.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias TimeoutTask
|
\typealias Tasking::TimeoutTask
|
||||||
|
|
||||||
Type alias for the CustomTask, to be used inside recipes, associated with the
|
Type alias for the CustomTask, to be used inside recipes, associated with the
|
||||||
\c std::chrono::milliseconds type. \c std::chrono::milliseconds is used to set up the
|
\c std::chrono::milliseconds type. \c std::chrono::milliseconds is used to set up the
|
||||||
|
@ -218,13 +218,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
|
||||||
@ -271,8 +270,6 @@ protected:
|
|||||||
void addChildren(const QList<GroupItem> &children);
|
void addChildren(const QList<GroupItem> &children);
|
||||||
|
|
||||||
static GroupItem groupHandler(const GroupHandler &handler) { return GroupItem({handler}); }
|
static GroupItem groupHandler(const GroupHandler &handler) { return GroupItem({handler}); }
|
||||||
static GroupItem parallelLimit(int limit) { return GroupItem({{}, limit}); }
|
|
||||||
static GroupItem workflowPolicy(WorkflowPolicy policy) { return GroupItem({{}, {}, policy}); }
|
|
||||||
|
|
||||||
// Checks if Function may be invoked with Args and if Function's return type is Result.
|
// Checks if Function may be invoked with Args and if Function's return type is Result.
|
||||||
template <typename Result, typename Function, typename ...Args,
|
template <typename Result, typename Function, typename ...Args,
|
||||||
@ -287,8 +284,11 @@ 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 WorkflowPolicyFunctor;
|
||||||
Type m_type = Type::Group;
|
Type m_type = Type::Group;
|
||||||
QList<GroupItem> m_children;
|
QList<GroupItem> m_children;
|
||||||
GroupData m_groupData;
|
GroupData m_groupData;
|
||||||
@ -319,6 +319,14 @@ protected:
|
|||||||
ExecutableItem(const TaskHandler &handler) : GroupItem(handler) {}
|
ExecutableItem(const TaskHandler &handler) : GroupItem(handler) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
TASKING_EXPORT friend ExecutableItem operator!(const ExecutableItem &item);
|
||||||
|
TASKING_EXPORT friend ExecutableItem operator&&(const ExecutableItem &first,
|
||||||
|
const ExecutableItem &second);
|
||||||
|
TASKING_EXPORT friend ExecutableItem operator||(const ExecutableItem &first,
|
||||||
|
const ExecutableItem &second);
|
||||||
|
TASKING_EXPORT friend ExecutableItem operator&&(const ExecutableItem &item, DoneResult result);
|
||||||
|
TASKING_EXPORT friend ExecutableItem operator||(const ExecutableItem &item, DoneResult result);
|
||||||
|
|
||||||
ExecutableItem withCancelImpl(
|
ExecutableItem withCancelImpl(
|
||||||
const std::function<void(QObject *, const std::function<void()> &)> &connectWrapper) const;
|
const std::function<void(QObject *, const std::function<void()> &)> &connectWrapper) const;
|
||||||
};
|
};
|
||||||
@ -338,8 +346,6 @@ public:
|
|||||||
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf = CallDoneIf::SuccessOrError) {
|
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf = CallDoneIf::SuccessOrError) {
|
||||||
return groupHandler({{}, wrapGroupDone(std::forward<Handler>(handler)), callDoneIf});
|
return groupHandler({{}, wrapGroupDone(std::forward<Handler>(handler)), callDoneIf});
|
||||||
}
|
}
|
||||||
using GroupItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
|
|
||||||
using GroupItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
@ -361,24 +367,34 @@ private:
|
|||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
static GroupDoneHandler wrapGroupDone(Handler &&handler)
|
static GroupDoneHandler wrapGroupDone(Handler &&handler)
|
||||||
{
|
{
|
||||||
// R, V, D stands for: Done[R]esult, [V]oid, [D]oneWith
|
static constexpr bool isDoneResultType = std::is_same_v<Handler, DoneResult>;
|
||||||
|
// R, B, V, D stands for: Done[R]esult, [B]ool, [V]oid, [D]oneWith
|
||||||
static constexpr bool isRD = isInvocable<DoneResult, Handler, DoneWith>();
|
static constexpr bool isRD = isInvocable<DoneResult, Handler, DoneWith>();
|
||||||
static constexpr bool isR = isInvocable<DoneResult, Handler>();
|
static constexpr bool isR = isInvocable<DoneResult, Handler>();
|
||||||
|
static constexpr bool isBD = isInvocable<bool, Handler, DoneWith>();
|
||||||
|
static constexpr bool isB = isInvocable<bool, Handler>();
|
||||||
static constexpr bool isVD = isInvocable<void, Handler, DoneWith>();
|
static constexpr bool isVD = isInvocable<void, Handler, DoneWith>();
|
||||||
static constexpr bool isV = isInvocable<void, Handler>();
|
static constexpr bool isV = isInvocable<void, Handler>();
|
||||||
static_assert(isRD || isR || isVD || isV,
|
static_assert(isDoneResultType || isRD || isR || isBD || isB || isVD || isV,
|
||||||
"Group done handler needs to take (DoneWith) or (void) as an argument and has to "
|
"Group done handler needs to take (DoneWith) or (void) as an argument and has to "
|
||||||
"return void or DoneResult. The passed handler doesn't fulfill these requirements.");
|
"return void, bool or DoneResult. Alternatively, it may be of DoneResult type. "
|
||||||
|
"The passed handler doesn't fulfill these requirements.");
|
||||||
return [handler](DoneWith result) {
|
return [handler](DoneWith result) {
|
||||||
|
if constexpr (isDoneResultType)
|
||||||
|
return handler;
|
||||||
if constexpr (isRD)
|
if constexpr (isRD)
|
||||||
return std::invoke(handler, result);
|
return std::invoke(handler, result);
|
||||||
if constexpr (isR)
|
if constexpr (isR)
|
||||||
return std::invoke(handler);
|
return std::invoke(handler);
|
||||||
|
if constexpr (isBD)
|
||||||
|
return toDoneResult(std::invoke(handler, result));
|
||||||
|
if constexpr (isB)
|
||||||
|
return toDoneResult(std::invoke(handler));
|
||||||
if constexpr (isVD)
|
if constexpr (isVD)
|
||||||
std::invoke(handler, result);
|
std::invoke(handler, result);
|
||||||
else if constexpr (isV)
|
else if constexpr (isV)
|
||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
|
return toDoneResult(result == DoneWith::Success);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -395,10 +411,22 @@ static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf = CallDone
|
|||||||
return Group::onGroupDone(std::forward<Handler>(handler), callDoneIf);
|
return Group::onGroupDone(std::forward<Handler>(handler), callDoneIf);
|
||||||
}
|
}
|
||||||
|
|
||||||
TASKING_EXPORT GroupItem parallelLimit(int limit);
|
class TASKING_EXPORT ParallelLimitFunctor
|
||||||
TASKING_EXPORT GroupItem workflowPolicy(WorkflowPolicy policy);
|
{
|
||||||
|
public:
|
||||||
|
// Default: 1 (sequential). 0 means unlimited (parallel).
|
||||||
|
GroupItem operator()(int limit) const;
|
||||||
|
};
|
||||||
|
|
||||||
TASKING_EXPORT extern const GroupItem nullItem;
|
class TASKING_EXPORT WorkflowPolicyFunctor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Default: WorkflowPolicy::StopOnError.
|
||||||
|
GroupItem operator()(WorkflowPolicy policy) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
TASKING_EXPORT extern const ParallelLimitFunctor parallelLimit;
|
||||||
|
TASKING_EXPORT extern const WorkflowPolicyFunctor workflowPolicy;
|
||||||
|
|
||||||
TASKING_EXPORT extern const GroupItem sequential;
|
TASKING_EXPORT extern const GroupItem sequential;
|
||||||
TASKING_EXPORT extern const GroupItem parallel;
|
TASKING_EXPORT extern const GroupItem parallel;
|
||||||
@ -412,11 +440,46 @@ TASKING_EXPORT extern const GroupItem stopOnSuccessOrError;
|
|||||||
TASKING_EXPORT extern const GroupItem finishAllAndSuccess;
|
TASKING_EXPORT extern const GroupItem finishAllAndSuccess;
|
||||||
TASKING_EXPORT extern const GroupItem finishAllAndError;
|
TASKING_EXPORT extern const GroupItem finishAllAndError;
|
||||||
|
|
||||||
class TASKING_EXPORT Forever final : public Group
|
TASKING_EXPORT extern const GroupItem nullItem;
|
||||||
|
TASKING_EXPORT extern const ExecutableItem successItem;
|
||||||
|
TASKING_EXPORT extern const ExecutableItem errorItem;
|
||||||
|
|
||||||
|
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()
|
||||||
@ -425,26 +488,20 @@ class TASKING_EXPORT Sync final : public ExecutableItem
|
|||||||
public:
|
public:
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
Sync(Handler &&handler) {
|
Sync(Handler &&handler) {
|
||||||
addChildren({ onGroupSetup(wrapHandler(std::forward<Handler>(handler))) });
|
addChildren({ onGroupDone(wrapHandler(std::forward<Handler>(handler))) });
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
static GroupSetupHandler wrapHandler(Handler &&handler) {
|
static auto wrapHandler(Handler &&handler) {
|
||||||
// R, V stands for: Done[R]esult, [V]oid
|
// R, B, V stands for: Done[R]esult, [B]ool, [V]oid
|
||||||
static constexpr bool isR = isInvocable<DoneResult, Handler>();
|
static constexpr bool isR = isInvocable<DoneResult, Handler>();
|
||||||
|
static constexpr bool isB = isInvocable<bool, Handler>();
|
||||||
static constexpr bool isV = isInvocable<void, Handler>();
|
static constexpr bool isV = isInvocable<void, Handler>();
|
||||||
static_assert(isR || isV,
|
static_assert(isR || isB || isV,
|
||||||
"Sync handler needs to take no arguments and has to return void or DoneResult. "
|
"Sync handler needs to take no arguments and has to return void, bool or DoneResult. "
|
||||||
"The passed handler doesn't fulfill these requirements.");
|
"The passed handler doesn't fulfill these requirements.");
|
||||||
return [handler] {
|
return handler;
|
||||||
if constexpr (isR) {
|
|
||||||
return std::invoke(handler) == DoneResult::Success ? SetupResult::StopWithSuccess
|
|
||||||
: SetupResult::StopWithError;
|
|
||||||
}
|
|
||||||
std::invoke(handler);
|
|
||||||
return SetupResult::StopWithSuccess;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -507,21 +564,31 @@ private:
|
|||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
static InterfaceDoneHandler wrapDone(Handler &&handler) {
|
static InterfaceDoneHandler wrapDone(Handler &&handler) {
|
||||||
if constexpr (std::is_same_v<Handler, TaskDoneHandler>)
|
if constexpr (std::is_same_v<Handler, TaskDoneHandler>)
|
||||||
return {}; // When user passed {} for the done handler.
|
return {}; // User passed {} for the done handler.
|
||||||
// R, V, T, D stands for: Done[R]esult, [V]oid, [T]ask, [D]oneWith
|
static constexpr bool isDoneResultType = std::is_same_v<Handler, DoneResult>;
|
||||||
|
// R, B, V, T, D stands for: Done[R]esult, [B]ool, [V]oid, [T]ask, [D]oneWith
|
||||||
static constexpr bool isRTD = isInvocable<DoneResult, Handler, const Task &, DoneWith>();
|
static constexpr bool isRTD = isInvocable<DoneResult, Handler, const Task &, DoneWith>();
|
||||||
static constexpr bool isRT = isInvocable<DoneResult, Handler, const Task &>();
|
static constexpr bool isRT = isInvocable<DoneResult, Handler, const Task &>();
|
||||||
static constexpr bool isRD = isInvocable<DoneResult, Handler, DoneWith>();
|
static constexpr bool isRD = isInvocable<DoneResult, Handler, DoneWith>();
|
||||||
static constexpr bool isR = isInvocable<DoneResult, Handler>();
|
static constexpr bool isR = isInvocable<DoneResult, Handler>();
|
||||||
|
static constexpr bool isBTD = isInvocable<bool, Handler, const Task &, DoneWith>();
|
||||||
|
static constexpr bool isBT = isInvocable<bool, Handler, const Task &>();
|
||||||
|
static constexpr bool isBD = isInvocable<bool, Handler, DoneWith>();
|
||||||
|
static constexpr bool isB = isInvocable<bool, Handler>();
|
||||||
static constexpr bool isVTD = isInvocable<void, Handler, const Task &, DoneWith>();
|
static constexpr bool isVTD = isInvocable<void, Handler, const Task &, DoneWith>();
|
||||||
static constexpr bool isVT = isInvocable<void, Handler, const Task &>();
|
static constexpr bool isVT = isInvocable<void, Handler, const Task &>();
|
||||||
static constexpr bool isVD = isInvocable<void, Handler, DoneWith>();
|
static constexpr bool isVD = isInvocable<void, Handler, DoneWith>();
|
||||||
static constexpr bool isV = isInvocable<void, Handler>();
|
static constexpr bool isV = isInvocable<void, Handler>();
|
||||||
static_assert(isRTD || isRT || isRD || isR || isVTD || isVT || isVD || isV,
|
static_assert(isDoneResultType || isRTD || isRT || isRD || isR
|
||||||
|
|| isBTD || isBT || isBD || isB
|
||||||
|
|| isVTD || isVT || isVD || isV,
|
||||||
"Task done handler needs to take (const Task &, DoneWith), (const Task &), "
|
"Task done handler needs to take (const Task &, DoneWith), (const Task &), "
|
||||||
"(DoneWith) or (void) as arguments and has to return void or DoneResult. "
|
"(DoneWith) or (void) as arguments and has to return void, bool or DoneResult. "
|
||||||
|
"Alternatively, it may be of DoneResult type. "
|
||||||
"The passed handler doesn't fulfill these requirements.");
|
"The passed handler doesn't fulfill these requirements.");
|
||||||
return [handler](const TaskInterface &taskInterface, DoneWith result) {
|
return [handler](const TaskInterface &taskInterface, DoneWith result) {
|
||||||
|
if constexpr (isDoneResultType)
|
||||||
|
return handler;
|
||||||
const Adapter &adapter = static_cast<const Adapter &>(taskInterface);
|
const Adapter &adapter = static_cast<const Adapter &>(taskInterface);
|
||||||
if constexpr (isRTD)
|
if constexpr (isRTD)
|
||||||
return std::invoke(handler, *adapter.task(), result);
|
return std::invoke(handler, *adapter.task(), result);
|
||||||
@ -531,6 +598,14 @@ private:
|
|||||||
return std::invoke(handler, result);
|
return std::invoke(handler, result);
|
||||||
if constexpr (isR)
|
if constexpr (isR)
|
||||||
return std::invoke(handler);
|
return std::invoke(handler);
|
||||||
|
if constexpr (isBTD)
|
||||||
|
return toDoneResult(std::invoke(handler, *adapter.task(), result));
|
||||||
|
if constexpr (isBT)
|
||||||
|
return toDoneResult(std::invoke(handler, *adapter.task()));
|
||||||
|
if constexpr (isBD)
|
||||||
|
return toDoneResult(std::invoke(handler, result));
|
||||||
|
if constexpr (isB)
|
||||||
|
return toDoneResult(std::invoke(handler));
|
||||||
if constexpr (isVTD)
|
if constexpr (isVTD)
|
||||||
std::invoke(handler, *adapter.task(), result);
|
std::invoke(handler, *adapter.task(), result);
|
||||||
else if constexpr (isVT)
|
else if constexpr (isVT)
|
||||||
@ -539,7 +614,7 @@ private:
|
|||||||
std::invoke(handler, result);
|
std::invoke(handler, result);
|
||||||
else if constexpr (isV)
|
else if constexpr (isV)
|
||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
|
return toDoneResult(result == DoneWith::Success);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
67
src/assets/downloader/tasking/tcpsocket.cpp
Normal file
67
src/assets/downloader/tasking/tcpsocket.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright (C) 2024 Jarek Kobus
|
||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
#include "tcpsocket.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace Tasking {
|
||||||
|
|
||||||
|
void TcpSocket::start()
|
||||||
|
{
|
||||||
|
if (m_socket) {
|
||||||
|
qWarning("The TcpSocket is already running. Ignoring the call to start().");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_address.isNull()) {
|
||||||
|
qWarning("Can't start the TcpSocket with invalid address. "
|
||||||
|
"Stopping with an error.");
|
||||||
|
m_error = QAbstractSocket::HostNotFoundError;
|
||||||
|
emit done(DoneResult::Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_socket.reset(new QTcpSocket);
|
||||||
|
connect(m_socket.get(), &QAbstractSocket::errorOccurred, this,
|
||||||
|
[this](QAbstractSocket::SocketError error) {
|
||||||
|
m_error = error;
|
||||||
|
m_socket->disconnect();
|
||||||
|
emit done(DoneResult::Error);
|
||||||
|
m_socket.release()->deleteLater();
|
||||||
|
});
|
||||||
|
connect(m_socket.get(), &QAbstractSocket::connected, this, [this] {
|
||||||
|
if (!m_writeData.isEmpty())
|
||||||
|
m_socket->write(m_writeData);
|
||||||
|
emit started();
|
||||||
|
});
|
||||||
|
connect(m_socket.get(), &QAbstractSocket::disconnected, this, [this] {
|
||||||
|
m_socket->disconnect();
|
||||||
|
emit done(DoneResult::Success);
|
||||||
|
m_socket.release()->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_socket->connectToHost(m_address, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpSocket::~TcpSocket()
|
||||||
|
{
|
||||||
|
if (m_socket) {
|
||||||
|
m_socket->disconnect();
|
||||||
|
m_socket->abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpSocketTaskAdapter::TcpSocketTaskAdapter()
|
||||||
|
{
|
||||||
|
connect(task(), &TcpSocket::done, this, &TaskInterface::done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpSocketTaskAdapter::start()
|
||||||
|
{
|
||||||
|
task()->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tasking
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
72
src/assets/downloader/tasking/tcpsocket.h
Normal file
72
src/assets/downloader/tasking/tcpsocket.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright (C) 2024 Jarek Kobus
|
||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
|
#ifndef TASKING_TCPSOCKET_H
|
||||||
|
#define TASKING_TCPSOCKET_H
|
||||||
|
|
||||||
|
#include "tasking_global.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists purely as an
|
||||||
|
// implementation detail. This header file may change from version to
|
||||||
|
// version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "tasktree.h"
|
||||||
|
|
||||||
|
#include <QtNetwork/QTcpSocket>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace Tasking {
|
||||||
|
|
||||||
|
// This class introduces the dependency to Qt::Network, otherwise Tasking namespace
|
||||||
|
// is independent on Qt::Network.
|
||||||
|
// Possibly, it could be placed inside Qt::Network library, as a wrapper around QTcpSocket.
|
||||||
|
|
||||||
|
class TASKING_EXPORT TcpSocket final : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
~TcpSocket();
|
||||||
|
void setAddress(const QHostAddress &address) { m_address = address; }
|
||||||
|
void setPort(quint16 port) { m_port = port; }
|
||||||
|
void setWriteData(const QByteArray &data) { m_writeData = data; }
|
||||||
|
QTcpSocket *socket() const { return m_socket.get(); }
|
||||||
|
void start();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void started();
|
||||||
|
void done(DoneResult result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHostAddress m_address;
|
||||||
|
quint16 m_port = 0;
|
||||||
|
QByteArray m_writeData;
|
||||||
|
std::unique_ptr<QTcpSocket> m_socket;
|
||||||
|
QAbstractSocket::SocketError m_error = QAbstractSocket::UnknownSocketError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TASKING_EXPORT TcpSocketTaskAdapter final : public TaskAdapter<TcpSocket>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TcpSocketTaskAdapter();
|
||||||
|
void start() final;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TcpSocketTask = CustomTask<TcpSocketTaskAdapter>;
|
||||||
|
|
||||||
|
} // namespace Tasking
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // TASKING_TCPSOCKET_H
|
Loading…
x
Reference in New Issue
Block a user