1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QFUTUREINTERFACE_H
41#define QFUTUREINTERFACE_H
42
43#include <QtCore/qmutex.h>
44#include <QtCore/QMutexLocker>
45#include <QtCore/qresultstore.h>
46#ifndef QT_NO_EXCEPTIONS
47#include <exception>
48#endif
49
50#include <utility>
51
52QT_REQUIRE_CONFIG(future);
53
54QT_FORWARD_DECLARE_CLASS(QRunnable)
55QT_FORWARD_DECLARE_CLASS(QException)
56QT_BEGIN_NAMESPACE
57
58
59template <typename T> class QFuture;
60class QThreadPool;
61class QFutureInterfaceBasePrivate;
62class QFutureWatcherBase;
63class QFutureWatcherBasePrivate;
64
65namespace QtPrivate {
66template<typename Function, typename ResultType, typename ParentResultType>
67class Continuation;
68
69class ExceptionStore;
70
71template<class Function, class ResultType>
72class CanceledHandler;
73
74#ifndef QT_NO_EXCEPTIONS
75template<class Function, class ResultType>
76class FailureHandler;
77#endif
78}
79
80class Q_CORE_EXPORT QFutureInterfaceBase
81{
82public:
83 enum State {
84 NoState = 0x00,
85 Running = 0x01,
86 Started = 0x02,
87 Finished = 0x04,
88 Canceled = 0x08,
89 Suspending = 0x10,
90 Suspended = 0x20,
91 Throttled = 0x40,
92 // Pending means that the future depends on another one, which is not finished yet
93 Pending = 0x80,
94 };
95
96 QFutureInterfaceBase(State initialState = NoState);
97 QFutureInterfaceBase(const QFutureInterfaceBase &other);
98 virtual ~QFutureInterfaceBase();
99
100 // reporting functions available to the engine author:
101 void reportStarted();
102 void reportFinished();
103 void reportCanceled();
104#ifndef QT_NO_EXCEPTIONS
105 void reportException(const QException &e);
106 void reportException(std::exception_ptr e);
107#endif
108 void reportResultsReady(int beginIndex, int endIndex);
109
110 void setRunnable(QRunnable *runnable);
111 void setThreadPool(QThreadPool *pool);
112 QThreadPool *threadPool() const;
113 void setFilterMode(bool enable);
114 void setProgressRange(int minimum, int maximum);
115 int progressMinimum() const;
116 int progressMaximum() const;
117 bool isProgressUpdateNeeded() const;
118 void setProgressValue(int progressValue);
119 int progressValue() const;
120 void setProgressValueAndText(int progressValue, const QString &progressText);
121 QString progressText() const;
122
123 void setExpectedResultCount(int resultCount);
124 int expectedResultCount();
125 int resultCount() const;
126
127 bool queryState(State state) const;
128 bool isRunning() const;
129 bool isStarted() const;
130 bool isCanceled() const;
131 bool isFinished() const;
132#if QT_DEPRECATED_SINCE(6, 0)
133 QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.")
134 bool isPaused() const;
135
136 QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.")
137 void setPaused(bool paused) { setSuspended(paused); }
138
139 QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.")
140 void togglePaused() { toggleSuspended(); }
141#endif
142 bool isSuspending() const;
143 bool isSuspended() const;
144 bool isThrottled() const;
145 bool isResultReadyAt(int index) const;
146 bool isValid() const;
147 int loadState() const;
148
149 void cancel();
150 void setSuspended(bool suspend);
151 void toggleSuspended();
152 void reportSuspended() const;
153 void setThrottled(bool enable);
154
155 void waitForFinished();
156 bool waitForNextResult();
157 void waitForResult(int resultIndex);
158 void waitForResume();
159 void suspendIfRequested();
160
161 QMutex &mutex() const;
162 QtPrivate::ExceptionStore &exceptionStore();
163 QtPrivate::ResultStoreBase &resultStoreBase();
164 const QtPrivate::ResultStoreBase &resultStoreBase() const;
165
166 inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; }
167 inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; }
168 QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other);
169
170 void swap(QFutureInterfaceBase &other) noexcept;
171
172protected:
173 bool refT() const;
174 bool derefT() const;
175 void reset();
176 void rethrowPossibleException();
177public:
178
179#ifndef QFUTURE_TEST
180private:
181#endif
182 QFutureInterfaceBasePrivate *d;
183
184private:
185 friend class QFutureWatcherBase;
186 friend class QFutureWatcherBasePrivate;
187
188 template<typename Function, typename ResultType, typename ParentResultType>
189 friend class QtPrivate::Continuation;
190
191 template<class Function, class ResultType>
192 friend class QtPrivate::CanceledHandler;
193
194#ifndef QT_NO_EXCEPTIONS
195 template<class Function, class ResultType>
196 friend class QtPrivate::FailureHandler;
197#endif
198
199protected:
200 void setContinuation(std::function<void(const QFutureInterfaceBase &)> func);
201 void runContinuation() const;
202
203 void setLaunchAsync(bool value);
204 bool launchAsync() const;
205
206 bool isRunningOrPending() const;
207};
208
209template <typename T>
210class QFutureInterface : public QFutureInterfaceBase
211{
212public:
213 QFutureInterface(State initialState = NoState)
214 : QFutureInterfaceBase(initialState)
215 {
216 refT();
217 }
218 QFutureInterface(const QFutureInterface &other)
219 : QFutureInterfaceBase(other)
220 {
221 refT();
222 }
223 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { refT(); }
224 ~QFutureInterface()
225 {
226 if (!derefT())
227 resultStoreBase().template clear<T>();
228 }
229
230 static QFutureInterface canceledResult()
231 { return QFutureInterface(State(Started | Finished | Canceled)); }
232
233 QFutureInterface &operator=(const QFutureInterface &other)
234 {
235 other.refT();
236 if (!derefT())
237 resultStoreBase().template clear<T>();
238 QFutureInterfaceBase::operator=(other);
239 return *this;
240 }
241
242 inline QFuture<T> future(); // implemented in qfuture.h
243
244 inline bool reportResult(const T *result, int index = -1);
245 inline bool reportAndMoveResult(T &&result, int index = -1);
246 inline bool reportResult(T &&result, int index = -1);
247 inline bool reportResult(const T &result, int index = -1);
248 inline bool reportResults(const QList<T> &results, int beginIndex = -1, int count = -1);
249 inline bool reportFinished(const T *result);
250 void reportFinished()
251 {
252 QFutureInterfaceBase::reportFinished();
253 QFutureInterfaceBase::runContinuation();
254 }
255
256 inline const T &resultReference(int index) const;
257 inline const T *resultPointer(int index) const;
258 inline QList<T> results();
259
260 T takeResult();
261#if 0
262 // TODO: Enable and make it return a QList, when QList is fixed to support move-only types
263 std::vector<T> takeResults();
264#endif
265};
266
267template <typename T>
268inline bool QFutureInterface<T>::reportResult(const T *result, int index)
269{
270 QMutexLocker<QMutex> locker{&mutex()};
271 if (this->queryState(Canceled) || this->queryState(Finished))
272 return false;
273
274 QtPrivate::ResultStoreBase &store = resultStoreBase();
275
276 const int resultCountBefore = store.count();
277 const int insertIndex = store.addResult<T>(index, result);
278 if (insertIndex == -1)
279 return false;
280 if (store.filterMode()) {
281 this->reportResultsReady(resultCountBefore, store.count());
282 } else {
283 this->reportResultsReady(insertIndex, insertIndex + 1);
284 }
285 return true;
286}
287
288template<typename T>
289bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
290{
291 QMutexLocker<QMutex> locker{&mutex()};
292 if (queryState(Canceled) || queryState(Finished))
293 return false;
294
295 QtPrivate::ResultStoreBase &store = resultStoreBase();
296
297 const int oldResultCount = store.count();
298 const int insertIndex = store.moveResult(index, std::forward<T>(result));
299 // Let's make sure it's not in pending results.
300 if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count()))
301 reportResultsReady(insertIndex, store.count());
302 return insertIndex != -1;
303}
304
305template<typename T>
306bool QFutureInterface<T>::reportResult(T &&result, int index)
307{
308 return reportAndMoveResult(std::move(result), index);
309}
310
311template <typename T>
312inline bool QFutureInterface<T>::reportResult(const T &result, int index)
313{
314 return reportResult(&result, index);
315}
316
317template<typename T>
318inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beginIndex, int count)
319{
320 QMutexLocker<QMutex> locker{&mutex()};
321 if (this->queryState(Canceled) || this->queryState(Finished))
322 return false;
323
324 auto &store = resultStoreBase();
325
326 const int resultCountBefore = store.count();
327 const int insertIndex = store.addResults(beginIndex, &_results, count);
328 if (insertIndex == -1)
329 return false;
330 if (store.filterMode()) {
331 this->reportResultsReady(resultCountBefore, store.count());
332 } else {
333 this->reportResultsReady(insertIndex, insertIndex + _results.count());
334 }
335 return true;
336}
337
338template <typename T>
339inline bool QFutureInterface<T>::reportFinished(const T *result)
340{
341 bool resultReported = false;
342 if (result)
343 resultReported = reportResult(result);
344 reportFinished();
345 return resultReported;
346}
347
348template <typename T>
349inline const T &QFutureInterface<T>::resultReference(int index) const
350{
351 QMutexLocker<QMutex> locker{&mutex()};
352 return resultStoreBase().resultAt(index).template value<T>();
353}
354
355template <typename T>
356inline const T *QFutureInterface<T>::resultPointer(int index) const
357{
358 QMutexLocker<QMutex> locker{&mutex()};
359 return resultStoreBase().resultAt(index).template pointer<T>();
360}
361
362template <typename T>
363inline QList<T> QFutureInterface<T>::results()
364{
365 if (this->isCanceled()) {
366 rethrowPossibleException();
367 return QList<T>();
368 }
369
370 QFutureInterfaceBase::waitForResult(-1);
371
372 QList<T> res;
373 QMutexLocker<QMutex> locker{&mutex()};
374
375 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
376 while (it != resultStoreBase().end()) {
377 res.append(it.value<T>());
378 ++it;
379 }
380
381 return res;
382}
383
384template<typename T>
385T QFutureInterface<T>::takeResult()
386{
387 Q_ASSERT(isValid());
388
389 // Note: we wait for all, this is intentional,
390 // not to mess with other unready results.
391 waitForResult(-1);
392
393 const QMutexLocker<QMutex> locker{&mutex()};
394 QtPrivate::ResultIteratorBase position = resultStoreBase().resultAt(0);
395 T ret(std::move_if_noexcept(position.value<T>()));
396 reset();
397 resultStoreBase().template clear<T>();
398
399 return ret;
400}
401
402#if 0
403template<typename T>
404std::vector<T> QFutureInterface<T>::takeResults()
405{
406 Q_ASSERT(isValid());
407
408 waitForResult(-1);
409 std::vector<T> res;
410 res.reserve(resultCount());
411
412 const QMutexLocker<QMutex> locker{&mutex()};
413
414 QtPrivate::ResultIteratorBase it = resultStoreBase().begin();
415 for (auto endIt = resultStoreBase().end(); it != endIt; ++it)
416 res.push_back(std::move_if_noexcept(it.value<T>()));
417
418 reset();
419 resultStoreBase().template clear<T>();
420
421 return res;
422}
423#endif
424
425template <>
426class QFutureInterface<void> : public QFutureInterfaceBase
427{
428public:
429 explicit QFutureInterface<void>(State initialState = NoState)
430 : QFutureInterfaceBase(initialState)
431 { }
432
433 QFutureInterface(const QFutureInterfaceBase &dd) : QFutureInterfaceBase(dd) { }
434
435 static QFutureInterface<void> canceledResult()
436 { return QFutureInterface(State(Started | Finished | Canceled)); }
437
438
439 inline QFuture<void> future(); // implemented in qfuture.h
440
441 bool reportResult(const void *, int) { return false; }
442 bool reportResults(const QList<void> &, int) { return false; }
443 bool reportFinished(const void *)
444 {
445 reportFinished();
446 return false;
447 }
448 void reportFinished()
449 {
450 QFutureInterfaceBase::reportFinished();
451 QFutureInterfaceBase::runContinuation();
452 }
453};
454
455template<typename T>
456inline void swap(QFutureInterface<T> &a, QFutureInterface<T> &b) noexcept
457{
458 a.swap(b);
459}
460
461QT_END_NAMESPACE
462
463#endif // QFUTUREINTERFACE_H
464