diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-03-20 16:11:15 +0100 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-04-05 13:38:15 +0200 |
commit | 9b4b32ec98bf80023d2233a061564dfe59b783c7 (patch) | |
tree | 42ea1e44c26e9ba38e52b9b159dbfd6d8fddd288 | |
parent | 7f38f9f394b7283de93a2367765572241dede84b (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.cpp | 20 | ||||
-rw-r--r-- | src/corelib/platform/android/qandroidextras.cpp | 6 | ||||
-rw-r--r-- | src/corelib/thread/qfuture.h | 10 | ||||
-rw-r--r-- | src/corelib/thread/qfuture.qdoc | 64 | ||||
-rw-r--r-- | src/corelib/thread/qfuture_impl.h | 27 | ||||
-rw-r--r-- | src/corelib/thread/qfutureinterface.cpp | 13 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qfuture/tst_qfuture.cpp | 39 | ||||
-rw-r--r-- | tests/benchmarks/corelib/thread/qfuture/tst_bench_qfuture.cpp | 18 |
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); |