Add convenience functions for QFuture creation

[ChangeLog][QtCore][QFuture] Add convenience functions to create
a ready QFuture and a QFuture with an exception

Task-number: QTBUG-86713
Change-Id: Ic7f9ca590a8ea8a9696b84f35bad074780794461
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
bb10
Ivan Solovev 2020-11-12 18:02:09 +01:00
parent f61f8bb966
commit 54875be84d
3 changed files with 239 additions and 1 deletions

View File

@ -134,7 +134,12 @@
you can attach multiple continuations to a signal, which are invoked in the
same thread or a new thread.
\sa QtFuture::connect(), QFutureWatcher, {Qt Concurrent}
A ready QFuture object with a value or a QFuture object holding exception can
be created using convenience functions QtFuture::makeReadyFuture and
QtFuture::makeExceptionalFuture.
\sa QtFuture::connect(), QtFuture::makeReadyFuture(),
QtFuture::makeExceptionalFuture(), QFutureWatcher, {Qt Concurrent}
*/
/*! \fn template <typename T> QFuture<T>::QFuture()
@ -944,6 +949,107 @@
\sa QFuture, QFuture::then()
*/
/*! \fn template<typename T> static QFuture<std::decay_t<T>> QtFuture::makeReadyFuture(T &&value)
\since 6.1
\overload
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.
\code
auto f = QtFuture::makeReadyFuture(std::make_unique<int>(42));
...
const int result = *f.takeResult(); // result == 42
\endcode
\sa QFuture, QtFuture::makeExceptionalFuture()
*/
/*! \fn QFuture<void> QtFuture::makeReadyFuture()
\since 6.1
\overload
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 always be in the finished state.
\code
auto f = QtFuture::makeReadyFuture();
...
const bool started = f.isStarted(); // started == true
const bool running = f.isRunning(); // running == false
const bool finished = f.isFinished(); // finished == true
\endcode
\sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
QFuture::isFinished(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeReadyFuture(const QList<T> &values)
\since 6.1
\overload
Creates and returns a QFuture which already has multiple results set from \a values.
\code
const QList<int> values { 1, 2, 3 };
auto f = QtFuture::makeReadyFuture(values);
...
const int count = f.resultCount(); // count == 3
const auto results = f.results(); // results == { 1, 2, 3 }
\endcode
\sa QFuture, QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(const QException &exception)
\since 6.1
Creates and returns a QFuture which already has an exception \a exception.
\code
QException e;
auto f = QtFuture::makeExceptionalFuture<int>(e);
...
try {
f.result(); // throws QException
} catch (QException &) {
// handle exception here
}
\endcode
\sa QFuture, QException, QtFuture::makeReadyFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(std::exception_ptr exception)
\since 6.1
\overload
Creates and returns a QFuture which already has an exception \a exception.
\code
struct TestException
{
};
...
auto exception = std::make_exception_ptr(TestException());
auto f = QtFuture::makeExceptionalFuture<int>(exception);
...
try {
f.result(); // throws TestException
} catch (TestException &) {
// handle exception here
}
\endcode
\sa QFuture, QException, QtFuture::makeReadyFuture()
*/
/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(Function &&function)
\since 6.0

View File

@ -49,6 +49,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qfutureinterface.h>
#include <QtCore/qthreadpool.h>
#include <QtCore/qexception.h>
QT_BEGIN_NAMESPACE
@ -741,6 +742,68 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
return promise.future();
}
template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
{
QFutureInterface<std::decay_t<T>> promise;
promise.reportStarted();
promise.reportResult(std::forward<T>(value));
promise.reportFinished();
return promise.future();
}
#if defined(Q_CLANG_QDOC)
static QFuture<void> makeReadyFuture()
#else
template<typename T = void>
static QFuture<T> makeReadyFuture()
#endif
{
QFutureInterface<T> promise;
promise.reportStarted();
promise.reportFinished();
return promise.future();
}
template<typename T>
static QFuture<T> makeReadyFuture(const QList<T> &values)
{
QFutureInterface<T> promise;
promise.reportStarted();
promise.reportResults(values);
promise.reportFinished();
return promise.future();
}
#ifndef QT_NO_EXCEPTIONS
template<typename T = void>
static QFuture<T> makeExceptionalFuture(std::exception_ptr exception)
{
QFutureInterface<T> promise;
promise.reportStarted();
promise.reportException(exception);
promise.reportFinished();
return promise.future();
}
template<typename T = void>
static QFuture<T> makeExceptionalFuture(const QException &exception)
{
try {
exception.raise();
} catch (...) {
return makeExceptionalFuture<T>(std::current_exception());
}
Q_UNREACHABLE();
}
#endif // QT_NO_EXCEPTIONS
} // namespace QtFuture
QT_END_NAMESPACE

View File

@ -156,6 +156,8 @@ private slots:
void rejectPendingResultOverwrite_data() { rejectResultOverwrite_data(); }
void rejectPendingResultOverwrite();
void createReadyFutures();
private:
using size_type = std::vector<int>::size_type;
@ -3338,5 +3340,72 @@ void tst_QFuture::rejectPendingResultOverwrite()
QCOMPARE(f.results(), initResults);
}
void tst_QFuture::createReadyFutures()
{
// using const T &
{
const int val = 42;
QFuture<int> f = QtFuture::makeReadyFuture(val);
QCOMPARE(f.result(), val);
}
// using T
{
int val = 42;
QFuture<int> f = QtFuture::makeReadyFuture(val);
QCOMPARE(f.result(), val);
}
// using T &&
{
auto f = QtFuture::makeReadyFuture(std::make_unique<int>(42));
QCOMPARE(*f.takeResult(), 42);
}
// using void
{
auto f = QtFuture::makeReadyFuture();
QVERIFY(f.isStarted());
QVERIFY(!f.isRunning());
QVERIFY(f.isFinished());
}
// using const QList<T> &
{
const QList<int> values { 1, 2, 3 };
auto f = QtFuture::makeReadyFuture(values);
QCOMPARE(f.resultCount(), 3);
QCOMPARE(f.results(), values);
}
#ifndef QT_NO_EXCEPTIONS
// using QException
{
QException e;
auto f = QtFuture::makeExceptionalFuture<int>(e);
bool caught = false;
try {
f.result();
} catch (QException &) {
caught = true;
}
QVERIFY(caught);
}
// using std::exception_ptr and QFuture<void>
{
auto exception = std::make_exception_ptr(TestException());
auto f = QtFuture::makeExceptionalFuture(exception);
bool caught = false;
try {
f.waitForFinished();
} catch (TestException &) {
caught = true;
}
QVERIFY(caught);
}
#endif
}
QTEST_MAIN(tst_QFuture)
#include "tst_qfuture.moc"