summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2023-03-20 16:11:15 +0100
committerIvan Solovev <ivan.solovev@qt.io>2023-04-05 13:38:15 +0200
commit9b4b32ec98bf80023d2233a061564dfe59b783c7 (patch)
tree42ea1e44c26e9ba38e52b9b159dbfd6d8fddd288
parent7f38f9f394b7283de93a2367765572241dede84b (diff)
Long live QtFuture::makeReadyVoidFuture() and QtFuture::makeReadyValueFuture()
[ChangeLog][QtCore][QFuture] Added QtFuture::makeReadyVoidFuture() and QtFuture::makeReadyValueFuture(). Basically, these methods behave like QtFuture::makeReadyFuture(), but QtFuture::makeReadyValueFuture() does not have a "const QList<T> &" specialization returning QFuture<T> instead of QFuture<QList<T>>, which allows it to always behave consistently. This patch also introduces usage of the new methods around qtbase. Task-number: QTBUG-109677 Change-Id: I89df8b26d82c192baad69efb5df517a8b182995f Reviewed-by: Marc Mutz <marc.mutz@qt.io>
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp20
-rw-r--r--src/corelib/platform/android/qandroidextras.cpp6
-rw-r--r--src/corelib/thread/qfuture.h10
-rw-r--r--src/corelib/thread/qfuture.qdoc64
-rw-r--r--src/corelib/thread/qfuture_impl.h27
-rw-r--r--src/corelib/thread/qfutureinterface.cpp13
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp39
-rw-r--r--tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp18
8 files changed, 147 insertions, 50 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp
index 494719d988..ea104ec1a9 100644
--- a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp
@@ -239,9 +239,9 @@ auto future = QtConcurrent::run([] {
//! [20]
QObject *context = ...;
-auto future = cachedResultsReady ? QtFuture::makeReadyFuture(results)
- : QtConcurrent::run([] { /* compute results */});
-auto continuation = future.then(context, [] (Results results) {
+auto future = cachedResultsReady ? QtFuture::makeReadyValueFuture(result)
+ : QtConcurrent::run([] { /* compute result */});
+auto continuation = future.then(context, [] (Result result) {
// Runs in the context's thread
}).then([] {
// May or may not run in the context's thread
@@ -413,3 +413,17 @@ auto f = QtFuture::makeReadyRangeFuture({1, 2, 3});
const int count = f.resultCount(); // count == 3
const auto results = f.results(); // results == { 1, 2, 3 }
//! [34]
+
+//! [35]
+auto f = QtFuture::makeReadyValueFuture(std::make_unique<int>(42));
+...
+const int result = *f.takeResult(); // result == 42
+//! [35]
+
+//! [36]
+auto f = QtFuture::makeReadyVoidFuture();
+...
+const bool started = f.isStarted(); // started == true
+const bool running = f.isRunning(); // running == false
+const bool finished = f.isFinished(); // finished == true
+//! [36]
diff --git a/src/corelib/platform/android/qandroidextras.cpp b/src/corelib/platform/android/qandroidextras.cpp
index b7c07a8f03..85f8a7e808 100644
--- a/src/corelib/platform/android/qandroidextras.cpp
+++ b/src/corelib/platform/android/qandroidextras.cpp
@@ -1095,7 +1095,7 @@ requestPermissionsInternal(const QStringList &permissions)
}
if (!QtAndroidPrivate::acquireAndroidDeadlockProtector())
- return QtFuture::makeReadyFuture(QtAndroidPrivate::Denied);
+ return QtFuture::makeReadyValueFuture(QtAndroidPrivate::Denied);
QSharedPointer<QPromise<QtAndroidPrivate::PermissionResult>> promise;
promise.reset(new QPromise<QtAndroidPrivate::PermissionResult>());
@@ -1145,7 +1145,7 @@ QtAndroidPrivate::requestPermissions(const QStringList &permissions)
{
// avoid the uneccessary call and response to an empty permission string
if (permissions.isEmpty())
- return QtFuture::makeReadyFuture(QtAndroidPrivate::Denied);
+ return QtFuture::makeReadyValueFuture(QtAndroidPrivate::Denied);
return requestPermissionsInternal(permissions);
}
@@ -1168,7 +1168,7 @@ QtAndroidPrivate::checkPermission(const QString &permission)
QJniObject::fromString(permission).object());
result = resultFromAndroid(res);
}
- return QtFuture::makeReadyFuture(result);
+ return QtFuture::makeReadyValueFuture(result);
}
bool QtAndroidPrivate::registerPermissionNatives()
diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h
index 34fb8a039d..219d3368f0 100644
--- a/src/corelib/thread/qfuture.h
+++ b/src/corelib/thread/qfuture.h
@@ -522,6 +522,16 @@ QFuture<std::variant<std::decay_t<Futures>...>> whenAny(Futures &&... futures);
#endif // Q_QDOC
+#if defined(Q_QDOC)
+static QFuture<void> makeReadyFuture()
+#else
+template<typename T = void>
+static QFuture<T> makeReadyFuture()
+#endif
+{
+ return makeReadyVoidFuture();
+}
+
} // namespace QtFuture
Q_DECLARE_SEQUENTIAL_ITERATOR(Future)
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 7ba4debeea..e9aabdda2d 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -118,15 +118,16 @@
combine several futures and track when the last or first of them completes.
A ready QFuture object with a value or a QFuture object holding exception can
- be created using convenience functions QtFuture::makeReadyFuture(),
- QtFuture::makeReadyRangeFuture(), and QtFuture::makeExceptionalFuture().
+ be created using convenience functions QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(), and
+ QtFuture::makeExceptionalFuture().
\note To start a computation and store results in a QFuture, use QPromise or
one of the APIs in the \l {Qt Concurrent} framework.
- \sa QPromise, QtFuture::connect(), QtFuture::makeReadyFuture(),
- QtFuture::makeReadyRangeFuture(), QtFuture::makeExceptionalFuture(),
- QFutureWatcher, {Qt Concurrent}
+ \sa QPromise, QtFuture::connect(), QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture(), QFutureWatcher, {Qt Concurrent}
*/
/*! \fn template <typename T> QFuture<T>::QFuture()
@@ -982,7 +983,9 @@
const int result = *f.takeResult(); // result == 42
\endcode
- \sa QFuture, QtFuture::makeExceptionalFuture()
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
*/
/*! \fn QFuture<void> QtFuture::makeReadyFuture()
@@ -1003,7 +1006,9 @@
\endcode
\sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
- QFuture::isFinished(), QtFuture::makeExceptionalFuture()
+ QFuture::isFinished(), QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeReadyFuture(const QList<T> &values)
@@ -1021,7 +1026,38 @@
const auto results = f.results(); // results == { 1, 2, 3 }
\endcode
- \sa QFuture, QtFuture::makeExceptionalFuture()
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn template<typename T> static QFuture<std::decay_t<T>> QtFuture::makeReadyValueFuture(T &&value)
+
+ \since 6.6
+
+ Creates and returns a QFuture which already has a result \a value.
+ The returned QFuture has a type of std::decay_t<T>, where T is not void.
+ The returned QFuture will already be in the finished state.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 35
+
+ \sa QFuture, QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeReadyVoidFuture(), QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn QFuture<void> QtFuture::makeReadyVoidFuture()
+
+ \since 6.6
+
+ Creates and returns a void QFuture. Such QFuture can't store any result.
+ One can use it to query the state of the computation.
+ The returned QFuture will already be in the finished state.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 36
+
+ \sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
+ QFuture::isFinished(), QtFuture::makeReadyValueFuture(),
+ QtFuture::makeReadyRangeFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(const QException &exception)
@@ -1041,7 +1077,8 @@
}
\endcode
- \sa QFuture, QException, QtFuture::makeReadyFuture()
+ \sa QFuture, QException, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(std::exception_ptr exception)
@@ -1066,7 +1103,8 @@
}
\endcode
- \sa QFuture, QException, QtFuture::makeReadyFuture()
+ \sa QFuture, QException, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture()
*/
/*! \fn template<typename Container, QtFuture::if_container_with_input_iterators<Container>> static QFuture<QtFuture::ContainedType<Container>> QtFuture::makeReadyRangeFuture(Container &&container)
@@ -1085,7 +1123,8 @@
\dots
\snippet code/src_corelib_thread_qfuture.cpp 34
- \sa QFuture, QtFuture::makeReadyFuture(), QtFuture::makeExceptionalFuture()
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename ValueType> static QFuture<ValueType> QtFuture::makeReadyRangeFuture(std::initializer_list<ValueType> values)
@@ -1100,7 +1139,8 @@
\dots
\snippet code/src_corelib_thread_qfuture.cpp 34
- \sa QFuture, QtFuture::makeReadyFuture(), QtFuture::makeExceptionalFuture()
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(Function &&function)
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 5ed7a4d27f..b282903405 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -996,8 +996,8 @@ static QFuture<ValueType> makeReadyRangeFuture(std::initializer_list<ValueType>
return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{values});
}
-template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
-static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
+template<typename T>
+static QFuture<std::decay_t<T>> makeReadyValueFuture(T &&value)
{
QFutureInterface<std::decay_t<T>> promise;
promise.reportStarted();
@@ -1007,20 +1007,17 @@ static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
return promise.future();
}
-#if defined(Q_QDOC)
-static QFuture<void> makeReadyFuture()
-#else
-template<typename T = void>
-static QFuture<T> makeReadyFuture()
-#endif
-{
- QFutureInterface<T> promise;
- promise.reportStarted();
- promise.reportFinished();
+Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
- return promise.future();
+template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
+static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
+{
+ return makeReadyValueFuture(std::forward<T>(value));
}
+// the void specialization is moved to the end of qfuture.h, because it now
+// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
+
template<typename T>
static QFuture<T> makeReadyFuture(const QList<T> &values)
{
@@ -1127,7 +1124,7 @@ QFuture<OutputSequence> whenAllImpl(InputIt first, InputIt last)
{
const qsizetype size = std::distance(first, last);
if (size == 0)
- return QtFuture::makeReadyFuture(OutputSequence());
+ return QtFuture::makeReadyValueFuture(OutputSequence());
const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
context->futures.resize(size);
@@ -1166,7 +1163,7 @@ QFuture<QtFuture::WhenAnyResult<typename Future<ValueType>::type>> whenAnyImpl(I
const qsizetype size = std::distance(first, last);
if (size == 0) {
- return QtFuture::makeReadyFuture(
+ return QtFuture::makeReadyValueFuture(
QtFuture::WhenAnyResult { qsizetype(-1), QFuture<PackagedType>() });
}
diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp
index e656527e04..790963547c 100644
--- a/src/corelib/thread/qfutureinterface.cpp
+++ b/src/corelib/thread/qfutureinterface.cpp
@@ -889,4 +889,17 @@ bool QFutureInterfaceBase::launchAsync() const
return d->launchAsync;
}
+namespace QtFuture {
+
+QFuture<void> makeReadyVoidFuture()
+{
+ QFutureInterface<void> promise;
+ promise.reportStarted();
+ promise.reportFinished();
+
+ return promise.future();
+}
+
+} // namespace QtFuture
+
QT_END_NAMESPACE
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index f457ba4668..bb78898836 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -3052,7 +3052,7 @@ void tst_QFuture::cancelContinuations()
// The chain is cancelled before the execution of continuations
{
- auto f = QtFuture::makeReadyFuture(42);
+ auto f = QtFuture::makeReadyValueFuture(42);
f.cancel();
int checkpoint = 0;
@@ -3301,7 +3301,8 @@ void tst_QFuture::continuationsWithMoveOnlyLambda()
// .then()
{
std::unique_ptr<int> uniquePtr(new int(42));
- auto future = QtFuture::makeReadyFuture().then([p = std::move(uniquePtr)] { return *p; });
+ auto future = QtFuture::makeReadyVoidFuture()
+ .then([p = std::move(uniquePtr)] { return *p; });
QCOMPARE(future.result(), 42);
}
// .then() with thread pool
@@ -3309,8 +3310,8 @@ void tst_QFuture::continuationsWithMoveOnlyLambda()
QThreadPool pool;
std::unique_ptr<int> uniquePtr(new int(42));
- auto future =
- QtFuture::makeReadyFuture().then(&pool, [p = std::move(uniquePtr)] { return *p; });
+ auto future = QtFuture::makeReadyVoidFuture()
+ .then(&pool, [p = std::move(uniquePtr)] { return *p; });
QCOMPARE(future.result(), 42);
}
// .then() with context
@@ -3318,8 +3319,8 @@ void tst_QFuture::continuationsWithMoveOnlyLambda()
QObject object;
std::unique_ptr<int> uniquePtr(new int(42));
- auto future = QtFuture::makeReadyFuture().then(&object,
- [p = std::move(uniquePtr)] { return *p; });
+ auto future = QtFuture::makeReadyVoidFuture()
+ .then(&object, [p = std::move(uniquePtr)] { return *p; });
QCOMPARE(future.result(), 42);
}
@@ -4113,6 +4114,28 @@ void tst_QFuture::createReadyFutures()
QCOMPARE(f.results(), values);
}
+ // test makeReadyValueFuture<T>()
+ {
+ const int val = 42;
+ auto f = QtFuture::makeReadyValueFuture(val);
+ QCOMPARE_EQ(f.result(), val);
+
+ int otherVal = 42;
+ f = QtFuture::makeReadyValueFuture(otherVal);
+ QCOMPARE_EQ(f.result(), otherVal);
+ }
+ {
+ auto f = QtFuture::makeReadyValueFuture(std::make_unique<int>(42));
+ QCOMPARE(*f.takeResult(), 42);
+ }
+ // test makeReadyVoidFuture()
+ {
+ auto f = QtFuture::makeReadyVoidFuture();
+ QVERIFY(f.isStarted());
+ QVERIFY(!f.isRunning());
+ QVERIFY(f.isFinished());
+ }
+
#ifndef QT_NO_EXCEPTIONS
// using QException
{
@@ -4236,7 +4259,7 @@ void tst_QFuture::createReadyFutures()
void tst_QFuture::getFutureInterface()
{
const int val = 42;
- QFuture<int> f = QtFuture::makeReadyFuture(val);
+ QFuture<int> f = QtFuture::makeReadyValueFuture(val);
auto interface = QFutureInterfaceBase::get(f);
QCOMPARE(interface.resultCount(), 1);
@@ -4250,7 +4273,7 @@ void tst_QFuture::convertQMetaType()
QVERIFY(QMetaType::canConvert(intType, voidType));
const int val = 42;
- QFuture<int> f = QtFuture::makeReadyFuture(val);
+ QFuture<int> f = QtFuture::makeReadyValueFuture(val);
auto variant = QVariant::fromValue(f);
QVERIFY(variant.convert(voidType));
diff --git a/tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp b/tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp
index 7c0e3b2fcf..74dd549462 100644
--- a/tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp
+++ b/tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp
@@ -13,7 +13,7 @@ class tst_QFuture : public QObject
Q_OBJECT
private slots:
- void makeReadyfuture();
+ void makeReadyValueFuture();
#ifndef QT_NO_EXCEPTIONS
void makeExceptionalFuture();
#endif
@@ -43,10 +43,10 @@ private slots:
void progressText();
};
-void tst_QFuture::makeReadyfuture()
+void tst_QFuture::makeReadyValueFuture()
{
QBENCHMARK {
- auto future = QtFuture::makeReadyFuture(42);
+ auto future = QtFuture::makeReadyValueFuture(42);
Q_UNUSED(future);
}
}
@@ -64,7 +64,7 @@ void tst_QFuture::makeExceptionalFuture()
void tst_QFuture::result()
{
- auto future = QtFuture::makeReadyFuture(42);
+ auto future = QtFuture::makeReadyValueFuture(42);
QBENCHMARK {
auto value = future.result();
@@ -92,7 +92,7 @@ void tst_QFuture::results()
void tst_QFuture::takeResult()
{
QBENCHMARK {
- auto future = QtFuture::makeReadyFuture(42);
+ auto future = QtFuture::makeReadyValueFuture(42);
auto value = future.takeResult();
Q_UNUSED(value);
}
@@ -140,7 +140,7 @@ void tst_QFuture::reportException()
void tst_QFuture::then()
{
- auto f = QtFuture::makeReadyFuture(42);
+ auto f = QtFuture::makeReadyValueFuture(42);
QBENCHMARK {
auto future = f.then([](int value) { return value; });
Q_UNUSED(future);
@@ -149,7 +149,7 @@ void tst_QFuture::then()
void tst_QFuture::thenVoid()
{
- auto f = QtFuture::makeReadyFuture();
+ auto f = QtFuture::makeReadyVoidFuture();
QBENCHMARK {
auto future = f.then([] {});
Q_UNUSED(future);
@@ -205,7 +205,7 @@ void tst_QFuture::onFailedVoid()
void tst_QFuture::thenOnFailed()
{
- auto f = QtFuture::makeReadyFuture(42);
+ auto f = QtFuture::makeReadyValueFuture(42);
QBENCHMARK {
auto future =
f.then([](int) { throw std::runtime_error("error"); }).onFailed([] { return 0; });
@@ -215,7 +215,7 @@ void tst_QFuture::thenOnFailed()
void tst_QFuture::thenOnFailedVoid()
{
- auto f = QtFuture::makeReadyFuture();
+ auto f = QtFuture::makeReadyVoidFuture();
QBENCHMARK {
auto future = f.then([] { throw std::runtime_error("error"); }).onFailed([] {});
Q_UNUSED(future);