5#ifndef TASKING_TASKTREE_H
6#define TASKING_TASKTREE_H
21#include <QtCore/QList>
22#include <QtCore/QObject>
103 template <
typename Task,
typename Deleter>
friend class TaskAdapter;
118 int iteration()
const;
125 const void *valuePtr()
const;
130 std::shared_ptr<LoopData> m_loopData;
163 using StorageConstructor = std::function<
void *(
void)>;
164 using StorageDestructor = std::function<
void(
void *)>;
165 using StorageHandler = std::function<
void(
void *)>;
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; }
180 std::shared_ptr<StorageData> m_storageData;
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>
224 GroupItem(
const QList<GroupItem> &children) : m_type(
Type::List) { addChildren(children); }
225 GroupItem(std::initializer_list<GroupItem> children) : m_type(
Type::List) { addChildren(children); }
250 std::optional<int> m_parallelLimit = {};
251 std::optional<WorkflowPolicy> m_workflowPolicy = {};
252 std::optional<Loop> m_loop = {};
267 , m_groupData(
data) {}
270 , m_taskHandler(handler) {}
271 void addChildren(
const QList<GroupItem> &children);
278 template <
typename Result,
typename Function,
typename ...Args,
279 typename DecayedFunction = std::decay_t<Function>>
283 if constexpr (std::is_invocable_r_v<Result, DecayedFunction, Args...>)
284 return std::is_same_v<Result, std::invoke_result_t<DecayedFunction, Args...>>;
292 Type m_type = Type::Group;
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] {
314 return withCancelImpl(connectWrapper);
323 const std::function<
void(
QObject *,
const std::function<
void()> &)> &connectWrapper)
const;
329 Group(
const QList<GroupItem> &children) { addChildren(children); }
330 Group(std::initializer_list<GroupItem> children) { addChildren(children); }
333 template <
typename Handler>
335 return groupHandler({wrapGroupSetup(std::forward<Handler>(handler))});
337 template <
typename Handler>
339 return groupHandler({{}, wrapGroupDone(std::forward<Handler>(handler)), callDoneIf});
341 using GroupItem::parallelLimit;
342 using GroupItem::workflowPolicy;
345 template <
typename Handler>
346 static GroupSetupHandler wrapGroupSetup(Handler &&handler)
349 static constexpr bool isR = isInvocable<SetupResult, Handler>();
350 static constexpr bool isV = isInvocable<void, Handler>();
351 static_assert(isR || isV,
352 "Group setup handler needs to take no arguments and has to return void or SetupResult. "
353 "The passed handler doesn't fulfill these requirements.");
356 return std::invoke(handler);
357 std::invoke(handler);
358 return SetupResult::Continue;
361 template <
typename Handler>
362 static GroupDoneHandler wrapGroupDone(Handler &&handler)
365 static constexpr bool isRD = isInvocable<DoneResult, Handler, DoneWith>();
366 static constexpr bool isR = isInvocable<DoneResult, Handler>();
367 static constexpr bool isVD = isInvocable<void, Handler, DoneWith>();
368 static constexpr bool isV = isInvocable<void, Handler>();
369 static_assert(isRD || isR || isVD || isV,
370 "Group done handler needs to take (DoneWith) or (void) as an argument and has to "
371 "return void or DoneResult. The passed handler doesn't fulfill these requirements.");
374 return std::invoke(handler,
result);
376 return std::invoke(handler);
378 std::invoke(handler,
result);
379 else if constexpr (isV)
380 std::invoke(handler);
381 return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
386template <
typename Handler>
389 return Group::onGroupSetup(std::forward<Handler>(handler));
392template <
typename Handler>
395 return Group::onGroupDone(std::forward<Handler>(handler), callDoneIf);
405TASKING_EXPORT extern const GroupItem parallelIdealThreadCountLimit;
426 template <
typename Handler>
428 addChildren({
onGroupSetup(wrapHandler(std::forward<Handler>(handler))) });
432 template <
typename Handler>
433 static GroupSetupHandler wrapHandler(Handler &&handler) {
435 static constexpr bool isR = isInvocable<DoneResult, Handler>();
436 static constexpr bool isV = isInvocable<void, Handler>();
437 static_assert(isR || isV,
438 "Sync handler needs to take no arguments and has to return void or DoneResult. "
439 "The passed handler doesn't fulfill these requirements.");
442 return std::invoke(handler) == DoneResult::Success ? SetupResult::StopWithSuccess
443 : SetupResult::StopWithError;
445 std::invoke(handler);
446 return SetupResult::StopWithSuccess;
451template <
typename Task,
typename Deleter = std::default_delete<Task>>
456 Task *
task() {
return m_task.get(); }
457 const Task *
task()
const {
return m_task.get(); }
460 using TaskType = Task;
461 using DeleterType = Deleter;
463 std::unique_ptr<Task, Deleter> m_task;
466template <
typename Adapter>
470 using Task =
typename Adapter::TaskType;
471 using Deleter =
typename Adapter::DeleterType;
472 static_assert(std::is_base_of_v<TaskAdapter<Task, Deleter>, Adapter>,
473 "The Adapter type for the CustomTask<Adapter> needs to be derived from "
474 "TaskAdapter<Task>.");
478 template <
typename SetupHandler = TaskSetupHandler,
typename DoneHandler = TaskDoneHandler>
480 CallDoneIf callDoneIf = CallDoneIf::SuccessOrError)
481 :
ExecutableItem({&createAdapter, wrapSetup(std::forward<SetupHandler>(setup)),
482 wrapDone(std::forward<DoneHandler>(
done)), callDoneIf})
486 static Adapter *createAdapter() {
return new Adapter; }
488 template <
typename Handler>
489 static InterfaceSetupHandler wrapSetup(Handler &&handler) {
490 if constexpr (std::is_same_v<Handler, TaskSetupHandler>)
493 static constexpr bool isR = isInvocable<SetupResult, Handler, Task &>();
494 static constexpr bool isV = isInvocable<void, Handler, Task &>();
495 static_assert(isR || isV,
496 "Task setup handler needs to take (Task &) as an argument and has to return void or "
497 "SetupResult. The passed handler doesn't fulfill these requirements.");
498 return [handler](TaskInterface &taskInterface) {
499 Adapter &adapter =
static_cast<Adapter &
>(taskInterface);
501 return std::invoke(handler, *adapter.task());
502 std::invoke(handler, *adapter.task());
503 return SetupResult::Continue;
507 template <
typename Handler>
508 static InterfaceDoneHandler wrapDone(Handler &&handler) {
509 if constexpr (std::is_same_v<Handler, TaskDoneHandler>)
512 static constexpr bool isRTD = isInvocable<DoneResult, Handler, const Task &, DoneWith>();
513 static constexpr bool isRT = isInvocable<DoneResult, Handler, const Task &>();
514 static constexpr bool isRD = isInvocable<DoneResult, Handler, DoneWith>();
515 static constexpr bool isR = isInvocable<DoneResult, Handler>();
516 static constexpr bool isVTD = isInvocable<void, Handler, const Task &, DoneWith>();
517 static constexpr bool isVT = isInvocable<void, Handler, const Task &>();
518 static constexpr bool isVD = isInvocable<void, Handler, DoneWith>();
519 static constexpr bool isV = isInvocable<void, Handler>();
520 static_assert(isRTD || isRT || isRD || isR || isVTD || isVT || isVD || isV,
521 "Task done handler needs to take (const Task &, DoneWith), (const Task &), "
522 "(DoneWith) or (void) as arguments and has to return void or DoneResult. "
523 "The passed handler doesn't fulfill these requirements.");
524 return [handler](
const TaskInterface &taskInterface,
DoneWith result) {
525 const Adapter &adapter =
static_cast<const Adapter &
>(taskInterface);
527 return std::invoke(handler, *adapter.task(),
result);
529 return std::invoke(handler, *adapter.task());
531 return std::invoke(handler,
result);
533 return std::invoke(handler);
535 std::invoke(handler, *adapter.task(),
result);
536 else if constexpr (isVT)
537 std::invoke(handler, *adapter.task());
538 else if constexpr (isVD)
539 std::invoke(handler,
result);
540 else if constexpr (isV)
541 std::invoke(handler);
542 return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
556 void setRecipe(
const Group &recipe);
568 std::chrono::milliseconds
timeout = std::chrono::milliseconds::max());
570 std::chrono::milliseconds
timeout = std::chrono::milliseconds::max());
572 int asyncCount()
const;
573 int taskCount()
const;
575 int progressValue()
const;
577 template <
typename StorageStruct,
typename Handler>
579 static_assert(std::is_invocable_v<std::decay_t<Handler>, StorageStruct &>,
580 "Storage setup handler needs to take (Storage &) as an argument. "
581 "The passed handler doesn't fulfill this requirement.");
583 wrapHandler<StorageStruct>(std::forward<Handler>(handler)), {});
585 template <
typename StorageStruct,
typename Handler>
587 static_assert(std::is_invocable_v<std::decay_t<Handler>,
const StorageStruct &>,
588 "Storage done handler needs to take (const Storage &) as an argument. "
589 "The passed handler doesn't fulfill this requirement.");
590 setupStorageHandler(
storage, {},
591 wrapHandler<const StorageStruct>(std::forward<Handler>(handler)));
602 StorageBase::StorageHandler setupHandler,
603 StorageBase::StorageHandler doneHandler);
604 template <
typename StorageStruct,
typename Handler>
605 StorageBase::StorageHandler wrapHandler(Handler &&handler) {
606 return [handler](
void *voidStruct) {
607 auto *storageStruct =
static_cast<StorageStruct *
>(voidStruct);
608 std::invoke(handler, *storageStruct);
632 std::optional<int> m_timerId;
const_reference at(qsizetype i) const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
\macro QT_RESTRICTED_CAST_FROM_ASCII
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
typename Adapter::TaskType Task
typename Adapter::DeleterType Deleter
std::function< DoneResult(const Task &, DoneWith)> TaskDoneHandler
std::function< SetupResult(Task &)> TaskSetupHandler
CustomTask(SetupHandler &&setup=TaskSetupHandler(), DoneHandler &&done=TaskDoneHandler(), CallDoneIf callDoneIf=CallDoneIf::SuccessOrError)
\typealias CustomTask::Task
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
ExecutableItem(const TaskHandler &handler)
ExecutableItem withCancel(SenderSignalPairGetter &&getter) const
Forever(std::initializer_list< GroupItem > children)
Forever(const QList< GroupItem > &children)
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
std::function< SetupResult()> GroupSetupHandler
std::function< DoneResult(const TaskInterface &, DoneWith)> InterfaceDoneHandler
std::function< SetupResult(TaskInterface &)> InterfaceSetupHandler
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)
GroupItem(const GroupData &data)
static GroupItem parallelLimit(int limit)
GroupItem(const QList< GroupItem > &children)
Constructs a GroupItem element with a given list of items.
static GroupItem workflowPolicy(WorkflowPolicy policy)
std::function< DoneResult(DoneWith)> GroupDoneHandler
static GroupItem groupHandler(const GroupHandler &handler)
std::function< TaskInterface *(void)> InterfaceCreateHandler
GroupItem(const Storage< StorageStruct > &storage)
Constructs a GroupItem element holding the storage object.
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)
std::function< const void *(int)> ValueGetter
std::function< bool(int)> Condition
const void * valuePtr() const
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)
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
StorageStruct & operator*() const noexcept
Returns a reference to the active StorageStruct object, created by the running task tree.
StorageStruct * operator->() const noexcept
Returns a pointer 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.
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
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
void done(DoneResult result)
Emit this signal from the TaskAdapter<Task>'s subclass, when the Task is finished.
virtual void start()=0
This method is called by the running TaskTree for starting the Task instance.
\inheaderfile solutions/tasking/tasktree.h \inmodule TaskingSolution
void done(DoneWith result)
This signal is emitted when the task tree finished, passing the final result of the execution.
int progressMaximum() const
Returns the maximum progressValue().
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())
void started()
This signal is emitted when the task tree is started.
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 ...
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.
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...
Combined button and popup list for selecting options.
\inmodule TaskingSolution
static GroupItem onGroupSetup(Handler &&handler)
\typealias GroupItem::GroupSetupHandler
CustomTask< TimeoutTaskAdapter > TimeoutTask
CustomTask< TaskTreeTaskAdapter > TaskTreeTask
DoneResult toDoneResult(bool success)
static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf=CallDoneIf::SuccessOrError)
Constructs a group's element holding the group done handler.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
QFuture< void > future
[5]
GroupSetupHandler m_setupHandler
InterfaceCreateHandler m_createHandler