TaskTree: Enhance Sync's function

Make it possible to pass a void returning function to the
Sync constructor. In this case it's assumed that function
returns true by default and finishes successfully.

Add some helpful error messages when requirements for the
passed function are not met.

Change-Id: I8be75acd277d06e87db3c87a6eb96173aa9cd890
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Jarek Kobus
2023-04-26 12:33:11 +02:00
parent 1a658eff26
commit df5e3c587a
2 changed files with 109 additions and 23 deletions

View File

@@ -306,11 +306,28 @@ public:
// 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()
class QTCREATOR_UTILS_EXPORT Sync : public Group class QTCREATOR_UTILS_EXPORT Sync : public Group
{ {
public: public:
using SynchronousMethod = std::function<bool()>; template<typename Function>
Sync(const SynchronousMethod &sync) Sync(Function &&function) : Group(init(std::forward<Function>(function))) {}
: Group({OnGroupSetup([sync] { return sync() ? TaskAction::StopWithDone
: TaskAction::StopWithError; })}) {} private:
template<typename Function>
static QList<TaskItem> init(Function &&function) {
constexpr bool isInvocable = std::is_invocable_v<std::decay_t<Function>>;
static_assert(isInvocable,
"Sync element: The synchronous function can't take any arguments.");
constexpr bool isBool = std::is_same_v<bool, std::invoke_result_t<std::decay_t<Function>>>;
constexpr bool isVoid = std::is_same_v<void, std::invoke_result_t<std::decay_t<Function>>>;
static_assert(isBool || isVoid,
"Sync element: The synchronous function has to return void or bool.");
if constexpr (isBool) {
return {OnGroupSetup([function] { return function() ? TaskAction::StopWithDone
: TaskAction::StopWithError; })};
}
return {OnGroupSetup([function] { function(); return TaskAction::StopWithDone; })};
};
}; };
QTCREATOR_UTILS_EXPORT extern ParallelLimit sequential; QTCREATOR_UTILS_EXPORT extern ParallelLimit sequential;

View File

@@ -122,6 +122,32 @@ void tst_TaskTree::validConstructs()
OnGroupDone([] {}), OnGroupDone([] {}),
OnGroupError([] {}) OnGroupError([] {})
}; };
// When turning each of below blocks on, you should see the specific compiler error message.
#if 0
{
// "Sync element: The synchronous function has to return void or bool."
const auto setupSync = [] { return 3; };
const Sync sync(setupSync);
}
#endif
#if 0
{
// "Sync element: The synchronous function can't take any arguments."
const auto setupSync = [](int) { };
const Sync sync(setupSync);
}
#endif
#if 0
{
// "Sync element: The synchronous function can't take any arguments."
const auto setupSync = [](int) { return true; };
const Sync sync(setupSync);
}
#endif
} }
void tst_TaskTree::processTree_data() void tst_TaskTree::processTree_data()
@@ -174,7 +200,10 @@ void tst_TaskTree::processTree_data()
const auto groupError = [storage](int groupId) { const auto groupError = [storage](int groupId) {
return [=] { storage->m_log.append({groupId, Handler::GroupError}); }; return [=] { storage->m_log.append({groupId, Handler::GroupError}); };
}; };
const auto setupSync = [storage](int syncId, bool success) { const auto setupSync = [storage](int syncId) {
return [=] { storage->m_log.append({syncId, Handler::Sync}); };
};
const auto setupSyncWithReturn = [storage](int syncId, bool success) {
return [=] { storage->m_log.append({syncId, Handler::Sync}); return success; }; return [=] { storage->m_log.append({syncId, Handler::Sync}); return success; };
}; };
@@ -997,11 +1026,11 @@ void tst_TaskTree::processTree_data()
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
Sync(setupSync(1, true)), Sync(setupSync(1)),
Sync(setupSync(2, true)), Sync(setupSync(2)),
Sync(setupSync(3, true)), Sync(setupSync(3)),
Sync(setupSync(4, true)), Sync(setupSync(4)),
Sync(setupSync(5, true)) Sync(setupSync(5))
}; };
const Log log { const Log log {
{1, Handler::Sync}, {1, Handler::Sync},
@@ -1014,15 +1043,35 @@ void tst_TaskTree::processTree_data()
<< TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success}; << TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success};
} }
{
const Group root {
Storage(storage),
Sync(setupSyncWithReturn(1, true)),
Sync(setupSyncWithReturn(2, true)),
Sync(setupSyncWithReturn(3, true)),
Sync(setupSyncWithReturn(4, true)),
Sync(setupSyncWithReturn(5, true))
};
const Log log {
{1, Handler::Sync},
{2, Handler::Sync},
{3, Handler::Sync},
{4, Handler::Sync},
{5, Handler::Sync}
};
QTest::newRow("SyncWithReturn")
<< TestData{storage, root, log, 0, OnStart::NotRunning, OnDone::Success};
}
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
parallel, parallel,
Sync(setupSync(1, true)), Sync(setupSync(1)),
Sync(setupSync(2, true)), Sync(setupSync(2)),
Sync(setupSync(3, true)), Sync(setupSync(3)),
Sync(setupSync(4, true)), Sync(setupSync(4)),
Sync(setupSync(5, true)) Sync(setupSync(5))
}; };
const Log log { const Log log {
{1, Handler::Sync}, {1, Handler::Sync},
@@ -1039,11 +1088,11 @@ void tst_TaskTree::processTree_data()
const Group root { const Group root {
Storage(storage), Storage(storage),
parallel, parallel,
Sync(setupSync(1, true)), Sync(setupSync(1)),
Sync(setupSync(2, true)), Sync(setupSync(2)),
Sync(setupSync(3, false)), Sync(setupSyncWithReturn(3, false)),
Sync(setupSync(4, true)), Sync(setupSync(4)),
Sync(setupSync(5, true)) Sync(setupSync(5))
}; };
const Log log { const Log log {
{1, Handler::Sync}, {1, Handler::Sync},
@@ -1057,11 +1106,11 @@ void tst_TaskTree::processTree_data()
{ {
const Group root { const Group root {
Storage(storage), Storage(storage),
Sync(setupSync(1, true)), Sync(setupSync(1)),
Process(setupProcess(2)), Process(setupProcess(2)),
Sync(setupSync(3, true)), Sync(setupSync(3)),
Process(setupProcess(4)), Process(setupProcess(4)),
Sync(setupSync(5, true)), Sync(setupSync(5)),
OnGroupDone(groupDone(0)) OnGroupDone(groupDone(0))
}; };
const Log log { const Log log {
@@ -1076,6 +1125,26 @@ void tst_TaskTree::processTree_data()
<< TestData{storage, root, log, 2, OnStart::Running, OnDone::Success}; << TestData{storage, root, log, 2, OnStart::Running, OnDone::Success};
} }
{
const Group root {
Storage(storage),
Sync(setupSync(1)),
Process(setupProcess(2)),
Sync(setupSyncWithReturn(3, false)),
Process(setupProcess(4)),
Sync(setupSync(5)),
OnGroupError(groupError(0))
};
const Log log {
{1, Handler::Sync},
{2, Handler::Setup},
{3, Handler::Sync},
{0, Handler::GroupError}
};
QTest::newRow("SyncAndAsyncError")
<< TestData{storage, root, log, 2, OnStart::Running, OnDone::Failure};
}
{ {
Condition condition; Condition condition;