Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:07:24

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