diff options
Diffstat (limited to 'src/corelib/thread/qfutureinterface.h')
-rw-r--r-- | src/corelib/thread/qfutureinterface.h | 184 |
1 files changed, 116 insertions, 68 deletions
diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index 2432503cf7..180a59a94e 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -1,61 +1,27 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 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 QFUTUREINTERFACE_H #define QFUTUREINTERFACE_H -#include <QtCore/qrunnable.h> #include <QtCore/qmutex.h> -#include <QtCore/qexception.h> #include <QtCore/qresultstore.h> +#ifndef QT_NO_EXCEPTIONS +#include <exception> +#endif #include <utility> -#include <vector> -#include <mutex> QT_REQUIRE_CONFIG(future); +QT_FORWARD_DECLARE_CLASS(QRunnable) +QT_FORWARD_DECLARE_CLASS(QException) QT_BEGIN_NAMESPACE template <typename T> class QFuture; class QThreadPool; +class QFutureInterfaceBase; class QFutureInterfaceBasePrivate; class QFutureWatcherBase; class QFutureWatcherBasePrivate; @@ -64,6 +30,8 @@ namespace QtPrivate { template<typename Function, typename ResultType, typename ParentResultType> class Continuation; +class ExceptionStore; + template<class Function, class ResultType> class CanceledHandler; @@ -71,6 +39,10 @@ class CanceledHandler; template<class Function, class ResultType> class FailureHandler; #endif + +void Q_CORE_EXPORT watchContinuationImpl(const QObject *context, + QtPrivate::QSlotObjectBase *slotObj, + QFutureInterfaceBase &fi); } class Q_CORE_EXPORT QFutureInterfaceBase @@ -91,6 +63,10 @@ public: QFutureInterfaceBase(State initialState = NoState); QFutureInterfaceBase(const QFutureInterfaceBase &other); + QFutureInterfaceBase(QFutureInterfaceBase &&other) noexcept + : d(std::exchange(other.d, nullptr)) {} + QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other); + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QFutureInterfaceBase) virtual ~QFutureInterfaceBase(); // reporting functions available to the engine author: @@ -99,7 +75,11 @@ public: void reportCanceled(); #ifndef QT_NO_EXCEPTIONS void reportException(const QException &e); +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) void reportException(std::exception_ptr e); +#else + void reportException(const std::exception_ptr &e); +#endif #endif void reportResultsReady(int beginIndex, int endIndex); @@ -143,6 +123,8 @@ public: int loadState() const; void cancel(); + void cancelAndFinish() { cancel(CancelMode::CancelAndFinish); } + void setSuspended(bool suspend); void toggleSuspended(); void reportSuspended() const; @@ -155,20 +137,28 @@ public: void suspendIfRequested(); QMutex &mutex() const; + bool hasException() const; QtPrivate::ExceptionStore &exceptionStore(); QtPrivate::ResultStoreBase &resultStoreBase(); const QtPrivate::ResultStoreBase &resultStoreBase() const; inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; } inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; } - QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other); + // ### Qt 7: inline void swap(QFutureInterfaceBase &other) noexcept; + template<typename T> + static QFutureInterfaceBase get(const QFuture<T> &future); // implemented in qfuture.h + + bool isChainCanceled() const; + protected: - bool refT() const; - bool derefT() const; + // ### Qt 7: remove const from refT/derefT + bool refT() const noexcept; + bool derefT() const noexcept; void reset(); + void rethrowPossibleException(); public: #ifndef QFUTURE_TEST @@ -191,16 +181,33 @@ private: friend class QtPrivate::FailureHandler; #endif + friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl( + const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi); + + template<class T> + friend class QPromise; + protected: void setContinuation(std::function<void(const QFutureInterfaceBase &)> func); + void setContinuation(std::function<void(const QFutureInterfaceBase &)> func, + QFutureInterfaceBasePrivate *continuationFutureData); + void cleanContinuation(); void runContinuation() const; void setLaunchAsync(bool value); bool launchAsync() const; bool isRunningOrPending() const; + + enum class CancelMode { CancelOnly, CancelAndFinish }; + void cancel(CancelMode mode); }; +inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept +{ + lhs.swap(rhs); +} + template <typename T> class QFutureInterface : public QFutureInterfaceBase { @@ -216,26 +223,29 @@ public: refT(); } QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { refT(); } + QFutureInterface(QFutureInterfaceBase &&dd) noexcept : QFutureInterfaceBase(std::move(dd)) { refT(); } + QFutureInterface &operator=(const QFutureInterface &other) + { + QFutureInterface copy(other); + swap(copy); + return *this; + } + QFutureInterface(QFutureInterface &&other) = default; + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QFutureInterface) + ~QFutureInterface() { - if (!derefT()) + if (!derefT() && !hasException()) resultStoreBase().template clear<T>(); } static QFutureInterface canceledResult() { return QFutureInterface(State(Started | Finished | Canceled)); } - QFutureInterface &operator=(const QFutureInterface &other) - { - other.refT(); - if (!derefT()) - resultStoreBase().template clear<T>(); - QFutureInterfaceBase::operator=(other); - return *this; - } - inline QFuture<T> future(); // implemented in qfuture.h + template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true> + inline bool reportAndEmplaceResult(int index, Args&&...args); inline bool reportResult(const T *result, int index = -1); inline bool reportAndMoveResult(T &&result, int index = -1); inline bool reportResult(T &&result, int index = -1); @@ -257,15 +267,35 @@ public: // TODO: Enable and make it return a QList, when QList is fixed to support move-only types std::vector<T> takeResults(); #endif + +#ifndef QT_NO_EXCEPTIONS + void reportException(const std::exception_ptr &e) + { + if (hasException()) + return; + + resultStoreBase().template clear<T>(); + QFutureInterfaceBase::reportException(e); + } + void reportException(const QException &e) + { + if (hasException()) + return; + + resultStoreBase().template clear<T>(); + QFutureInterfaceBase::reportException(e); + } +#endif }; template <typename T> inline bool QFutureInterface<T>::reportResult(const T *result, int index) { - std::lock_guard<QMutex> locker{mutex()}; + QMutexLocker<QMutex> locker{&mutex()}; if (this->queryState(Canceled) || this->queryState(Finished)) return false; + Q_ASSERT(!hasException()); QtPrivate::ResultStoreBase &store = resultStoreBase(); const int resultCountBefore = store.count(); @@ -281,16 +311,18 @@ inline bool QFutureInterface<T>::reportResult(const T *result, int index) } template<typename T> -bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index) +template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>> +bool QFutureInterface<T>::reportAndEmplaceResult(int index, Args&&...args) { - std::lock_guard<QMutex> locker{mutex()}; + QMutexLocker<QMutex> locker{&mutex()}; if (queryState(Canceled) || queryState(Finished)) return false; + Q_ASSERT(!hasException()); QtPrivate::ResultStoreBase &store = resultStoreBase(); const int oldResultCount = store.count(); - const int insertIndex = store.moveResult(index, std::forward<T>(result)); + const int insertIndex = store.emplaceResult<T>(index, std::forward<Args>(args)...); // Let's make sure it's not in pending results. if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count())) reportResultsReady(insertIndex, store.count()); @@ -298,6 +330,12 @@ bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index) } template<typename T> +bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index) +{ + return reportAndEmplaceResult(index, std::move(result)); +} + +template<typename T> bool QFutureInterface<T>::reportResult(T &&result, int index) { return reportAndMoveResult(std::move(result), index); @@ -312,10 +350,11 @@ inline bool QFutureInterface<T>::reportResult(const T &result, int index) template<typename T> inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beginIndex, int count) { - std::lock_guard<QMutex> locker{mutex()}; + QMutexLocker<QMutex> locker{&mutex()}; if (this->queryState(Canceled) || this->queryState(Finished)) return false; + Q_ASSERT(!hasException()); auto &store = resultStoreBase(); const int resultCountBefore = store.count(); @@ -325,7 +364,7 @@ inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beg if (store.filterMode()) { this->reportResultsReady(resultCountBefore, store.count()); } else { - this->reportResultsReady(insertIndex, insertIndex + _results.count()); + this->reportResultsReady(insertIndex, insertIndex + _results.size()); } return true; } @@ -343,14 +382,18 @@ inline bool QFutureInterface<T>::reportFinished(const T *result) template <typename T> inline const T &QFutureInterface<T>::resultReference(int index) const { - std::lock_guard<QMutex> locker{mutex()}; + Q_ASSERT(!hasException()); + + QMutexLocker<QMutex> locker{&mutex()}; return resultStoreBase().resultAt(index).template value<T>(); } template <typename T> inline const T *QFutureInterface<T>::resultPointer(int index) const { - std::lock_guard<QMutex> locker{mutex()}; + Q_ASSERT(!hasException()); + + QMutexLocker<QMutex> locker{&mutex()}; return resultStoreBase().resultAt(index).template pointer<T>(); } @@ -358,14 +401,14 @@ template <typename T> inline QList<T> QFutureInterface<T>::results() { if (this->isCanceled()) { - exceptionStore().throwPossibleException(); + rethrowPossibleException(); return QList<T>(); } QFutureInterfaceBase::waitForResult(-1); QList<T> res; - std::lock_guard<QMutex> locker{mutex()}; + QMutexLocker<QMutex> locker{&mutex()}; QtPrivate::ResultIteratorBase it = resultStoreBase().begin(); while (it != resultStoreBase().end()) { @@ -385,7 +428,9 @@ T QFutureInterface<T>::takeResult() // not to mess with other unready results. waitForResult(-1); - const std::lock_guard<QMutex> locker{mutex()}; + Q_ASSERT(!hasException()); + + const QMutexLocker<QMutex> locker{&mutex()}; QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0); T ret(std::move_if_noexcept(position.value<T>())); reset(); @@ -401,10 +446,13 @@ std::vector<T> QFutureInterface<T>::takeResults() Q_ASSERT(isValid()); waitForResult(-1); + + Q_ASSERT(!hasException()); + std::vector<T> res; res.reserve(resultCount()); - const std::lock_guard<QMutex> locker{mutex()}; + const QMutexLocker<QMutex> locker{&mutex()}; QtPrivate::ResultIteratorBase it = resultStoreBase().begin(); for (auto endIt = resultStoreBase().end(); it != endIt; ++it) @@ -421,7 +469,7 @@ template <> class QFutureInterface<void> : public QFutureInterfaceBase { public: - explicit QFutureInterface<void>(State initialState = NoState) + explicit QFutureInterface(State initialState = NoState) : QFutureInterfaceBase(initialState) { } |