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
135 void setSuspended(bool suspend);
136 void toggleSuspended();
137 void reportSuspended() const;
138 void setThrottled(bool enable);
139
140 void waitForFinished();
141 bool waitForNextResult();
142 void waitForResult(int resultIndex);
143 void waitForResume();
144 void suspendIfRequested();
145
146 QMutex &mutex() const;
147 bool hasException() const;
148 QtPrivate::ExceptionStore &exceptionStore();
149 QtPrivate::ResultStoreBase &resultStoreBase();
150 const QtPrivate::ResultStoreBase &resultStoreBase() const;
151
152 inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; }
153 inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; }
154
155 // ### Qt 7: inline
156 void swap(QFutureInterfaceBase &other) noexcept;
157
158 template<typename T>
159 static QFutureInterfaceBase get(const QFuture<T> &future); // implemented in qfuture.h
160
161 bool isChainCanceled() const;
162
163protected:
164 // ### Qt 7: remove const from refT/derefT
165 bool refT() const noexcept;
166 bool derefT() const noexcept;
167 void reset();
168 void rethrowPossibleException();
169public:
170
171#ifndef QFUTURE_TEST
172private:
173#endif
174 friend class QFutureInterfaceBasePrivate;
175 QFutureInterfaceBasePrivate *d;
176
177private:
178 friend class QFutureWatcherBase;
179 friend class QFutureWatcherBasePrivate;
180
181 template<typename Function, typename ResultType, typename ParentResultType>
182 friend class QtPrivate::CompactContinuation;
183
184 template<class Function, class ResultType>
185 friend class QtPrivate::CanceledHandler;
186
187#ifndef QT_NO_EXCEPTIONS
188 template<class Function, class ResultType>
189 friend class QtPrivate::FailureHandler;
190#endif
191
192 friend struct QtPrivate::UnwrapHandler;
193
194#if QT_CORE_REMOVED_SINCE(6, 10)
195 friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
196 const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
197#endif // QT_CORE_REMOVED_SINCE(6, 10)
198
199 template<class T>
200 friend class QPromise;
201
202protected:
203 enum class ContinuationType : quint8
204 {
205 Unknown,
206 Then,
207 OnFailed,
208 OnCanceled,
209 };
210
211#if QT_CORE_REMOVED_SINCE(6, 10)
212 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func);
213 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
214 QFutureInterfaceBasePrivate *continuationFutureData);
215#endif // QT_CORE_REMOVED_SINCE(6, 10)
216 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
217 void *continuationFutureData, ContinuationType type);
218 void setContinuation(const QObject *context, std::function<void()> func,
219 const QVariant &continuationFuture, ContinuationType type);
220 void cleanContinuation();
221 void runContinuation() const;
222
223 void setLaunchAsync(bool value);
224 bool launchAsync() const;
225
226 bool isRunningOrPending() const;
227
228 enum class CancelMode { CancelOnly, CancelAndFinish };
229 void cancel(CancelMode mode);
230 void cancelChain(CancelMode mode);
231};
232
233inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
234{
235 lhs.swap(rhs);
236}
237
238template <typename T>
240{
241public:
242 QFutureInterface(State initialState = NoState)
243 : QFutureInterfaceBase(initialState)
244 {
245 refT();
246 }
248 : QFutureInterfaceBase(other)
249 {
250 refT();
251 }
252 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { refT(); }
253 QFutureInterface(QFutureInterfaceBase &&dd) noexcept : QFutureInterfaceBase(std::move(dd)) { refT(); }
255 {
256 QFutureInterface copy(other);
257 swap(copy);
258 return *this;
259 }
262
264 {
265 if (!derefT() && !hasException())
266 resultStoreBase().template clear<T>();
267 }
268
271
272 inline QFuture<T> future(); // implemented in qfuture.h
273
274 template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
275 inline bool reportAndEmplaceResult(int index, Args&&...args);
276 inline bool reportResult(const T *result, int index = -1);
277 inline bool reportAndMoveResult(T &&result, int index = -1);
278 inline bool reportResult(T &&result, int index = -1);
279 inline bool reportResult(const T &result, int index = -1);
280 inline bool reportResults(const QList<T> &results, int beginIndex = -1, int count = -1);
281 inline bool reportFinished(const T *result);
283 {
284 QFutureInterfaceBase::reportFinished();
285 QFutureInterfaceBase::runContinuation();
286 }
287
288 inline const T &resultReference(int index) const;
289 inline const T *resultPointer(int index) const;
290 inline QList<T> results();
291
293#if 0
294 // TODO: Enable and make it return a QList, when QList is fixed to support move-only types
296#endif
297
298#ifndef QT_NO_EXCEPTIONS
299 void reportException(const std::exception_ptr &e)
300 {
301 if (hasException())
302 return;
303
304 resultStoreBase().template clear<T>();
305 QFutureInterfaceBase::reportException(e);
306 }
307 void reportException(const QException &e)
308 {
309 if (hasException())
310 return;
311
312 resultStoreBase().template clear<T>();
313 QFutureInterfaceBase::reportException(e);
314 }
315#endif
316};
317
318template <typename T>
319inline bool QFutureInterface<T>::reportResult(const T *result, int index)
320{
321 QMutexLocker<QMutex> locker{&mutex()};
322 if (this->queryState(Canceled) || this->queryState(Finished))
323 return false;
324
325 Q_ASSERT(!hasException());
326 QtPrivate::ResultStoreBase &store = resultStoreBase();
327
328 const int resultCountBefore = store.count();
329 const int insertIndex = store.addResult<T>(index, result);
330 if (insertIndex == -1)
331 return false;
332 if (store.filterMode()) {
333 this->reportResultsReady(resultCountBefore, store.count());
334 } else {
335 this->reportResultsReady(insertIndex, insertIndex + 1);
336 }
337 return true;
338}
339
340template<typename T>
341template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>>
342bool QFutureInterface<T>::reportAndEmplaceResult(int index, Args&&...args)
343{
344 QMutexLocker<QMutex> locker{&mutex()};
345 if (queryState(Canceled) || queryState(Finished))
346 return false;
347
348 Q_ASSERT(!hasException());
349 QtPrivate::ResultStoreBase &store = resultStoreBase();
350
351 const int oldResultCount = store.count();
352 const int insertIndex = store.emplaceResult<T>(index, std::forward<Args>(args)...);
353 // Let's make sure it's not in pending results.
354 if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count()))
355 reportResultsReady(insertIndex, store.count());
356 return insertIndex != -1;
357}
358
359template<typename T>
360bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
361{
362 return reportAndEmplaceResult(index, std::move(result));
363}
364
365template<typename T>
366bool QFutureInterface<T>::reportResult(T &&result, int index)
367{
368 return reportAndMoveResult(std::move(result), index);
369}
370
371template <typename T>
372inline bool QFutureInterface<T>::reportResult(const T &result, int index)
373{
374 return reportResult(&result, index);
375}
376
377template<typename T>
378inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beginIndex, int count)
379{
380 QMutexLocker<QMutex> locker{&mutex()};
381 if (this->queryState(Canceled) || this->queryState(Finished))
382 return false;
383
384 Q_ASSERT(!hasException());
385 auto &store = resultStoreBase();
386
387 const int resultCountBefore = store.count();
388 const int insertIndex = store.addResults(beginIndex, &_results, count);
389 if (insertIndex == -1)
390 return false;
391 if (store.filterMode()) {
392 this->reportResultsReady(resultCountBefore, store.count());
393 } else {
394 this->reportResultsReady(insertIndex, insertIndex + _results.size());
395 }
396 return true;
397}
398
399template <typename T>
400inline bool QFutureInterface<T>::reportFinished(const T *result)
401{
402 bool resultReported = false;
403 if (result)
404 resultReported = reportResult(result);
405 reportFinished();
406 return resultReported;
407}
408
409template <typename T>
410inline const T &QFutureInterface<T>::resultReference(int index) const
411{
412 Q_ASSERT(!hasException());
413
414 QMutexLocker<QMutex> locker{&mutex()};
415 return resultStoreBase().resultAt(index).template value<T>();
416}
417
418template <typename T>
419inline const T *QFutureInterface<T>::resultPointer(int index) const
420{
421 Q_ASSERT(!hasException());
422
423 QMutexLocker<QMutex> locker{&mutex()};
424 return resultStoreBase().resultAt(index).template pointer<T>();
425}
426
427template <typename T>
429{
430 if (this->isCanceled()) {
431 rethrowPossibleException();
432 return QList<T>();
433 }
434
435 QFutureInterfaceBase::waitForResult(-1);
436
437 QList<T> res;
438 QMutexLocker<QMutex> locker{&mutex()};
439
440 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
441 while (it != resultStoreBase().end()) {
442 res.append(it.value<T>());
443 ++it;
444 }
445
446 return res;
447}
448
449template<typename T>
451{
452 // Note: we wait for all, this is intentional,
453 // not to mess with other unready results.
454 waitForResult(-1);
455
456 Q_ASSERT(isValid());
457 Q_ASSERT(!hasException());
458
459 const QMutexLocker<QMutex> locker{&mutex()};
460 QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
461 T ret(std::move_if_noexcept(position.value<T>()));
462 reset();
463 resultStoreBase().template clear<T>();
464
465 return ret;
466}
467
468#if 0
469template<typename T>
470std::vector<T> QFutureInterface<T>::takeResults()
471{
472 waitForResult(-1);
473
474 Q_ASSERT(isValid());
475 Q_ASSERT(!hasException());
476
477 std::vector<T> res;
478 res.reserve(resultCount());
479
480 const QMutexLocker<QMutex> locker{&mutex()};
481
482 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
483 for (auto endIt = resultStoreBase().end(); it != endIt; ++it)
484 res.push_back(std::move_if_noexcept(it.value<T>()));
485
486 reset();
487 resultStoreBase().template clear<T>();
488
489 return res;
490}
491#endif
492
493QT_WARNING_PUSH
494QT_WARNING_DISABLE_CLANG("-Wweak-vtables") // QTBUG-125115
495
496template <>
497class QFutureInterface<void> : public QFutureInterfaceBase
498{
499public:
500 explicit QFutureInterface(State initialState = NoState)
501 : QFutureInterfaceBase(initialState)
502 { }
503
504 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { }
505
506 static QFutureInterface<void> canceledResult()
507 { return QFutureInterface(State(Started | Finished | Canceled)); }
508
509
510 inline QFuture<void> future(); // implemented in qfuture.h
511
512 bool reportResult(const void *, int) { return false; }
513 bool reportResults(const QList<void> &, int) { return false; }
514 bool reportFinished(const void *)
515 {
516 reportFinished();
517 return false;
518 }
519 void reportFinished()
520 {
521 QFutureInterfaceBase::reportFinished();
522 QFutureInterfaceBase::runContinuation();
523 }
524};
525
526QT_WARNING_POP // Clang -Wweak-vtables
527
528template<typename T>
529inline void swap(QFutureInterface<T> &a, QFutureInterface<T> &b) noexcept
530{
531 a.swap(b);
532}
533
534QT_END_NAMESPACE
535
536#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]