QtConcurrent: Integrate runWithPromise into run

Change-Id: I6eb95aa66ff847e8bb9aac348fded3a5d55015b6
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
This commit is contained in:
Jarek Kobus 2020-10-02 19:24:38 +02:00
parent bb8c24e467
commit cf043a785a
7 changed files with 373 additions and 309 deletions

View File

@ -147,7 +147,7 @@ QtConcurrent::run(&o, 42).waitForFinished(); // compilation error
//! [9] //! [9]
extern void aFunction(QPromise<void> &promise); extern void aFunction(QPromise<void> &promise);
QFuture<void> future = QtConcurrent::runWithPromise(aFunction); QFuture<void> future = QtConcurrent::run(aFunction);
//! [9] //! [9]
//! [10] //! [10]
@ -156,7 +156,7 @@ extern void aFunction(QPromise<void> &promise, int arg1, const QString &arg2);
int integer = ...; int integer = ...;
QString string = ...; QString string = ...;
QFuture<void> future = QtConcurrent::runWithPromise(aFunction, integer, string); QFuture<void> future = QtConcurrent::run(aFunction, integer, string);
//! [10] //! [10]
//! [11] //! [11]
@ -166,7 +166,7 @@ void helloWorldFunction(QPromise<QString> &promise)
promise.addResult("world"); promise.addResult("world");
} }
QFuture<QString> future = QtConcurrent::runWithPromise(helloWorldFunction); QFuture<QString> future = QtConcurrent::run(helloWorldFunction);
... ...
QList<QString> results = future.results(); QList<QString> results = future.results();
//! [11] //! [11]
@ -185,7 +185,7 @@ void aFunction(QPromise<int> &promise)
} }
} }
QFuture<int> future = QtConcurrent::runWithPromise(aFunction); QFuture<int> future = QtConcurrent::run(aFunction);
... // user pressed a pause button after 10 seconds ... // user pressed a pause button after 10 seconds
future.suspend(); future.suspend();
@ -216,7 +216,7 @@ QObject::connect(&watcher, &QFutureWatcher::progressValueChanged, [](int progres
... ; // update GUI with a progress ... ; // update GUI with a progress
qDebug() << "current progress:" << progress; qDebug() << "current progress:" << progress;
}); });
watcher.setFuture(QtConcurrent::runWithPromise(aFunction)); watcher.setFuture(QtConcurrent::run(aFunction));
//! [13] //! [13]
//! [14] //! [14]
@ -226,7 +226,7 @@ struct Functor {
}; };
Functor f; Functor f;
runWithPromise<double>(f); // this will select the 2nd overload run<double>(f); // this will select the 2nd overload
// runWithPromise(f); // error, both candidate overloads potentially match // run(f); // error, both candidate overloads potentially match
//! [14] //! [14]

View File

@ -81,15 +81,10 @@
folded into a single result. folded into a single result.
\endlist \endlist
\li \l {Concurrent Run and Run With Promise} \li \l {Concurrent Run}
\list \list
\li \l {QtConcurrent::run}{QtConcurrent::run()} runs a function in \li \l {QtConcurrent::run}{QtConcurrent::run()} runs a function in
another thread. another thread.
\li \l {QtConcurrent::runWithPromise}{QtConcurrent::runWithPromise()}
is like run(), except that the function to run accepts additional
argument of QPromise type that enables more control over the function
execution, like suspending or canceling the execution when requested,
progress reporting or reporting multiple results.
\endlist \endlist
\li \l {Concurrent Task} \li \l {Concurrent Task}

View File

@ -39,22 +39,25 @@
/*! /*!
\page qtconcurrentrun.html \page qtconcurrentrun.html
\title Concurrent Run and Run With Promise \title Concurrent Run
\ingroup thread \ingroup thread
The QtConcurrent::run() and QtConcurrent::runWithPromise() The QtConcurrent::run() function runs a function in a separate thread.
functions run a function in a separate thread.
The return value of the function is made available through the QFuture API. The return value of the function is made available through the QFuture API.
The function passed to QtConcurrent::run() is able to report merely
a single computation result to its caller, while the function passed to QtConcurrent::run() is an overloaded method. You can think of these overloads as slightly
QtConcurrent::runWithPromise() can make use of the additional different \e modes.
In \l {Concurrent Run (basic mode)} {basic mode}, the function passed to QtConcurrent::run()
is able to report merely a single computation result to its caller.
In \l {Concurrent Run With Promise} {run with promise mode}, the function passed to
QtConcurrent::run() can make use of the additional
QPromise API, which enables multiple result reporting, progress reporting, QPromise API, which enables multiple result reporting, progress reporting,
suspending the computation when requested by the caller, or stopping suspending the computation when requested by the caller, or stopping
the computation on the caller's demand. the computation on the caller's demand.
These functions are part of the Qt Concurrent framework. This function is a part of the Qt Concurrent framework.
\section1 Concurrent Run \section1 Concurrent Run (basic mode)
The function passed to QtConcurrent::run() may report the result The function passed to QtConcurrent::run() may report the result
through its return value. through its return value.
@ -65,7 +68,7 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp 0 \snippet code/src_concurrent_qtconcurrentrun.cpp 0
This will run \e aFunction in a separate thread obtained from the default This will run \c aFunction in a separate thread obtained from the default
QThreadPool. You can use the QFuture and QFutureWatcher classes to monitor QThreadPool. You can use the QFuture and QFutureWatcher classes to monitor
the status of the function. the status of the function.
@ -135,8 +138,8 @@
\section1 Concurrent Run With Promise \section1 Concurrent Run With Promise
The QtConcurrent::runWithPromise() enables more control The \e {Run With Promise} mode enables more control for the running
for the running task comparing to QtConcurrent::run(). task compared to \e basic mode of QtConcurrent::run().
It allows progress reporting of the running task, It allows progress reporting of the running task,
reporting multiple results, suspending the execution reporting multiple results, suspending the execution
if it was requested, or canceling the task on caller's if it was requested, or canceling the task on caller's
@ -144,16 +147,16 @@
\section2 The mandatory QPromise argument \section2 The mandatory QPromise argument
The function passed to QtConcurrent::runWithPromise() is expected The function passed to QtConcurrent::run() in \e {Run With Promise} mode is expected
to have an additional argument of \e {QPromise<T> &} type, where to have an additional argument of \c {QPromise<T> &} type, where
T is the type of the computation result (it should match the type T T is the type of the computation result (it should match the type T
of QFuture<T> returned by the QtConcurrent::runWithPromise()), like e.g.: of QFuture<T> returned by the QtConcurrent::runWithPromise()), like e.g.:
\snippet code/src_concurrent_qtconcurrentrun.cpp 9 \snippet code/src_concurrent_qtconcurrentrun.cpp 9
The \e promise argument is instantiated inside the The \c promise argument is instantiated inside the
QtConcurrent::runWithPromise() function, and its reference QtConcurrent::run() function, and its reference
is passed to the invoked \e aFunction, so the user is passed to the invoked \c aFunction, so the user
doesn't need to instantiate it by himself, nor pass it explicitly doesn't need to instantiate it by himself, nor pass it explicitly
when calling QtConcurrent::runWithPromise(). when calling QtConcurrent::runWithPromise().
@ -164,8 +167,8 @@
\section2 Reporting results \section2 Reporting results
In contrast to QtConcurrent::run(), the function passed to In contrast to \e basic mode of QtConcurrent::run(), the function passed to
QtConcurrent::runWithPromise() is expected to always return void type. QtConcurrent::run() in \e {Run With Promise} mode is expected to always return void type.
Result reporting is done through the additional argument of QPromise type. Result reporting is done through the additional argument of QPromise type.
It also enables multiple result reporting, like: It also enables multiple result reporting, like:
@ -177,20 +180,20 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp 12 \snippet code/src_concurrent_qtconcurrentrun.cpp 12
The call to \e future.suspend() requests the running task to The call to \c future.suspend() requests the running task to
hold its execution. After calling this method, the running task hold its execution. After calling this method, the running task
will suspend after the next call to \e promise.suspendIfRequested() will suspend after the next call to \c promise.suspendIfRequested()
in its iteration loop. In this case the running task will in its iteration loop. In this case the running task will
block on a call to \e promise.suspendIfRequested(). The blocked block on a call to \c promise.suspendIfRequested(). The blocked
call will unblock after the \e future.resume() is called. call will unblock after the \c future.resume() is called.
Note, that internally suspendIfRequested() uses wait condition Note, that internally suspendIfRequested() uses wait condition
in order to unblock, so the running thread goes into an idle state in order to unblock, so the running thread goes into an idle state
instead of wasting its resources when blocked in order to periodically instead of wasting its resources when blocked in order to periodically
check if the resume request came from the caller's thread. check if the resume request came from the caller's thread.
The call to \e future.cancel() from the last line causes that the next The call to \c future.cancel() from the last line causes that the next
call to \e promise.isCanceled() will return \c true and call to \c promise.isCanceled() will return \c true and
\e aFunction will return immediately without any further result reporting. \c aFunction will return immediately without any further result reporting.
\section2 Progress reporting \section2 Progress reporting
@ -199,17 +202,17 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp 13 \snippet code/src_concurrent_qtconcurrentrun.cpp 13
The caller installs the \e QFutureWatcher for the \e QFuture The caller installs the \c QFutureWatcher for the \c QFuture
returned by QtConcurrent::runWithPromise() in order to returned by QtConcurrent::run() in order to
connect to its \e progressValueChanged() signal and update connect to its \c progressValueChanged() signal and update
e.g. the graphical user interface accordingly. e.g. the graphical user interface accordingly.
\section2 Invoking functions with overloaded operator()() \section2 Invoking functions with overloaded operator()()
By default, QtConcurrent::runWithPromise() doesn't support functors with By default, QtConcurrent::run() doesn't support functors with
overloaded operator()(). In case of overloaded functors the user overloaded operator()() in \e {Run With Promise} mode. In case of overloaded
needs to explicitly specify the result type functors the user needs to explicitly specify the result type
as a template parameter passed to runWithPromise, like: as a template parameter passed to QtConcurrent::run(), like:
\snippet code/src_concurrent_qtconcurrentrun.cpp 14 \snippet code/src_concurrent_qtconcurrentrun.cpp 14
*/ */
@ -235,15 +238,28 @@
QThreadPool. Note that \a function may not run immediately; \a function QThreadPool. Note that \a function may not run immediately; \a function
will only be run once a thread becomes available. will only be run once a thread becomes available.
T is the same type as the return value of \a function. Non-void return //! [run-description]
values can be accessed via the QFuture::result() function. In \l {Concurrent Run (basic mode)} {basic mode} T is the same type as the return value
of \a function. Non-void return values can be accessed via the QFuture::result() function.
\note The QFuture returned can only be used to query for the In \l {Concurrent Run (basic mode)} {basic mode} the QFuture returned can only be used to
running/finished status and the return value of the function. In particular, query for the running/finished status and the return value of the function. In particular,
canceling or pausing can be issued only if the computations behind the future canceling or pausing can be issued only if the computations behind the future
has not been started. has not been started.
\sa {Concurrent Run} In \l {Concurrent Run With Promise} {run with promise mode}, the \a function is expected
to return void and must take an additional argument of \c {QPromise<T> &} type,
placed as a first argument in function's argument list. T is the result type
and it is the same for the returned \c QFuture<T>.
In \l {Concurrent Run With Promise} {run with promise mode}, similar to \e basic mode, the
QFuture returned can be used to query for the running/finished status and the value reported
by the function. In addition, it may be used for suspending or canceling the
running task, fetching multiple results from the called \a function or
monitoring progress reported by the \a function.
\sa {Concurrent Run (basic mode)}, {Concurrent Run With Promise}
//! [run-description]
*/ */
/*! /*!
@ -254,62 +270,6 @@
QThreadPool \a pool. Note that \a function may not run immediately; \a function QThreadPool \a pool. Note that \a function may not run immediately; \a function
will only be run once a thread becomes available. will only be run once a thread becomes available.
T is the same type as the return value of \a function. Non-void return \include qtconcurrentrun.cpp run-description
values can be accessed via the QFuture::result() function.
\note The QFuture returned can only be used to query for the
running/finished status and the return value of the function. In particular,
canceling or pausing can be issued only if the computations behind the future
has not been started.
\sa {Concurrent Run}
*/ */
/*!
\since 6.0
\fn QFuture<T> QtConcurrent::runWithPromise(Function function, ...);
Equivalent to
\code
QtConcurrent::runWithPromise(QThreadPool::globalInstance(), function, ...);
\endcode
Runs \a function in a separate thread. The thread is taken from the global
QThreadPool. Note that \a function may not run immediately; \a function
will only be run once a thread becomes available.
The \a function is expected to return void
and must take an additional argument of \e {QPromise<T> &} type,
placed as a first argument in function's argument list. T is the result type
and it is the same for the returned \e QFuture<T>.
Similar to QtConcurrent::run(), the QFuture returned can be used to query for the
running/finished status and the value reported by the function. In addition,
it may be used for suspending or canceling the running task, fetching
multiple results from the called /a function or monitoring progress
reported by the \a function.
\sa {Concurrent Run With Promise}
*/
/*!
\since 6.0
\fn QFuture<T> QtConcurrent::runWithPromise(QThreadPool *pool, Function function, ...);
Runs \a function in a separate thread. The thread is taken from the
QThreadPool \a pool. Note that \a function may not run immediately; \a function
will only be run once a thread becomes available.
The \a function is expected to return void
and must take an additional argument of \e {QPromise<T> &} type,
placed as a first argument in function's argument list. T is the result type
and it is the same for the returned \e QFuture<T>.
Similar to QtConcurrent::run(), the QFuture returned can be used to query for the
running/finished status and the value reported by the function. In addition,
it may be used for suspending or canceling the running task, fetching
multiple results from the called /a function or monitoring progress
reported by the \a function.
\sa {Concurrent Run With Promise}
*/

View File

@ -77,55 +77,45 @@ template <class Function, class ...Args>
[[nodiscard]] [[nodiscard]]
auto run(QThreadPool *pool, Function &&f, Args &&...args) auto run(QThreadPool *pool, Function &&f, Args &&...args)
{ {
return (new StoredFunctionCall<Function, Args...>( DecayedTuple<Function, Args...> tuple { std::forward<Function>(f),
std::forward<Function>(f), std::forward<Args>(args)...))->start(pool); std::forward<Args>(args)... };
return TaskResolver<std::decay_t<Function>, std::decay_t<Args>...>::run(
std::move(tuple), TaskStartParameters { pool });
}
template <class Function, class ...Args>
[[nodiscard]]
auto run(QThreadPool *pool, std::reference_wrapper<const Function> &&functionWrapper,
Args &&...args)
{
return run(pool, std::forward<const Function>(functionWrapper.get()),
std::forward<Args>(args)...);
} }
template <class Function, class ...Args> template <class Function, class ...Args>
[[nodiscard]] [[nodiscard]]
auto run(Function &&f, Args &&...args) auto run(Function &&f, Args &&...args)
{ {
return run(QThreadPool::globalInstance(), std::forward<Function>(f), std::forward<Args>(args)...); return run(QThreadPool::globalInstance(), std::forward<Function>(f),
std::forward<Args>(args)...);
} }
// overload with a Promise Type hint, takes thread pool
template <class PromiseType, class Function, class ...Args> template <class PromiseType, class Function, class ...Args>
[[nodiscard]] [[nodiscard]]
auto runWithPromise(QThreadPool *pool, Function &&f, Args &&...args) auto run(QThreadPool *pool, Function &&f, Args &&...args)
{ {
return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>( return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(
std::forward<Function>(f), std::forward<Args>(args)...))->start(pool); std::forward<Function>(f), std::forward<Args>(args)...))->start(pool);
} }
template <class Function, class ...Args> // overload with a Promise Type hint, uses global thread pool
[[nodiscard]]
auto runWithPromise(QThreadPool *pool, Function &&f, Args &&...args)
{
static_assert(QtPrivate::ArgResolver<Function>::IsPromise, "The first argument of passed callable object isn't a QPromise<T> & type.");
using PromiseType = typename QtPrivate::ArgResolver<Function>::PromiseType;
return runWithPromise<PromiseType>(pool, std::forward<Function>(f), std::forward<Args>(args)...);
}
template <class Function, class ...Args>
[[nodiscard]]
auto runWithPromise(QThreadPool *pool, std::reference_wrapper<const Function> &&functionWrapper, Args &&...args)
{
static_assert(QtPrivate::ArgResolver<const Function>::IsPromise, "The first argument of passed callable object isn't a QPromise<T> & type.");
using PromiseType = typename QtPrivate::ArgResolver<const Function>::PromiseType;
return runWithPromise<PromiseType>(pool, std::forward<const Function>(functionWrapper.get()), std::forward<Args>(args)...);
}
template <class PromiseType, class Function, class ...Args> template <class PromiseType, class Function, class ...Args>
[[nodiscard]] [[nodiscard]]
auto runWithPromise(Function &&f, Args &&...args) auto run(Function &&f, Args &&...args)
{ {
return runWithPromise<PromiseType>(QThreadPool::globalInstance(), std::forward<Function>(f), std::forward<Args>(args)...); return run<PromiseType>(QThreadPool::globalInstance(), std::forward<Function>(f),
} std::forward<Args>(args)...);
template <class Function, class ...Args>
[[nodiscard]]
auto runWithPromise(Function &&f, Args &&...args)
{
return runWithPromise(QThreadPool::globalInstance(), std::forward<Function>(f), std::forward<Args>(args)...);
} }
} //namespace QtConcurrent } //namespace QtConcurrent

View File

@ -102,17 +102,21 @@ template <class IsMember, class Function, class PromiseType, class... Args>
struct FunctionResolverHelper; struct FunctionResolverHelper;
template <class Function, class PromiseType, class... Args> template <class Function, class PromiseType, class... Args>
struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...> : public NonMemberFunctionResolver<Function, PromiseType, Args...> struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...>
: public NonMemberFunctionResolver<Function, PromiseType, Args...>
{ {
}; };
template <class Function, class PromiseType, class... Args> template <class Function, class PromiseType, class... Args>
struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...> : public MemberFunctionResolver<Function, PromiseType, Args...> struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...>
: public MemberFunctionResolver<Function, PromiseType, Args...>
{ {
}; };
template <class Function, class PromiseType, class... Args> template <class Function, class PromiseType, class... Args>
struct FunctionResolver : public FunctionResolverHelper<typename std::is_member_function_pointer<std::decay_t<Function>>::type, Function, PromiseType, Args...> struct FunctionResolver
: public FunctionResolverHelper<typename std::is_member_function_pointer<
std::decay_t<Function>>::type, Function, PromiseType, Args...>
{ {
}; };
@ -134,10 +138,6 @@ using DecayedTuple = std::tuple<std::decay_t<Types>...>;
template <class Function, class ...Args> template <class Function, class ...Args>
struct StoredFunctionCall : public RunFunctionTask<InvokeResultType<Function, Args...>> struct StoredFunctionCall : public RunFunctionTask<InvokeResultType<Function, Args...>>
{ {
StoredFunctionCall(Function &&f, Args &&...args)
: data{std::forward<Function>(f), std::forward<Args>(args)...}
{}
StoredFunctionCall(DecayedTuple<Function, Args...> &&_data) StoredFunctionCall(DecayedTuple<Function, Args...> &&_data)
: data(std::move(_data)) : data(std::move(_data))
{} {}
@ -165,11 +165,13 @@ struct StoredFunctionCallWithPromise : public RunFunctionTaskBase<PromiseType>
using DataType = typename Resolver::Type; using DataType = typename Resolver::Type;
StoredFunctionCallWithPromise(Function &&f, Args &&...args) StoredFunctionCallWithPromise(Function &&f, Args &&...args)
: prom(this->promise), : prom(this->promise),
data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom), std::forward<Args>(args)...))) data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom),
std::forward<Args>(args)...)))
{} {}
StoredFunctionCallWithPromise(DataType &&_data) StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data)
: data(std::move(_data)) : StoredFunctionCallWithPromise(std::move(_data),
std::index_sequence_for<std::decay_t<Function>, std::decay_t<Args>...>())
{} {}
protected: protected:
@ -179,10 +181,69 @@ protected:
} }
private: private:
// helper to pack back the tuple into parameter pack
template<std::size_t... Is>
StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data,
std::index_sequence<Is...>)
: StoredFunctionCallWithPromise(std::move(std::get<Is>(_data))...)
{}
QPromise<PromiseType> prom; QPromise<PromiseType> prom;
DataType data; DataType data;
}; };
template<typename...>
struct NonPromiseTaskResolver;
template <typename Function, typename ... Args>
struct NonPromiseTaskResolver<Function, Args...>
{
using TaskWithArgs = DecayedTuple<Function, Args...>;
static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) {
return (new StoredFunctionCall<Function, Args...>(std::move(args)))
->start(startParameters);
}
};
template<typename...>
struct PromiseTaskResolver;
template <typename Function, typename ... Args>
struct PromiseTaskResolver<Function, Args...>
{
static_assert(QtPrivate::ArgResolver<Function>::IsPromise::value,
"The first argument of passed callable object isn't a QPromise<T> & type. "
"Did you intend to pass a callable which takes a QPromise<T> & type as a first argument? "
"Otherwise it's not possible to invoke the function with passed arguments.");
using TaskWithArgs = DecayedTuple<Function, Args...>;
static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) {
using PromiseType = typename QtPrivate::ArgResolver<Function>::PromiseType;
return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(std::move(args)))
->start(startParameters);
}
};
template <class IsDirectlyInvocable, class Function, class... Args>
struct TaskResolverHelper;
template <class Function, class... Args>
struct TaskResolverHelper<std::true_type, Function, Args...>
: public NonPromiseTaskResolver<Function, Args...>
{
};
template <class Function, class... Args>
struct TaskResolverHelper<std::false_type, Function, Args...>
: public PromiseTaskResolver<Function, Args...>
{
};
template <class Function, class... Args>
struct TaskResolver : public TaskResolverHelper<typename std::is_invocable<std::decay_t<Function>,
std::decay_t<Args>...>::type, Function, Args...>
{
};
} //namespace QtConcurrent } //namespace QtConcurrent
#endif // Q_QDOC #endif // Q_QDOC

View File

@ -124,7 +124,7 @@ struct ArgsType<Arg, Args...>
{ {
using First = Arg; using First = Arg;
using PromiseType = void; using PromiseType = void;
static const bool IsPromise = false; using IsPromise = std::false_type;
static const bool HasExtraArgs = (sizeof...(Args) > 0); static const bool HasExtraArgs = (sizeof...(Args) > 0);
using AllArgs = using AllArgs =
std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>, std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>,
@ -139,7 +139,7 @@ struct ArgsType<QPromise<Arg> &, Args...>
{ {
using First = QPromise<Arg> &; using First = QPromise<Arg> &;
using PromiseType = Arg; using PromiseType = Arg;
static const bool IsPromise = true; using IsPromise = std::true_type;
static const bool HasExtraArgs = (sizeof...(Args) > 0); static const bool HasExtraArgs = (sizeof...(Args) > 0);
using AllArgs = using AllArgs =
std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<QPromise<Arg> &>, std::decay_t<Args>...>, std::conditional_t<HasExtraArgs, std::tuple<std::decay_t<QPromise<Arg> &>, std::decay_t<Args>...>,
@ -154,7 +154,7 @@ struct ArgsType<>
{ {
using First = void; using First = void;
using PromiseType = void; using PromiseType = void;
static const bool IsPromise = false; using IsPromise = std::false_type;
static const bool HasExtraArgs = false; static const bool HasExtraArgs = false;
using AllArgs = void; using AllArgs = void;

View File

@ -57,6 +57,7 @@ private slots:
void withPromiseInThreadPool(); void withPromiseInThreadPool();
void moveOnlyType(); void moveOnlyType();
void crefFunction(); void crefFunction();
void customPromise();
}; };
void light() void light()
@ -122,14 +123,14 @@ void tst_QtConcurrentRun::runLightFunction()
void (*f3)(QPromise<int> &) = lightOverloaded; void (*f3)(QPromise<int> &) = lightOverloaded;
qDebug("starting function with promise"); qDebug("starting function with promise");
QFuture<void> future3 = runWithPromise(f3); QFuture<void> future3 = run(f3);
qDebug("waiting"); qDebug("waiting");
future3.waitForFinished(); future3.waitForFinished();
qDebug("done"); qDebug("done");
void (*f4)(QPromise<double> &, int v) = lightOverloaded; void (*f4)(QPromise<double> &, int v) = lightOverloaded;
qDebug("starting function with promise and with arg"); qDebug("starting function with promise and with arg");
QFuture<void> future4 = runWithPromise(f4, 2); QFuture<void> future4 = run(f4, 2);
qDebug("waiting"); qDebug("waiting");
future4.waitForFinished(); future4.waitForFinished();
qDebug("done"); qDebug("done");
@ -429,141 +430,141 @@ void tst_QtConcurrentRun::reportValueWithPromise()
QThreadPool pool; QThreadPool pool;
QFuture<int> f; QFuture<int> f;
f = runWithPromise(reportInt0); f = run(reportInt0);
QCOMPARE(f.result(), 0); QCOMPARE(f.result(), 0);
f = runWithPromise(&pool, reportInt0); f = run(&pool, reportInt0);
QCOMPARE(f.result(), 0); QCOMPARE(f.result(), 0);
f = runWithPromise(reportIntPlusOne, 5); f = run(reportIntPlusOne, 5);
QCOMPARE(f.result(), 6); QCOMPARE(f.result(), 6);
f = runWithPromise(&pool, reportIntPlusOne, 5); f = run(&pool, reportIntPlusOne, 5);
QCOMPARE(f.result(), 6); QCOMPARE(f.result(), 6);
AWithPromise a; AWithPromise a;
f = runWithPromise(&AWithPromise::member0, &a); f = run(&AWithPromise::member0, &a);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &AWithPromise::member0, &a); f = run(&pool, &AWithPromise::member0, &a);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&AWithPromise::member1, &a, 20); f = run(&AWithPromise::member1, &a, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &AWithPromise::member1, &a, 20); f = run(&pool, &AWithPromise::member1, &a, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&AWithPromise::member0, a); f = run(&AWithPromise::member0, a);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &AWithPromise::member0, a); f = run(&pool, &AWithPromise::member0, a);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&AWithPromise::member1, a, 20); f = run(&AWithPromise::member1, a, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &AWithPromise::member1, a, 20); f = run(&pool, &AWithPromise::member1, a, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(a); f = run(a);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, a); f = run(&pool, a);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(std::ref(a)); f = run(std::ref(a));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, std::ref(a)); f = run(&pool, std::ref(a));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
const AConstWithPromise aConst = AConstWithPromise(); const AConstWithPromise aConst = AConstWithPromise();
f = runWithPromise(&AConstWithPromise::member0, &aConst); f = run(&AConstWithPromise::member0, &aConst);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &AConstWithPromise::member0, &aConst); f = run(&pool, &AConstWithPromise::member0, &aConst);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&AConstWithPromise::member1, &aConst, 20); f = run(&AConstWithPromise::member1, &aConst, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &AConstWithPromise::member1, &aConst, 20); f = run(&pool, &AConstWithPromise::member1, &aConst, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&AConstWithPromise::member0, aConst); f = run(&AConstWithPromise::member0, aConst);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &AConstWithPromise::member0, aConst); f = run(&pool, &AConstWithPromise::member0, aConst);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&AConstWithPromise::member1, aConst, 20); f = run(&AConstWithPromise::member1, aConst, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &AConstWithPromise::member1, aConst, 20); f = run(&pool, &AConstWithPromise::member1, aConst, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(aConst); f = run(aConst);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, aConst); f = run(&pool, aConst);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(std::ref(a)); f = run(std::ref(a));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, std::ref(a)); f = run(&pool, std::ref(a));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
ANoExceptWithPromise aNoExcept; ANoExceptWithPromise aNoExcept;
f = runWithPromise(&ANoExceptWithPromise::member0, &aNoExcept); f = run(&ANoExceptWithPromise::member0, &aNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &ANoExceptWithPromise::member0, &aNoExcept); f = run(&pool, &ANoExceptWithPromise::member0, &aNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&ANoExceptWithPromise::member1, &aNoExcept, 20); f = run(&ANoExceptWithPromise::member1, &aNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20); f = run(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&ANoExceptWithPromise::member0, aNoExcept); f = run(&ANoExceptWithPromise::member0, aNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &ANoExceptWithPromise::member0, aNoExcept); f = run(&pool, &ANoExceptWithPromise::member0, aNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&ANoExceptWithPromise::member1, aNoExcept, 20); f = run(&ANoExceptWithPromise::member1, aNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20); f = run(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(aNoExcept); f = run(aNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, aNoExcept); f = run(&pool, aNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(std::ref(aNoExcept)); f = run(std::ref(aNoExcept));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, std::ref(aNoExcept)); f = run(&pool, std::ref(aNoExcept));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
const AConstNoExceptWithPromise aConstNoExcept = AConstNoExceptWithPromise(); const AConstNoExceptWithPromise aConstNoExcept = AConstNoExceptWithPromise();
f = runWithPromise(&AConstNoExceptWithPromise::member0, &aConstNoExcept); f = run(&AConstNoExceptWithPromise::member0, &aConstNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept); f = run(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20); f = run(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20); f = run(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&AConstNoExceptWithPromise::member0, aConstNoExcept); f = run(&AConstNoExceptWithPromise::member0, aConstNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept); f = run(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20); f = run(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20); f = run(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
QCOMPARE(f.result(), 20); QCOMPARE(f.result(), 20);
f = runWithPromise(aConstNoExcept); f = run(aConstNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, aConstNoExcept); f = run(&pool, aConstNoExcept);
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(std::ref(aConstNoExcept)); f = run(std::ref(aConstNoExcept));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
f = runWithPromise(&pool, std::ref(aConstNoExcept)); f = run(&pool, std::ref(aConstNoExcept));
QCOMPARE(f.result(), 10); QCOMPARE(f.result(), 10);
} }
@ -960,14 +961,14 @@ void tst_QtConcurrentRun::functor()
} }
FunctorWithPromise fWithPromise; FunctorWithPromise fWithPromise;
{ {
QtConcurrent::runWithPromise(fWithPromise, 1.5).waitForFinished(); QtConcurrent::run(fWithPromise, 1.5).waitForFinished();
} }
OverloadedFunctorWithPromise ofWithPromise; OverloadedFunctorWithPromise ofWithPromise;
{ {
QtConcurrent::runWithPromise<int>(ofWithPromise).waitForFinished(); QtConcurrent::run<int>(ofWithPromise).waitForFinished();
QtConcurrent::runWithPromise<double>(ofWithPromise).waitForFinished(); QtConcurrent::run<double>(ofWithPromise).waitForFinished();
QtConcurrent::runWithPromise<int>(ofWithPromise, 1).waitForFinished(); QtConcurrent::run<int>(ofWithPromise, 1).waitForFinished();
QtConcurrent::runWithPromise<double>(ofWithPromise, 1).waitForFinished(); QtConcurrent::run<double>(ofWithPromise, 1).waitForFinished();
} }
// and now with explicit pool: // and now with explicit pool:
QThreadPool pool; QThreadPool pool;
@ -995,13 +996,17 @@ void tst_QtConcurrentRun::functor()
// Compiler supports lambda // Compiler supports lambda
void tst_QtConcurrentRun::lambda() void tst_QtConcurrentRun::lambda()
{ {
QCOMPARE(QtConcurrent::run([](){ return 45; }).result(), 45); QCOMPARE(QtConcurrent::run([]() { return 45; }).result(), 45);
QCOMPARE(QtConcurrent::run([](int a){ return a+15; }, 12).result(), 12+15); QCOMPARE(QtConcurrent::run([](int a) { return a+15; }, 12).result(), 12+15);
QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); QCOMPARE(QtConcurrent::run([](int a, double b) { return a + b; }, 12, 15).result(),
QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); double(12+15));
QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b)
{ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
QCOMPARE(QtConcurrent::runWithPromise([](QPromise<int> &promise){ promise.addResult(45); }).result(), 45); QCOMPARE(QtConcurrent::run([](QPromise<int> &promise)
QCOMPARE(QtConcurrent::runWithPromise([](QPromise<int> &promise, double input){ promise.addResult(input / 2.0); }, 15.0).result(), 7); { promise.addResult(45); }).result(), 45);
QCOMPARE(QtConcurrent::run([](QPromise<int> &promise, double input)
{ promise.addResult(input / 2.0); }, 15.0).result(), 7);
{ {
QString str { "Hello World Foo" }; QString str { "Hello World Foo" };
@ -1012,10 +1017,12 @@ void tst_QtConcurrentRun::lambda()
// and now with explicit pool: // and now with explicit pool:
QThreadPool pool; QThreadPool pool;
QCOMPARE(QtConcurrent::run(&pool, [](){ return 45; }).result(), 45); QCOMPARE(QtConcurrent::run(&pool, []() { return 45; }).result(), 45);
QCOMPARE(QtConcurrent::run(&pool, [](int a){ return a+15; }, 12).result(), 12+15); QCOMPARE(QtConcurrent::run(&pool, [](int a) { return a + 15; }, 12).result(), 12 + 15);
QCOMPARE(QtConcurrent::run(&pool, [](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); QCOMPARE(QtConcurrent::run(&pool, [](int a, double b)
QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); { return a + b; }, 12, 15).result(), double(12 + 15));
QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b)
{ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
{ {
QString str { "Hello World Foo" }; QString str { "Hello World Foo" };
@ -1065,19 +1072,20 @@ void tst_QtConcurrentRun::callableObjectWithState()
CallableWithStateWithPromise oWithPromise; CallableWithStateWithPromise oWithPromise;
// Run method setNewState explicitly // Run method setNewState explicitly
runWithPromise(&CallableWithStateWithPromise::setNewState, &oWithPromise, CallableWithStateWithPromise::defaultState() + 1).waitForFinished(); run(&CallableWithStateWithPromise::setNewState, &oWithPromise,
CallableWithStateWithPromise::defaultState() + 1).waitForFinished();
QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 1); QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 1);
// Run operator()(int) explicitly // Run operator()(int) explicitly
runWithPromise(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished(); run(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished();
QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2); QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2);
// Run on a copy of object (original object remains unchanged) // Run on a copy of object (original object remains unchanged)
runWithPromise(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished(); run(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished();
QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2); QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2);
// Explicitly run on a temporary object // Explicitly run on a temporary object
QCOMPARE(runWithPromise(CallableWithStateWithPromise(), 15).result(), 15); QCOMPARE(run(CallableWithStateWithPromise(), 15).result(), 15);
} }
void report3(QPromise<int> &promise) void report3(QPromise<int> &promise)
@ -1161,40 +1169,40 @@ public:
void tst_QtConcurrentRun::withPromise() void tst_QtConcurrentRun::withPromise()
{ {
// free function pointer // free function pointer
QCOMPARE(runWithPromise(&report3).results(), QCOMPARE(run(&report3).results(),
QList<int>({0, 2, 1})); QList<int>({0, 2, 1}));
QCOMPARE(runWithPromise(report3).results(), QCOMPARE(run(report3).results(),
QList<int>({0, 2, 1})); QList<int>({0, 2, 1}));
QCOMPARE(runWithPromise(reportN, 4).results(), QCOMPARE(run(reportN, 4).results(),
QList<double>({0, 0, 0, 0})); QList<double>({0, 0, 0, 0}));
QCOMPARE(runWithPromise(reportN, 2).results(), QCOMPARE(run(reportN, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
QString s = QLatin1String("string"); QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string"); const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string"); const QString cs = QLatin1String("c string");
QCOMPARE(runWithPromise(reportString1, s).results(), QCOMPARE(run(reportString1, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(reportString1, crs).results(), QCOMPARE(run(reportString1, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(reportString1, cs).results(), QCOMPARE(run(reportString1, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(reportString1, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(reportString1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(runWithPromise(reportString2, s).results(), QCOMPARE(run(reportString2, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(reportString2, crs).results(), QCOMPARE(run(reportString2, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(reportString2, cs).results(), QCOMPARE(run(reportString2, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(reportString2, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(reportString2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda // lambda
QCOMPARE(runWithPromise([](QPromise<double> &promise, int n) { QCOMPARE(run([](QPromise<double> &promise, int n) {
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
promise.addResult(0); promise.addResult(0);
}, 3).results(), }, 3).results(),
@ -1205,46 +1213,46 @@ void tst_QtConcurrentRun::withPromise()
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
promise.addResult(0); promise.addResult(0);
}; };
QCOMPARE(runWithPromise(fun, 2).results(), QCOMPARE(run(fun, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
// operator() // operator()
QCOMPARE(runWithPromise(Callable(), 3).results(), QCOMPARE(run(Callable(), 3).results(),
QList<double>({0, 0, 0})); QList<double>({0, 0, 0}));
const Callable c{}; const Callable c{};
QCOMPARE(runWithPromise(c, 2).results(), QCOMPARE(run(c, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
// static member functions // static member functions
QCOMPARE(runWithPromise(&MyObject::staticMember0).results(), QCOMPARE(run(&MyObject::staticMember0).results(),
QList<double>({0, 2, 1})); QList<double>({0, 2, 1}));
QCOMPARE(runWithPromise(&MyObject::staticMember1, 2).results(), QCOMPARE(run(&MyObject::staticMember1, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
// member functions // member functions
const MyObject obj{}; const MyObject obj{};
QCOMPARE(runWithPromise(&MyObject::member0, &obj).results(), QCOMPARE(run(&MyObject::member0, &obj).results(),
QList<double>({0, 2, 1})); QList<double>({0, 2, 1}));
QCOMPARE(runWithPromise(&MyObject::member1, &obj, 4).results(), QCOMPARE(run(&MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0})); QList<double>({0, 0, 0, 0}));
QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, s).results(), QCOMPARE(run(&MyObject::memberString1, &obj, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, crs).results(), QCOMPARE(run(&MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, cs).results(), QCOMPARE(run(&MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, s).results(), QCOMPARE(run(&MyObject::memberString2, &obj, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, crs).results(), QCOMPARE(run(&MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, cs).results(), QCOMPARE(run(&MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
MyObject nonConstObj{}; MyObject nonConstObj{};
QCOMPARE(runWithPromise(&MyObject::nonConstMember, &nonConstObj).results(), QCOMPARE(run(&MyObject::nonConstMember, &nonConstObj).results(),
QList<double>({0, 2, 1})); QList<double>({0, 2, 1}));
} }
@ -1252,40 +1260,40 @@ void tst_QtConcurrentRun::withPromiseInThreadPool()
{ {
QScopedPointer<QThreadPool> pool(new QThreadPool); QScopedPointer<QThreadPool> pool(new QThreadPool);
// free function pointer // free function pointer
QCOMPARE(runWithPromise(pool.data(), &report3).results(), QCOMPARE(run(pool.data(), &report3).results(),
QList<int>({0, 2, 1})); QList<int>({0, 2, 1}));
QCOMPARE(runWithPromise(pool.data(), report3).results(), QCOMPARE(run(pool.data(), report3).results(),
QList<int>({0, 2, 1})); QList<int>({0, 2, 1}));
QCOMPARE(runWithPromise(pool.data(), reportN, 4).results(), QCOMPARE(run(pool.data(), reportN, 4).results(),
QList<double>({0, 0, 0, 0})); QList<double>({0, 0, 0, 0}));
QCOMPARE(runWithPromise(pool.data(), reportN, 2).results(), QCOMPARE(run(pool.data(), reportN, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
QString s = QLatin1String("string"); QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string"); const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string"); const QString cs = QLatin1String("c string");
QCOMPARE(runWithPromise(pool.data(), reportString1, s).results(), QCOMPARE(run(pool.data(), reportString1, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(pool.data(), reportString1, crs).results(), QCOMPARE(run(pool.data(), reportString1, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(pool.data(), reportString1, cs).results(), QCOMPARE(run(pool.data(), reportString1, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(runWithPromise(pool.data(), reportString2, s).results(), QCOMPARE(run(pool.data(), reportString2, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(pool.data(), reportString2, crs).results(), QCOMPARE(run(pool.data(), reportString2, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(pool.data(), reportString2, cs).results(), QCOMPARE(run(pool.data(), reportString2, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda // lambda
QCOMPARE(runWithPromise(pool.data(), [](QPromise<double> &promise, int n) { QCOMPARE(run(pool.data(), [](QPromise<double> &promise, int n) {
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
promise.addResult(0); promise.addResult(0);
}, 3).results(), }, 3).results(),
@ -1296,43 +1304,45 @@ void tst_QtConcurrentRun::withPromiseInThreadPool()
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
promise.addResult(0); promise.addResult(0);
}; };
QCOMPARE(runWithPromise(pool.data(), fun, 2).results(), QCOMPARE(run(pool.data(), fun, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
// operator() // operator()
QCOMPARE(runWithPromise(pool.data(), Callable(), 3).results(), QCOMPARE(run(pool.data(), Callable(), 3).results(),
QList<double>({0, 0, 0})); QList<double>({0, 0, 0}));
const Callable c{}; const Callable c{};
QCOMPARE(runWithPromise(pool.data(), c, 2).results(), QCOMPARE(run(pool.data(), c, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
// static member functions // static member functions
QCOMPARE(runWithPromise(pool.data(), &MyObject::staticMember0).results(), QCOMPARE(run(pool.data(), &MyObject::staticMember0).results(),
QList<double>({0, 2, 1})); QList<double>({0, 2, 1}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::staticMember1, 2).results(), QCOMPARE(run(pool.data(), &MyObject::staticMember1, 2).results(),
QList<double>({0, 0})); QList<double>({0, 0}));
// member functions // member functions
const MyObject obj{}; const MyObject obj{};
QCOMPARE(runWithPromise(pool.data(), &MyObject::member0, &obj).results(), QCOMPARE(run(pool.data(), &MyObject::member0, &obj).results(),
QList<double>({0, 2, 1})); QList<double>({0, 2, 1}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::member1, &obj, 4).results(), QCOMPARE(run(pool.data(), &MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0})); QList<double>({0, 0, 0, 0}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, s).results(), QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, crs).results(), QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, cs).results(), QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj,
QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, s).results(), QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, s).results(),
QList<QString>({s})); QList<QString>({s}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, crs).results(), QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs})); QList<QString>({crs}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, cs).results(), QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs})); QList<QString>({cs}));
QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(), QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj,
QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))})); QList<QString>({QString(QLatin1String("rvalue"))}));
} }
@ -1357,44 +1367,92 @@ public:
void tst_QtConcurrentRun::moveOnlyType() void tst_QtConcurrentRun::moveOnlyType()
{ {
QCOMPARE(runWithPromise(MoveOnlyCallable(), MoveOnlyType()).results(), QCOMPARE(run(MoveOnlyCallable(), MoveOnlyType()).results(),
QList<int>({1})); QList<int>({1}));
} }
void tst_QtConcurrentRun::crefFunction() void tst_QtConcurrentRun::crefFunction()
{ {
// free function pointer with promise {
auto fun = &report3; // free function pointer with promise
QCOMPARE(runWithPromise(std::cref(fun)).results(), auto fun = &returnInt0;
QList<int>({0, 2, 1})); QCOMPARE(run(std::cref(fun)).result(), 10);
// lambda with promise // lambda with promise
auto lambda = [](QPromise<double> &promise, int n) { auto lambda = [](int n) {
for (int i = 0; i < n; ++i) return 2 * n;
promise.addResult(0); };
}; QCOMPARE(run(std::cref(lambda), 3).result(), 6);
QCOMPARE(runWithPromise(std::cref(lambda), 3).results(),
QList<double>({0, 0, 0}));
// std::function with promise // std::function with promise
const std::function<void(QPromise<double> &, int)> funObj = [](QPromise<double> &promise, int n) { const std::function<int(int)> funObj = [](int n) {
for (int i = 0; i < n; ++i) return 2 * n;
promise.addResult(0); };
}; QCOMPARE(run(std::cref(funObj), 2).result(), 4);
QCOMPARE(runWithPromise(std::cref(funObj), 2).results(),
QList<double>({0, 0}));
// callable with promise // callable with promise
const Callable c{}; const AConst c{};
QCOMPARE(runWithPromise(std::cref(c), 2).results(), QCOMPARE(run(std::cref(c), 2).result(), 2);
QList<double>({0, 0}));
// member functions with promise // member functions with promise
auto member = &MyObject::member0; auto member = &AConst::member0;
const MyObject obj{}; const AConst obj{};
QCOMPARE(runWithPromise(std::cref(member), &obj).results(), QCOMPARE(run(std::cref(member), &obj).result(), 10);
QList<double>({0, 2, 1})); }
{
// free function pointer with promise
auto fun = &report3;
QCOMPARE(run(std::cref(fun)).results(),
QList<int>({0, 2, 1}));
// lambda with promise
auto lambda = [](QPromise<double> &promise, int n) {
for (int i = 0; i < n; ++i)
promise.addResult(0);
};
QCOMPARE(run(std::cref(lambda), 3).results(),
QList<double>({0, 0, 0}));
// std::function with promise
const std::function<void(QPromise<double> &, int)> funObj =
[](QPromise<double> &promise, int n) {
for (int i = 0; i < n; ++i)
promise.addResult(0);
};
QCOMPARE(run(std::cref(funObj), 2).results(),
QList<double>({0, 0}));
// callable with promise
const Callable c{};
QCOMPARE(run(std::cref(c), 2).results(),
QList<double>({0, 0}));
// member functions with promise
auto member = &MyObject::member0;
const MyObject obj{};
QCOMPARE(run(std::cref(member), &obj).results(),
QList<double>({0, 2, 1}));
}
} }
int explicitPromise(QPromise<int> &promise, int &i)
{
promise.setProgressRange(-10, 10);
++i;
return i * 2;
}
void tst_QtConcurrentRun::customPromise()
{
QPromise<int> p;
int i = 4;
QCOMPARE(QtConcurrent::run(explicitPromise, std::ref(p), std::ref(i)).result(), 10);
QCOMPARE(i, 5);
QCOMPARE(p.future().progressMinimum(), -10);
QCOMPARE(p.future().progressMaximum(), 10);
}
QTEST_MAIN(tst_QtConcurrentRun) QTEST_MAIN(tst_QtConcurrentRun)
#include "tst_qtconcurrentrun.moc" #include "tst_qtconcurrentrun.moc"