Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-17 09:24:55

0001 // Copyright (C) 2020 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 // Qt-Security score:significant reason:default
0004 
0005 #ifndef QFUTUREINTERFACE_H
0006 #define QFUTUREINTERFACE_H
0007 
0008 #include <QtCore/qmutex.h>
0009 #include <QtCore/qresultstore.h>
0010 #include <QtCore/qtcoreexports.h>
0011 #ifndef QT_NO_EXCEPTIONS
0012 #include <exception>
0013 #endif
0014 
0015 #include <utility>
0016 
0017 QT_REQUIRE_CONFIG(future);
0018 
0019 QT_FORWARD_DECLARE_CLASS(QRunnable)
0020 QT_FORWARD_DECLARE_CLASS(QException)
0021 QT_BEGIN_NAMESPACE
0022 
0023 
0024 template <typename T> class QFuture;
0025 class QThreadPool;
0026 class QFutureInterfaceBase;
0027 class QFutureInterfaceBasePrivate;
0028 class QFutureWatcherBase;
0029 class QFutureWatcherBasePrivate;
0030 
0031 namespace QtPrivate {
0032 template<typename Function, typename ResultType, typename ParentResultType>
0033 class CompactContinuation;
0034 
0035 class ExceptionStore;
0036 
0037 template<class Function, class ResultType>
0038 class CanceledHandler;
0039 
0040 #ifndef QT_NO_EXCEPTIONS
0041 template<class Function, class ResultType>
0042 class FailureHandler;
0043 #endif
0044 
0045 struct UnwrapHandler;
0046 
0047 #if QT_CORE_REMOVED_SINCE(6, 10)
0048 void Q_CORE_EXPORT watchContinuationImpl(const QObject *context,
0049                                          QtPrivate::QSlotObjectBase *slotObj,
0050                                          QFutureInterfaceBase &fi);
0051 #endif // QT_CORE_REMOVED_SINCE(6, 10)
0052 }
0053 
0054 class Q_CORE_EXPORT QFutureInterfaceBase
0055 {
0056 public:
0057     enum State {
0058         NoState    = 0x00,
0059         Running    = 0x01,
0060         Started    = 0x02,
0061         Finished   = 0x04,
0062         Canceled   = 0x08,
0063         Suspending = 0x10,
0064         Suspended  = 0x20,
0065         Throttled  = 0x40,
0066         // Pending means that the future depends on another one, which is not finished yet
0067         Pending    = 0x80,
0068     };
0069 
0070     QFutureInterfaceBase(State initialState = NoState);
0071     QFutureInterfaceBase(const QFutureInterfaceBase &other);
0072     QFutureInterfaceBase(QFutureInterfaceBase &&other) noexcept
0073         : d(std::exchange(other.d, nullptr)) {}
0074     QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other);
0075     QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QFutureInterfaceBase)
0076     virtual ~QFutureInterfaceBase();
0077 
0078     // reporting functions available to the engine author:
0079     void reportStarted();
0080     void reportFinished();
0081     void reportCanceled();
0082 #ifndef QT_NO_EXCEPTIONS
0083     void reportException(const QException &e);
0084 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0085     void reportException(std::exception_ptr e);
0086 #else
0087     void reportException(const std::exception_ptr &e);
0088 #endif
0089 #endif
0090     void reportResultsReady(int beginIndex, int endIndex);
0091 
0092     void setRunnable(QRunnable *runnable);
0093     void setThreadPool(QThreadPool *pool);
0094     QThreadPool *threadPool() const;
0095     void setFilterMode(bool enable);
0096     void setProgressRange(int minimum, int maximum);
0097     int progressMinimum() const;
0098     int progressMaximum() const;
0099     bool isProgressUpdateNeeded() const;
0100     void setProgressValue(int progressValue);
0101     int progressValue() const;
0102     void setProgressValueAndText(int progressValue, const QString &progressText);
0103     QString progressText() const;
0104 
0105     void setExpectedResultCount(int resultCount);
0106     int expectedResultCount();
0107     int resultCount() const;
0108 
0109     bool queryState(State state) const;
0110     bool isRunning() const;
0111     bool isStarted() const;
0112     bool isCanceled() const;
0113     bool isFinished() const;
0114 #if QT_DEPRECATED_SINCE(6, 0)
0115     QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.")
0116     bool isPaused() const;
0117 
0118     QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.")
0119     void setPaused(bool paused) { setSuspended(paused); }
0120 
0121     QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.")
0122     void togglePaused() { toggleSuspended(); }
0123 #endif
0124     bool isSuspending() const;
0125     bool isSuspended() const;
0126     bool isThrottled() const;
0127     bool isResultReadyAt(int index) const;
0128     bool isValid() const;
0129     int loadState() const;
0130 
0131     void cancel();
0132     void cancelAndFinish() { cancel(CancelMode::CancelAndFinish); }
0133     void cancelChain();
0134     void setAddResultsIfCanceledEnabled(bool enable);
0135     bool isAddResultsIfCanceledEnabled() const;
0136 
0137     void setSuspended(bool suspend);
0138     void toggleSuspended();
0139     void reportSuspended() const;
0140     void setThrottled(bool enable);
0141 
0142     void waitForFinished();
0143     bool waitForNextResult();
0144     void waitForResult(int resultIndex);
0145     void waitForResume();
0146     void suspendIfRequested();
0147 
0148     QMutex &mutex() const;
0149     bool hasException() const;
0150     QtPrivate::ExceptionStore &exceptionStore();
0151     QtPrivate::ResultStoreBase &resultStoreBase();
0152     const QtPrivate::ResultStoreBase &resultStoreBase() const;
0153 
0154     inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; }
0155     inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; }
0156 
0157     // ### Qt 7: inline
0158     void swap(QFutureInterfaceBase &other) noexcept;
0159 
0160     template<typename T>
0161     static QFutureInterfaceBase get(const QFuture<T> &future);  // implemented in qfuture.h
0162 
0163     bool isChainCanceled() const;
0164 
0165 protected:
0166     // ### Qt 7: remove const from refT/derefT
0167     bool refT() const noexcept;
0168     bool derefT() const noexcept;
0169     void reset();
0170     void rethrowPossibleException();
0171 public:
0172 
0173 #ifndef QFUTURE_TEST
0174 private:
0175 #endif
0176     friend class QFutureInterfaceBasePrivate;
0177     QFutureInterfaceBasePrivate *d;
0178 
0179 private:
0180     friend class QFutureWatcherBase;
0181     friend class QFutureWatcherBasePrivate;
0182 
0183     template<typename Function, typename ResultType, typename ParentResultType>
0184     friend class QtPrivate::CompactContinuation;
0185 
0186     template<class Function, class ResultType>
0187     friend class QtPrivate::CanceledHandler;
0188 
0189 #ifndef QT_NO_EXCEPTIONS
0190     template<class Function, class ResultType>
0191     friend class QtPrivate::FailureHandler;
0192 #endif
0193 
0194     friend struct QtPrivate::UnwrapHandler;
0195 
0196 #if QT_CORE_REMOVED_SINCE(6, 10)
0197     friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
0198             const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
0199 #endif // QT_CORE_REMOVED_SINCE(6, 10)
0200 
0201     template<class T>
0202     friend class QPromise;
0203 
0204 protected:
0205     enum class ContinuationType : quint8
0206     {
0207         Unknown,
0208         Then,
0209         OnFailed,
0210         OnCanceled,
0211     };
0212 
0213 #if QT_CORE_REMOVED_SINCE(6, 10)
0214     void setContinuation(std::function<void(const QFutureInterfaceBase &)> func);
0215     void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
0216                          QFutureInterfaceBasePrivate *continuationFutureData);
0217 #endif // QT_CORE_REMOVED_SINCE(6, 10)
0218     void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
0219                          void *continuationFutureData, ContinuationType type);
0220     void setContinuation(const QObject *context, std::function<void()> func,
0221                          const QVariant &continuationFuture, ContinuationType type);
0222     void cleanContinuation();
0223     void runContinuation() const;
0224 
0225     void setLaunchAsync(bool value);
0226     bool launchAsync() const;
0227 
0228     bool isRunningOrPending() const;
0229 
0230     enum class CancelMode { CancelOnly, CancelAndFinish };
0231     void cancel(CancelMode mode);
0232     void cancelChain(CancelMode mode);
0233 };
0234 
0235 inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
0236 {
0237     lhs.swap(rhs);
0238 }
0239 
0240 template <typename T>
0241 class QFutureInterface : public QFutureInterfaceBase
0242 {
0243 public:
0244     QFutureInterface(State initialState = NoState)
0245         : QFutureInterfaceBase(initialState)
0246     {
0247         refT();
0248     }
0249     QFutureInterface(const QFutureInterface &other)
0250         : QFutureInterfaceBase(other)
0251     {
0252         refT();
0253     }
0254     QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { refT(); }
0255     QFutureInterface(QFutureInterfaceBase &&dd) noexcept : QFutureInterfaceBase(std::move(dd)) { refT(); }
0256     QFutureInterface &operator=(const QFutureInterface &other)
0257     {
0258         QFutureInterface copy(other);
0259         swap(copy);
0260         return *this;
0261     }
0262     QFutureInterface(QFutureInterface &&other) = default;
0263     QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QFutureInterface)
0264 
0265     ~QFutureInterface()
0266     {
0267         if (!derefT() && !hasException())
0268             resultStoreBase().template clear<T>();
0269     }
0270 
0271     static QFutureInterface canceledResult()
0272     { return QFutureInterface(State(Started | Finished | Canceled)); }
0273 
0274     inline QFuture<T> future(); // implemented in qfuture.h
0275 
0276     template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
0277     inline bool reportAndEmplaceResult(int index, Args&&...args);
0278     inline bool reportResult(const T *result, int index = -1);
0279     inline bool reportAndMoveResult(T &&result, int index = -1);
0280     inline bool reportResult(T &&result, int index = -1);
0281     inline bool reportResult(const T &result, int index = -1);
0282     inline bool reportResults(const QList<T> &results, int beginIndex = -1, int count = -1);
0283     inline bool reportFinished(const T *result);
0284     void reportFinished()
0285     {
0286         QFutureInterfaceBase::reportFinished();
0287         QFutureInterfaceBase::runContinuation();
0288     }
0289 
0290     inline const T &resultReference(int index) const;
0291     inline const T *resultPointer(int index) const;
0292     inline QList<T> results();
0293 
0294     T takeResult();
0295 #if 0
0296     // TODO: Enable and make it return a QList, when QList is fixed to support move-only types
0297     std::vector<T> takeResults();
0298 #endif
0299 
0300 #ifndef QT_NO_EXCEPTIONS
0301     void reportException(const std::exception_ptr &e)
0302     {
0303         if (hasException())
0304             return;
0305 
0306         resultStoreBase().template clear<T>();
0307         QFutureInterfaceBase::reportException(e);
0308     }
0309     void reportException(const QException &e)
0310     {
0311         if (hasException())
0312             return;
0313 
0314         resultStoreBase().template clear<T>();
0315         QFutureInterfaceBase::reportException(e);
0316     }
0317 #endif
0318 };
0319 
0320 template <typename T>
0321 inline bool QFutureInterface<T>::reportResult(const T *result, int index)
0322 {
0323     QMutexLocker<QMutex> locker{&mutex()};
0324     if ((this->queryState(Canceled) && !this->isAddResultsIfCanceledEnabled()) || this->queryState(Finished))
0325         return false;
0326 
0327     Q_ASSERT(!hasException());
0328     QtPrivate::ResultStoreBase &store = resultStoreBase();
0329 
0330     const int resultCountBefore = store.count();
0331     const int insertIndex = store.addResult<T>(index, result);
0332     if (insertIndex == -1)
0333         return false;
0334     if (store.filterMode()) {
0335         this->reportResultsReady(resultCountBefore, store.count());
0336     } else {
0337         this->reportResultsReady(insertIndex, insertIndex + 1);
0338     }
0339     return true;
0340 }
0341 
0342 template<typename T>
0343 template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>>
0344 bool QFutureInterface<T>::reportAndEmplaceResult(int index, Args&&...args)
0345 {
0346     QMutexLocker<QMutex> locker{&mutex()};
0347     if ((queryState(Canceled) && !isAddResultsIfCanceledEnabled()) || queryState(Finished))
0348         return false;
0349 
0350     Q_ASSERT(!hasException());
0351     QtPrivate::ResultStoreBase &store = resultStoreBase();
0352 
0353     const int oldResultCount = store.count();
0354     const int insertIndex = store.emplaceResult<T>(index, std::forward<Args>(args)...);
0355     // Let's make sure it's not in pending results.
0356     if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count()))
0357         reportResultsReady(insertIndex, store.count());
0358     return insertIndex != -1;
0359 }
0360 
0361 template<typename T>
0362 bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
0363 {
0364     return reportAndEmplaceResult(index, std::move(result));
0365 }
0366 
0367 template<typename T>
0368 bool QFutureInterface<T>::reportResult(T &&result, int index)
0369 {
0370     return reportAndMoveResult(std::move(result), index);
0371 }
0372 
0373 template <typename T>
0374 inline bool QFutureInterface<T>::reportResult(const T &result, int index)
0375 {
0376     return reportResult(&result, index);
0377 }
0378 
0379 template<typename T>
0380 inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beginIndex, int count)
0381 {
0382     QMutexLocker<QMutex> locker{&mutex()};
0383     if ((this->queryState(Canceled) && !this->isAddResultsIfCanceledEnabled()) || this->queryState(Finished))
0384         return false;
0385 
0386     Q_ASSERT(!hasException());
0387     auto &store = resultStoreBase();
0388 
0389     const int resultCountBefore = store.count();
0390     const int insertIndex = store.addResults(beginIndex, &_results, count);
0391     if (insertIndex == -1)
0392         return false;
0393     if (store.filterMode()) {
0394         this->reportResultsReady(resultCountBefore, store.count());
0395     } else {
0396         this->reportResultsReady(insertIndex, insertIndex + _results.size());
0397     }
0398     return true;
0399 }
0400 
0401 template <typename T>
0402 inline bool QFutureInterface<T>::reportFinished(const T *result)
0403 {
0404     bool resultReported = false;
0405     if (result)
0406         resultReported = reportResult(result);
0407     reportFinished();
0408     return resultReported;
0409 }
0410 
0411 template <typename T>
0412 inline const T &QFutureInterface<T>::resultReference(int index) const
0413 {
0414     Q_ASSERT(!hasException());
0415 
0416     QMutexLocker<QMutex> locker{&mutex()};
0417     return resultStoreBase().resultAt(index).template value<T>();
0418 }
0419 
0420 template <typename T>
0421 inline const T *QFutureInterface<T>::resultPointer(int index) const
0422 {
0423     Q_ASSERT(!hasException());
0424 
0425     QMutexLocker<QMutex> locker{&mutex()};
0426     return resultStoreBase().resultAt(index).template pointer<T>();
0427 }
0428 
0429 template <typename T>
0430 inline QList<T> QFutureInterface<T>::results()
0431 {
0432     if (this->isCanceled()) {
0433         rethrowPossibleException();
0434         return QList<T>();
0435     }
0436 
0437     QFutureInterfaceBase::waitForResult(-1);
0438 
0439     QList<T> res;
0440     QMutexLocker<QMutex> locker{&mutex()};
0441 
0442     QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
0443     while (it != resultStoreBase().end()) {
0444         res.append(it.value<T>());
0445         ++it;
0446     }
0447 
0448     return res;
0449 }
0450 
0451 template<typename T>
0452 T QFutureInterface<T>::takeResult()
0453 {
0454     // Note: we wait for all, this is intentional,
0455     // not to mess with other unready results.
0456     waitForResult(-1);
0457 
0458     Q_ASSERT(isValid());
0459     Q_ASSERT(!hasException());
0460 
0461     const QMutexLocker<QMutex> locker{&mutex()};
0462     QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
0463     T ret(std::move_if_noexcept(position.value<T>()));
0464     reset();
0465     resultStoreBase().template clear<T>();
0466 
0467     return ret;
0468 }
0469 
0470 #if 0
0471 template<typename T>
0472 std::vector<T> QFutureInterface<T>::takeResults()
0473 {
0474     waitForResult(-1);
0475 
0476     Q_ASSERT(isValid());
0477     Q_ASSERT(!hasException());
0478 
0479     std::vector<T> res;
0480     res.reserve(resultCount());
0481 
0482     const QMutexLocker<QMutex> locker{&mutex()};
0483 
0484     QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
0485     for (auto endIt = resultStoreBase().end(); it != endIt; ++it)
0486         res.push_back(std::move_if_noexcept(it.value<T>()));
0487 
0488     reset();
0489     resultStoreBase().template clear<T>();
0490 
0491     return res;
0492 }
0493 #endif
0494 
0495 QT_WARNING_PUSH
0496 QT_WARNING_DISABLE_CLANG("-Wweak-vtables") // QTBUG-125115
0497 
0498 template <>
0499 class QFutureInterface<void> : public QFutureInterfaceBase
0500 {
0501 public:
0502     explicit QFutureInterface(State initialState = NoState)
0503         : QFutureInterfaceBase(initialState)
0504     { }
0505 
0506     QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { }
0507 
0508     static QFutureInterface<void> canceledResult()
0509     { return QFutureInterface(State(Started | Finished | Canceled)); }
0510 
0511 
0512     inline QFuture<void> future(); // implemented in qfuture.h
0513 
0514     bool reportResult(const void *, int) { return false; }
0515     bool reportResults(const QList<void> &, int) { return false; }
0516     bool reportFinished(const void *)
0517     {
0518         reportFinished();
0519         return false;
0520     }
0521     void reportFinished()
0522     {
0523         QFutureInterfaceBase::reportFinished();
0524         QFutureInterfaceBase::runContinuation();
0525     }
0526 };
0527 
0528 QT_WARNING_POP // Clang -Wweak-vtables
0529 
0530 template<typename T>
0531 inline void swap(QFutureInterface<T> &a, QFutureInterface<T> &b) noexcept
0532 {
0533     a.swap(b);
0534 }
0535 
0536 QT_END_NAMESPACE
0537 
0538 #endif // QFUTUREINTERFACE_H