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>
This commit is contained in:
parent
7f38f9f394
commit
9b4b32ec98
@ -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]
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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>() });
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user