summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qfuture.h
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2020-02-27 17:30:07 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2020-03-05 13:24:32 +0100
commitdfaca09e85a49d2983bb89893bfbe1ba4c19eab4 (patch)
treec01c0acca4e8c183b555876d203fb4faa261d893 /src/corelib/thread/qfuture.h
parent1057d568bb921e378b9fc5eb6c95b39dd6dc94fa (diff)
Add support for attaching continuations to QFuture
Added QFuture::then() methods to allow chaining multiple asynchronous computations. Continuations can use the following execution policies: * QtFuture::Launch::Sync - the continuation will be launched in the same thread in which the parent has been executing. * QtFuture::Launch::Async - the continuation will be launched in a new thread. * QtFuture::Launch::Inherit - the continuation will inherit the launch policy of the parent, or its thread pool (if it was using a custom one). * Additionally then() also accepts a custom QThreadPool* instance. Note, that if the parent future gets canceled, its continuation(s) will be also canceled. If the parent throws an exception, it will be propagated to the continuation's future, unless it is caught inside the continuation (if it has a QFuture arg). Some example usages: QFuture<int> future = ...; future.then([](int res1){ ... }).then([](int res2){ ... })... QFuture<int> future = ...; future.then([](QFuture<int> fut1){ /* do something with fut1 */ })... In the examples above all continuations will run in the same thread as future. QFuture<int> future = ...; future.then(QtFuture::Launch::Async, [](int res1){ ... }) .then([](int res2){ ... }).. In this example the continuations will run in a new thread (but on the same one). QThreadPool pool; QFuture<int> future = ...; future.then(&pool, [](int res1){ ... }) .then([](int res2){ ... }).. In this example the continuations will run in the given thread pool. [ChangeLog][QtCore] Added support for attaching continuations to QFuture. Task-number: QTBUG-81587 Change-Id: I5b2e176694f7ae8ce00404aca725e9a170818955 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/corelib/thread/qfuture.h')
-rw-r--r--src/corelib/thread/qfuture.h86
1 files changed, 85 insertions, 1 deletions
diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h
index d3135510b3e..e103cfb5526 100644
--- a/src/corelib/thread/qfuture.h
+++ b/src/corelib/thread/qfuture.h
@@ -45,11 +45,12 @@
#include <QtCore/qfutureinterface.h>
#include <QtCore/qstring.h>
+#include <QtCore/qfuture_impl.h>
+
QT_REQUIRE_CONFIG(future);
QT_BEGIN_NAMESPACE
-
template <typename T>
class QFutureWatcher;
template <>
@@ -101,6 +102,18 @@ public:
operator T() const { return result(); }
QList<T> results() const { return d.results(); }
+ template<class Function>
+ using ResultType = typename QtPrivate::ResultTypeHelper<Function, T>::ResultType;
+
+ template<class Function>
+ QFuture<ResultType<Function>> then(Function &&function);
+
+ template<class Function>
+ QFuture<ResultType<Function>> then(QtFuture::Launch policy, Function &&function);
+
+ template<class Function>
+ QFuture<ResultType<Function>> then(QThreadPool *pool, Function &&function);
+
class const_iterator
{
public:
@@ -199,6 +212,7 @@ private:
friend class QFutureWatcher<T>;
public: // Warning: the d pointer is not documented and is considered private.
+ // TODO: make this private
mutable QFutureInterface<T> d;
};
@@ -222,6 +236,35 @@ inline QFuture<T> QFutureInterface<T>::future()
return QFuture<T>(this);
}
+template<class T>
+template<class Function>
+QFuture<typename QFuture<T>::template ResultType<Function>> QFuture<T>::then(Function &&function)
+{
+ return then(QtFuture::Launch::Sync, std::forward<Function>(function));
+}
+
+template<class T>
+template<class Function>
+QFuture<typename QFuture<T>::template ResultType<Function>>
+QFuture<T>::then(QtFuture::Launch policy, Function &&function)
+{
+ QFutureInterface<ResultType<Function>> promise(QFutureInterfaceBase::State::Pending);
+ QtPrivate::Continuation<Function, ResultType<Function>, T>::create(
+ std::forward<Function>(function), this, promise, policy);
+ return promise.future();
+}
+
+template<class T>
+template<class Function>
+QFuture<typename QFuture<T>::template ResultType<Function>> QFuture<T>::then(QThreadPool *pool,
+ Function &&function)
+{
+ QFutureInterface<ResultType<Function>> promise(QFutureInterfaceBase::State::Pending);
+ QtPrivate::Continuation<Function, ResultType<Function>, T>::create(
+ std::forward<Function>(function), this, promise, pool);
+ return promise.future();
+}
+
Q_DECLARE_SEQUENTIAL_ITERATOR(Future)
template <>
@@ -272,6 +315,18 @@ public:
QString progressText() const { return d.progressText(); }
void waitForFinished() { d.waitForFinished(); }
+ template<class Function>
+ using ResultType = typename QtPrivate::ResultTypeHelper<Function, void>::ResultType;
+
+ template<class Function>
+ QFuture<ResultType<Function>> then(Function &&function);
+
+ template<class Function>
+ QFuture<ResultType<Function>> then(QtFuture::Launch policy, Function &&function);
+
+ template<class Function>
+ QFuture<ResultType<Function>> then(QThreadPool *pool, Function &&function);
+
private:
friend class QFutureWatcher<void>;
@@ -279,6 +334,9 @@ private:
public:
#endif
mutable QFutureInterfaceBase d;
+
+ template<typename Function, typename ResultType, typename ParentResultType>
+ friend class QtPrivate::Continuation;
};
inline QFuture<void> QFutureInterface<void>::future()
@@ -292,6 +350,32 @@ QFuture<void> qToVoidFuture(const QFuture<T> &future)
return QFuture<void>(future.d);
}
+template<class Function>
+QFuture<QFuture<void>::ResultType<Function>> QFuture<void>::then(Function &&function)
+{
+ return then(QtFuture::Launch::Sync, std::forward<Function>(function));
+}
+
+template<class Function>
+QFuture<QFuture<void>::ResultType<Function>> QFuture<void>::then(QtFuture::Launch policy,
+ Function &&function)
+{
+ QFutureInterface<ResultType<Function>> promise(QFutureInterfaceBase::State::Pending);
+ QtPrivate::Continuation<Function, ResultType<Function>, void>::create(
+ std::forward<Function>(function), this, promise, policy);
+ return promise.future();
+}
+
+template<class Function>
+QFuture<QFuture<void>::ResultType<Function>> QFuture<void>::then(QThreadPool *pool,
+ Function &&function)
+{
+ QFutureInterface<ResultType<Function>> promise(QFutureInterfaceBase::State::Pending);
+ QtPrivate::Continuation<Function, ResultType<Function>, void>::create(
+ std::forward<Function>(function), this, promise, pool);
+ return promise.future();
+}
+
QT_END_NAMESPACE
#endif // QFUTURE_H