Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qfutureinterface.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QFUTUREINTERFACE_H
6#define QFUTUREINTERFACE_H
7
8#include <QtCore/qmutex.h>
9#include <QtCore/qresultstore.h>
10#include <QtCore/qtcoreexports.h>
11#ifndef QT_NO_EXCEPTIONS
12#include <exception>
13#endif
14
15#include <utility>
16
18
20QT_FORWARD_DECLARE_CLASS(QException)
21QT_BEGIN_NAMESPACE
22
23
24template <typename T> class QFuture;
25class QThreadPool;
26class QFutureInterfaceBase;
28class QFutureWatcherBase;
29class QFutureWatcherBasePrivate;
30
31namespace QtPrivate {
32template<typename Function, typename ResultType, typename ParentResultType>
34
35class ExceptionStore;
36
37template<class Function, class ResultType>
38class CanceledHandler;
39
40#ifndef QT_NO_EXCEPTIONS
41template<class Function, class ResultType>
42class FailureHandler;
43#endif
44
45struct UnwrapHandler;
46
47#if QT_CORE_REMOVED_SINCE(6, 10)
51#endif // QT_CORE_REMOVED_SINCE(6, 10)
52}
53
54class Q_CORE_EXPORT QFutureInterfaceBase
55{
56public:
57 enum State {
58 NoState = 0x00,
59 Running = 0x01,
60 Started = 0x02,
61 Finished = 0x04,
62 Canceled = 0x08,
63 Suspending = 0x10,
64 Suspended = 0x20,
65 Throttled = 0x40,
66 // Pending means that the future depends on another one, which is not finished yet
67 Pending = 0x80,
68 };
69
70 QFutureInterfaceBase(State initialState = NoState);
71 QFutureInterfaceBase(const QFutureInterfaceBase &other);
72 QFutureInterfaceBase(QFutureInterfaceBase &&other) noexcept
73 : d(std::exchange(other.d, nullptr)) {}
74 QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other);
75 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QFutureInterfaceBase)
76 virtual ~QFutureInterfaceBase();
77
78 // reporting functions available to the engine author:
79 void reportStarted();
80 void reportFinished();
81 void reportCanceled();
82#ifndef QT_NO_EXCEPTIONS
83 void reportException(const QException &e);
84#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
85 void reportException(std::exception_ptr e);
86#else
87 void reportException(const std::exception_ptr &e);
88#endif
89#endif
90 void reportResultsReady(int beginIndex, int endIndex);
91
92 void setRunnable(QRunnable *runnable);
93 void setThreadPool(QThreadPool *pool);
94 QThreadPool *threadPool() const;
95 void setFilterMode(bool enable);
96 void setProgressRange(int minimum, int maximum);
97 int progressMinimum() const;
98 int progressMaximum() const;
99 bool isProgressUpdateNeeded() const;
100 void setProgressValue(int progressValue);
101 int progressValue() const;
102 void setProgressValueAndText(int progressValue, const QString &progressText);
103 QString progressText() const;
104
105 void setExpectedResultCount(int resultCount);
106 int expectedResultCount();
107 int resultCount() const;
108
109 bool queryState(State state) const;
110 bool isRunning() const;
111 bool isStarted() const;
112 bool isCanceled() const;
113 bool isFinished() const;
114#if QT_DEPRECATED_SINCE(6, 0)
115 QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.")
116 bool isPaused() const;
117
118 QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.")
119 void setPaused(bool paused) { setSuspended(paused); }
120
121 QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.")
122 void togglePaused() { toggleSuspended(); }
123#endif
124 bool isSuspending() const;
125 bool isSuspended() const;
126 bool isThrottled() const;
127 bool isResultReadyAt(int index) const;
128 bool isValid() const;
129 int loadState() const;
130
131 void cancel();
132 void cancelAndFinish() { cancel(CancelMode::CancelAndFinish); }
133 void cancelChain();
134 void setAddResultsIfCanceledEnabled(bool enable);
135 bool isAddResultsIfCanceledEnabled() const;
136
137 void setSuspended(bool suspend);
138 void toggleSuspended();
139 void reportSuspended() const;
140 void setThrottled(bool enable);
141
142 void waitForFinished();
143 bool waitForNextResult();
144 void waitForResult(int resultIndex);
145 void waitForResume();
146 void suspendIfRequested();
147
148 QMutex &mutex() const;
149 bool hasException() const;
150 QtPrivate::ExceptionStore &exceptionStore();
151 QtPrivate::ResultStoreBase &resultStoreBase();
152 const QtPrivate::ResultStoreBase &resultStoreBase() const;
153
154 inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; }
155 inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; }
156
157 // ### Qt 7: inline
158 void swap(QFutureInterfaceBase &other) noexcept;
159
160 template<typename T>
161 static QFutureInterfaceBase get(const QFuture<T> &future); // implemented in qfuture.h
162
163 bool isChainCanceled() const;
164
165protected:
166 // ### Qt 7: remove const from refT/derefT
167 bool refT() const noexcept;
168 bool derefT() const noexcept;
169 void reset();
170 void rethrowPossibleException();
171public:
172
173#ifndef QFUTURE_TEST
174private:
175#endif
176 friend class QFutureInterfaceBasePrivate;
177 QFutureInterfaceBasePrivate *d;
178
179private:
180 friend class QFutureWatcherBase;
181 friend class QFutureWatcherBasePrivate;
182
183 template<typename Function, typename ResultType, typename ParentResultType>
184 friend class QtPrivate::CompactContinuation;
185
186 template<class Function, class ResultType>
187 friend class QtPrivate::CanceledHandler;
188
189#ifndef QT_NO_EXCEPTIONS
190 template<class Function, class ResultType>
191 friend class QtPrivate::FailureHandler;
192#endif
193
194 friend struct QtPrivate::UnwrapHandler;
195
196#if QT_CORE_REMOVED_SINCE(6, 10)
197 friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
198 const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
199#endif // QT_CORE_REMOVED_SINCE(6, 10)
200
201 template<class T>
202 friend class QPromise;
203
204protected:
205 enum class ContinuationType : quint8
206 {
207 Unknown,
208 Then,
209 OnFailed,
210 OnCanceled,
211 };
212
213#if QT_CORE_REMOVED_SINCE(6, 10)
214 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func);
215 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
216 QFutureInterfaceBasePrivate *continuationFutureData);
217#endif // QT_CORE_REMOVED_SINCE(6, 10)
218 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
219 void *continuationFutureData, ContinuationType type);
220 void setContinuation(const QObject *context, std::function<void()> func,
221 const QVariant &continuationFuture, ContinuationType type);
222 void cleanContinuation();
223 void runContinuation() const;
224
225 void setLaunchAsync(bool value);
226 bool launchAsync() const;
227
228 bool isRunningOrPending() const;
229
230 enum class CancelMode { CancelOnly, CancelAndFinish };
231 void cancel(CancelMode mode);
232 void cancelChain(CancelMode mode);
233};
234
235inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
236{
237 lhs.swap(rhs);
238}
239
240template <typename T>
242{
243public:
244 QFutureInterface(State initialState = NoState)
245 : QFutureInterfaceBase(initialState)
246 {
247 refT();
248 }
250 : QFutureInterfaceBase(other)
251 {
252 refT();
253 }
254 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { refT(); }
255 QFutureInterface(QFutureInterfaceBase &&dd) noexcept : QFutureInterfaceBase(std::move(dd)) { refT(); }
257 {
258 QFutureInterface copy(other);
259 swap(copy);
260 return *this;
261 }
264
266 {
267 if (!derefT() && !hasException())
268 resultStoreBase().template clear<T>();
269 }
270
273
274 inline QFuture<T> future(); // implemented in qfuture.h
275
276 template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
277 inline bool reportAndEmplaceResult(int index, Args&&...args);
278 inline bool reportResult(const T *result, int index = -1);
279 inline bool reportAndMoveResult(T &&result, int index = -1);
280 inline bool reportResult(T &&result, int index = -1);
281 inline bool reportResult(const T &result, int index = -1);
282 inline bool reportResults(const QList<T> &results, int beginIndex = -1, int count = -1);
283 inline bool reportFinished(const T *result);
285 {
286 QFutureInterfaceBase::reportFinished();
287 QFutureInterfaceBase::runContinuation();
288 }
289
290 inline const T &resultReference(int index) const;
291 inline const T *resultPointer(int index) const;
292 inline QList<T> results();
293
295#if 0
296 // TODO: Enable and make it return a QList, when QList is fixed to support move-only types
298#endif
299
300#ifndef QT_NO_EXCEPTIONS
301 void reportException(const std::exception_ptr &e)
302 {
303 if (hasException())
304 return;
305
306 resultStoreBase().template clear<T>();
307 QFutureInterfaceBase::reportException(e);
308 }
309 void reportException(const QException &e)
310 {
311 if (hasException())
312 return;
313
314 resultStoreBase().template clear<T>();
315 QFutureInterfaceBase::reportException(e);
316 }
317#endif
318};
319
320template <typename T>
321inline bool QFutureInterface<T>::reportResult(const T *result, int index)
322{
323 QMutexLocker<QMutex> locker{&mutex()};
324 if ((this->queryState(Canceled) && !this->isAddResultsIfCanceledEnabled()) || this->queryState(Finished))
325 return false;
326
327 Q_ASSERT(!hasException());
328 QtPrivate::ResultStoreBase &store = resultStoreBase();
329
330 const int resultCountBefore = store.count();
331 const int insertIndex = store.addResult<T>(index, result);
332 if (insertIndex == -1)
333 return false;
334 if (store.filterMode()) {
335 this->reportResultsReady(resultCountBefore, store.count());
336 } else {
337 this->reportResultsReady(insertIndex, insertIndex + 1);
338 }
339 return true;
340}
341
342template<typename T>
343template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>>
344bool QFutureInterface<T>::reportAndEmplaceResult(int index, Args&&...args)
345{
346 QMutexLocker<QMutex> locker{&mutex()};
347 if ((queryState(Canceled) && !isAddResultsIfCanceledEnabled()) || queryState(Finished))
348 return false;
349
350 Q_ASSERT(!hasException());
351 QtPrivate::ResultStoreBase &store = resultStoreBase();
352
353 const int oldResultCount = store.count();
354 const int insertIndex = store.emplaceResult<T>(index, std::forward<Args>(args)...);
355 // Let's make sure it's not in pending results.
356 if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count()))
357 reportResultsReady(insertIndex, store.count());
358 return insertIndex != -1;
359}
360
361template<typename T>
362bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
363{
364 return reportAndEmplaceResult(index, std::move(result));
365}
366
367template<typename T>
368bool QFutureInterface<T>::reportResult(T &&result, int index)
369{
370 return reportAndMoveResult(std::move(result), index);
371}
372
373template <typename T>
374inline bool QFutureInterface<T>::reportResult(const T &result, int index)
375{
376 return reportResult(&result, index);
377}
378
379template<typename T>
380inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beginIndex, int count)
381{
382 QMutexLocker<QMutex> locker{&mutex()};
383 if ((this->queryState(Canceled) && !this->isAddResultsIfCanceledEnabled()) || this->queryState(Finished))
384 return false;
385
386 Q_ASSERT(!hasException());
387 auto &store = resultStoreBase();
388
389 const int resultCountBefore = store.count();
390 const int insertIndex = store.addResults(beginIndex, &_results, count);
391 if (insertIndex == -1)
392 return false;
393 if (store.filterMode()) {
394 this->reportResultsReady(resultCountBefore, store.count());
395 } else {
396 this->reportResultsReady(insertIndex, insertIndex + _results.size());
397 }
398 return true;
399}
400
401template <typename T>
402inline bool QFutureInterface<T>::reportFinished(const T *result)
403{
404 bool resultReported = false;
405 if (result)
406 resultReported = reportResult(result);
407 reportFinished();
408 return resultReported;
409}
410
411template <typename T>
412inline const T &QFutureInterface<T>::resultReference(int index) const
413{
414 Q_ASSERT(!hasException());
415
416 QMutexLocker<QMutex> locker{&mutex()};
417 return resultStoreBase().resultAt(index).template value<T>();
418}
419
420template <typename T>
421inline const T *QFutureInterface<T>::resultPointer(int index) const
422{
423 Q_ASSERT(!hasException());
424
425 QMutexLocker<QMutex> locker{&mutex()};
426 return resultStoreBase().resultAt(index).template pointer<T>();
427}
428
429template <typename T>
431{
432 if (this->isCanceled()) {
433 rethrowPossibleException();
434 return QList<T>();
435 }
436
437 QFutureInterfaceBase::waitForResult(-1);
438
439 QList<T> res;
440 QMutexLocker<QMutex> locker{&mutex()};
441
442 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
443 while (it != resultStoreBase().end()) {
444 res.append(it.value<T>());
445 ++it;
446 }
447
448 return res;
449}
450
451template<typename T>
453{
454 // Note: we wait for all, this is intentional,
455 // not to mess with other unready results.
456 waitForResult(-1);
457
458 Q_ASSERT(isValid());
459 Q_ASSERT(!hasException());
460
461 const QMutexLocker<QMutex> locker{&mutex()};
462 QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
463 T ret(std::move_if_noexcept(position.value<T>()));
464 reset();
465 resultStoreBase().template clear<T>();
466
467 return ret;
468}
469
470#if 0
471template<typename T>
472std::vector<T> QFutureInterface<T>::takeResults()
473{
474 waitForResult(-1);
475
476 Q_ASSERT(isValid());
477 Q_ASSERT(!hasException());
478
479 std::vector<T> res;
480 res.reserve(resultCount());
481
482 const QMutexLocker<QMutex> locker{&mutex()};
483
484 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
485 for (auto endIt = resultStoreBase().end(); it != endIt; ++it)
486 res.push_back(std::move_if_noexcept(it.value<T>()));
487
488 reset();
489 resultStoreBase().template clear<T>();
490
491 return res;
492}
493#endif
494
495QT_WARNING_PUSH
496QT_WARNING_DISABLE_CLANG("-Wweak-vtables") // QTBUG-125115
497
498template <>
499class QFutureInterface<void> : public QFutureInterfaceBase
500{
501public:
502 explicit QFutureInterface(State initialState = NoState)
503 : QFutureInterfaceBase(initialState)
504 { }
505
506 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { }
507
508 static QFutureInterface<void> canceledResult()
509 { return QFutureInterface(State(Started | Finished | Canceled)); }
510
511
512 inline QFuture<void> future(); // implemented in qfuture.h
513
514 bool reportResult(const void *, int) { return false; }
515 bool reportResults(const QList<void> &, int) { return false; }
516 bool reportFinished(const void *)
517 {
518 reportFinished();
519 return false;
520 }
521 void reportFinished()
522 {
523 QFutureInterfaceBase::reportFinished();
524 QFutureInterfaceBase::runContinuation();
525 }
526};
527
528QT_WARNING_POP // Clang -Wweak-vtables
529
530template<typename T>
531inline void swap(QFutureInterface<T> &a, QFutureInterface<T> &b) noexcept
532{
533 a.swap(b);
534}
535
536QT_END_NAMESPACE
537
538#endif // QFUTUREINTERFACE_H
QFutureInterface(QFutureInterface &&other)=default
bool reportAndEmplaceResult(int index, Args &&...args)
QFutureInterface(const QFutureInterfaceBase &dd)
bool reportResult(T &&result, int index=-1)
QFutureInterface & operator=(const QFutureInterface &other)
bool reportResults(const QList< T > &results, int beginIndex=-1, int count=-1)
const T * resultPointer(int index) const
QFutureInterface(State initialState=NoState)
bool reportResult(const T &result, int index=-1)
void reportException(const std::exception_ptr &e)
QFutureInterface(const QFutureInterface &other)
bool reportFinished(const T *result)
void reportException(const QException &e)
bool reportResult(const T *result, int index=-1)
bool reportAndMoveResult(T &&result, int index=-1)
QFutureInterface(QFutureInterfaceBase &&dd) noexcept
const T & resultReference(int index) const
\inmodule QtCore
Definition qrunnable.h:19
void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
QFuture< void > future
[5]