// Copyright (C) 2025 Jarek Kobus // Copyright (C) 2025 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 // Qt-Security score:significant reason:default #ifndef QTASKTREE_QTHREADFUNCTIONTASK_H #define QTASKTREE_QTHREADFUNCTIONTASK_H #include #include QT_REQUIRE_CONFIG(concurrent); QT_BEGIN_NAMESPACE namespace QtTaskTree { class QThreadFunctionBasePrivate; class Q_TASKTREE_EXPORT QThreadFunctionBase { Q_DECLARE_PRIVATE(QThreadFunctionBase) Q_DISABLE_COPY_MOVE(QThreadFunctionBase) public: QThreadFunctionBase(); virtual ~QThreadFunctionBase(); void setThreadPool(QThreadPool *pool); QThreadPool *threadPool() const; void setAutoDelayedSync(bool on); bool isAutoDelayedSync() const; void setSyncSkipped(bool on); bool isSyncSkipped() const; static void syncAll(); protected: void storeFuture(const QFuture &future); std::unique_ptr d_ptr; }; template class QThreadFunction final : public QThreadFunctionBase { Q_DISABLE_COPY_MOVE(QThreadFunction) public: QThreadFunction() : QThreadFunctionBase() {} ~QThreadFunction() override { m_watcher.disconnect(); } template void setThreadFunctionData(Function &&function, Args &&...args) { wrapConcurrent(std::forward(function), std::forward(args)...); } bool isDone() const { return m_watcher.isFinished(); } bool isResultAvailable() const { return future().resultCount(); } QFutureWatcher *futureWatcher() { return &m_watcher; } const QFutureWatcher *futureWatcher() const { return &m_watcher; } QFuture future() const { return m_watcher.future(); } ResultType result() const { return m_watcher.result(); } ResultType takeResult() const { return future().takeResult(); } ResultType resultAt(int index) const { return m_watcher.resultAt(index); } QList results() const { return future().results(); } #ifdef Q_QDOC void setThreadPool(QThreadPool *pool); QThreadPool *threadPool() const; void setAutoDelayedSync(bool on); bool isAutoDelayedSync() const; #endif private: template void wrapConcurrent(Function &&function, Args &&...args) { m_startHandler = [this, function = std::forward(function), args...] { QThreadPool *pool = threadPool() ? threadPool() : QThreadPool::globalInstance(); return QtConcurrent::run(pool, function, args...); }; } template void wrapConcurrent(std::reference_wrapper &&wrapper, Args &&...args) { m_startHandler = [this, wrapper = std::forward>(wrapper), args...] { QThreadPool *pool = threadPool() ? threadPool() : QThreadPool::globalInstance(); return QtConcurrent::run(pool, std::forward(wrapper.get()), args...); }; } std::function()> m_startHandler; QFutureWatcher m_watcher; template friend class QThreadFunctionTaskAdapter; }; template class QThreadFunctionTaskAdapter { public: void operator()(QThreadFunction *task, QTaskInterface *iface) const { if (task->future().isRunning()) { qWarning("QThreadFunction: Can't start, the future is still running."); return; } if (!task->m_startHandler) { qWarning("QThreadFunction: No start handler specified."); iface->reportDone(DoneResult::Error); return; } QObject::connect(&task->m_watcher, &QFutureWatcherBase::finished, iface, [task, iface] { iface->reportDone(toDoneResult(!task->m_watcher.isCanceled())); }, Qt::SingleShotConnection); task->m_watcher.setFuture(task->m_startHandler()); task->storeFuture(QFuture(task->future())); } }; template using QThreadFunctionTask = QCustomTask, QThreadFunctionTaskAdapter>; } // namespace QtTaskTree QT_END_NAMESPACE #endif // QTASKTREE_QTHREADFUNCTIONTASK_H