QtConcurrent: prevent conversion of ReduceOption to initial value

QtConcurrent map- and filter-reduce functions take an initial value,
which can be of any type that is convertable to the result type. The
side-effect of this is that the enum values passed as ReduceOptions can
be treated as an initial value (if they are convertable to the result
type) which will result into a wrong overload call. To avoid this, added
additional check to make sure that the initial value type doesn't match
with ReduceOption enum.

Note that this required including the qtconcurrentreducekernel.h header
in qtconcurrentfunctionwrappers.h (which contains compiler checks for
QtConcurrent) for accessing ReduceOption enum, so I had to get rid of
qtconcurrentfunctionwrappers.h include from qtconcurrentreducekernel.h
to avoid circular header includes. This, in turn, required moving the
QtPrivate::SequenceHolder helper type to qtconcurrentreducekernel.h,
which didn't belong to qtconcurrentfunctionwrappers.h anyway.

Pick-to: 6.3 6.2
Fixes: QTBUG-102999
Change-Id: Ieaa8ef2e4bd82ce2ada2e0af9a47b87b51d59e87
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
Sona Kurazyan 2022-05-18 17:28:12 +02:00
parent fa01e0bd71
commit bd1023a824
6 changed files with 178 additions and 41 deletions

View File

@ -73,7 +73,8 @@ template <typename ResultType, typename Sequence, typename KeepFunctor, typename
#else
template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> filteredReduced(QThreadPool *pool,
Sequence &&sequence,
@ -95,7 +96,8 @@ template <typename ResultType, typename Sequence, typename KeepFunctor, typename
#else
template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> filteredReduced(Sequence &&sequence,
KeepFunctor &&keep,
@ -144,7 +146,8 @@ template <typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<KeepFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
QFuture<ResultType> filteredReduced(QThreadPool *pool,
Sequence &&sequence,
KeepFunctor &&keep,
@ -163,7 +166,8 @@ template <typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<KeepFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
QFuture<ResultType> filteredReduced(Sequence &&sequence,
KeepFunctor &&keep,
ReduceFunctor &&reduce,
@ -211,7 +215,8 @@ template <typename ResultType, typename Iterator, typename KeepFunctor, typename
#else
template <typename ResultType, typename Iterator, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> filteredReduced(QThreadPool *pool,
Iterator begin,
@ -233,7 +238,8 @@ template <typename ResultType, typename Iterator, typename KeepFunctor, typename
#else
template <typename ResultType, typename Iterator, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> filteredReduced(Iterator begin,
Iterator end,
@ -281,7 +287,8 @@ QFuture<ResultType> filteredReduced(Iterator begin,
template <typename Iterator, typename KeepFunctor, typename ReduceFunctor,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
QFuture<ResultType> filteredReduced(QThreadPool *pool,
Iterator begin,
Iterator end,
@ -300,7 +307,8 @@ template <typename Iterator, typename KeepFunctor, typename ReduceFunctor,
std::enable_if_t<QtPrivate::isIterator_v<Iterator>, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
QFuture<ResultType> filteredReduced(Iterator begin,
Iterator end,
KeepFunctor &&keep,
@ -400,7 +408,8 @@ template <typename ResultType, typename Sequence, typename KeepFunctor, typename
#else
template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingFilteredReduced(QThreadPool *pool,
Sequence &&sequence,
@ -423,7 +432,8 @@ template <typename ResultType, typename Sequence, typename KeepFunctor, typename
#else
template <typename ResultType, typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingFilteredReduced(Sequence &&sequence,
KeepFunctor &&keep,
@ -475,7 +485,8 @@ template <typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<KeepFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
ResultType blockingFilteredReduced(QThreadPool *pool,
Sequence &&sequence,
KeepFunctor &&keep,
@ -495,7 +506,8 @@ template <typename Sequence, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<KeepFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
ResultType blockingFilteredReduced(Sequence &&sequence,
KeepFunctor &&keep,
ReduceFunctor &&reduce,
@ -547,7 +559,8 @@ template <typename ResultType, typename Iterator, typename KeepFunctor, typename
#else
template <typename ResultType, typename Iterator, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingFilteredReduced(QThreadPool *pool,
Iterator begin,
@ -570,7 +583,8 @@ template <typename ResultType, typename Iterator, typename KeepFunctor, typename
#else
template <typename ResultType, typename Iterator, typename KeepFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingFilteredReduced(Iterator begin,
Iterator end,
@ -621,7 +635,8 @@ ResultType blockingFilteredReduced(Iterator begin,
template <typename Iterator, typename KeepFunctor, typename ReduceFunctor,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
ResultType blockingFilteredReduced(QThreadPool *pool,
Iterator begin,
Iterator end, KeepFunctor &&keep,
@ -640,7 +655,8 @@ template <typename Iterator, typename KeepFunctor, typename ReduceFunctor,
std::enable_if_t<QtPrivate::isIterator_v<Iterator>, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
ResultType blockingFilteredReduced(Iterator begin,
Iterator end,
KeepFunctor &&keep,

View File

@ -5,6 +5,7 @@
#define QTCONCURRENT_FUNCTIONWRAPPERS_H
#include <QtConcurrent/qtconcurrentcompilertest.h>
#include <QtConcurrent/qtconcurrentreducekernel.h>
#include <QtCore/qfuture.h>
#include <tuple>
@ -121,6 +122,11 @@ inline constexpr bool isIterator_v<T, std::void_t<typename std::iterator_traits<
template <class Callable, class Sequence>
using isInvocable = std::is_invocable<Callable, typename std::decay_t<Sequence>::value_type>;
template <class InitialValueType, class ResultType>
inline constexpr bool isInitialValueCompatible_v = std::conjunction_v<
std::is_convertible<InitialValueType, ResultType>,
std::negation<std::is_same<std::decay_t<InitialValueType>, QtConcurrent::ReduceOption>>>;
template<class Callable, class Enable = void>
struct ReduceResultTypeHelper
{
@ -163,14 +169,6 @@ struct MapSequenceResultType<InputSequence<T...>, MapFunctor>
#endif // QT_NO_TEMPLATE_TEMPLATE_PARAMETER
template<typename Sequence>
struct SequenceHolder
{
SequenceHolder(const Sequence &s) : sequence(s) { }
SequenceHolder(Sequence &&s) : sequence(std::move(s)) { }
Sequence sequence;
};
} // namespace QtPrivate.

View File

@ -77,7 +77,8 @@ template <typename ResultType, typename Sequence, typename MapFunctor, typename
#else
template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(QThreadPool *pool,
Sequence &&sequence,
@ -98,7 +99,8 @@ template <typename ResultType, typename Sequence, typename MapFunctor, typename
#else
template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(Sequence &&sequence,
MapFunctor &&map,
@ -149,7 +151,8 @@ template <typename Sequence, typename MapFunctor, typename ReduceFunctor, typena
template <typename Sequence, typename MapFunctor, typename ReduceFunctor, typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<MapFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(QThreadPool *pool,
Sequence &&sequence,
@ -172,7 +175,8 @@ template <typename Sequence, typename MapFunctor, typename ReduceFunctor, typena
template <typename Sequence, typename MapFunctor, typename ReduceFunctor, typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<MapFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(Sequence &&sequence,
MapFunctor &&map,
@ -221,7 +225,8 @@ template <typename ResultType, typename Iterator, typename MapFunctor, typename
#else
template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(QThreadPool *pool,
Iterator begin,
@ -243,7 +248,8 @@ template <typename ResultType, typename Iterator, typename MapFunctor, typename
#else
template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(Iterator begin,
Iterator end,
@ -295,7 +301,8 @@ template <typename Iterator, typename MapFunctor, typename ReduceFunctor, typena
template <typename Iterator, typename MapFunctor, typename ReduceFunctor,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(QThreadPool *pool,
Iterator begin,
@ -319,7 +326,8 @@ template<typename Iterator, typename MapFunctor, typename ReduceFunctor,
std::enable_if_t<QtPrivate::isIterator_v<Iterator>, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
QFuture<ResultType> mappedReduced(Iterator begin,
Iterator end,
@ -447,7 +455,8 @@ template <typename ResultType, typename Sequence, typename MapFunctor, typename
#else
template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(QThreadPool *pool,
Sequence &&sequence,
@ -470,7 +479,8 @@ template <typename ResultType, typename Sequence, typename MapFunctor, typename
#else
template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(Sequence &&sequence,
MapFunctor &&map,
@ -526,7 +536,8 @@ template <typename MapFunctor, typename ReduceFunctor, typename Sequence, typena
template <typename MapFunctor, typename ReduceFunctor, typename Sequence, typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<MapFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(QThreadPool *pool,
Sequence &&sequence,
@ -550,7 +561,8 @@ template <typename MapFunctor, typename ReduceFunctor, typename Sequence, typena
template<typename MapFunctor, typename ReduceFunctor, typename Sequence, typename InitialValueType,
std::enable_if_t<QtPrivate::isInvocable<MapFunctor, Sequence>::value, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(Sequence &&sequence,
MapFunctor &&map,
@ -602,7 +614,8 @@ template <typename ResultType, typename Iterator, typename MapFunctor, typename
#else
template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(QThreadPool *pool,
Iterator begin,
@ -626,7 +639,8 @@ template <typename ResultType, typename Iterator, typename MapFunctor, typename
#else
template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(Iterator begin,
Iterator end,
@ -681,7 +695,8 @@ template <typename Iterator, typename MapFunctor, typename ReduceFunctor, typena
template <typename Iterator, typename MapFunctor, typename ReduceFunctor,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(QThreadPool *pool,
Iterator begin,
@ -706,7 +721,8 @@ template <typename Iterator, typename MapFunctor, typename ReduceFunctor,
std::enable_if_t<QtPrivate::isIterator_v<Iterator>, int> = 0,
typename ResultType = typename QtPrivate::ReduceResultTypeHelper<ReduceFunctor>::type,
typename InitialValueType,
std::enable_if_t<std::is_convertible_v<InitialValueType, ResultType>, int> = 0>
std::enable_if_t<QtPrivate::isInitialValueCompatible_v<InitialValueType, ResultType>,
int> = 0>
#endif
ResultType blockingMappedReduced(Iterator begin,
Iterator end,

View File

@ -5,7 +5,6 @@
#define QTCONCURRENT_REDUCEKERNEL_H
#include <QtConcurrent/qtconcurrent_global.h>
#include <QtConcurrent/qtconcurrentfunctionwrappers.h>
#if !defined(QT_NO_CONCURRENT) || defined(Q_CLANG_QDOC)
@ -20,6 +19,17 @@
QT_BEGIN_NAMESPACE
namespace QtPrivate {
template<typename Sequence>
struct SequenceHolder
{
SequenceHolder(const Sequence &s) : sequence(s) { }
SequenceHolder(Sequence &&s) : sequence(std::move(s)) { }
Sequence sequence;
};
}
namespace QtConcurrent {

View File

@ -27,6 +27,7 @@ private slots:
void filteredReducedInitialValueThreadPool();
void filteredReducedInitialValueWithMoveOnlyCallables();
void filteredReducedDifferentTypeInitialValue();
void filteredReduceOptionConvertableToResultType();
void resultAt();
void incrementalResults();
void noDetach();
@ -1338,6 +1339,56 @@ void tst_QtConcurrentFilter::filteredReducedDifferentTypeInitialValue()
CHECK_FAIL("lambda-lambda");
}
void tst_QtConcurrentFilter::filteredReduceOptionConvertableToResultType()
{
const QList<int> intList { 1, 2, 3 };
const int sum = 4;
QThreadPool p;
ReduceOption ro = OrderedReduce;
// With container
QCOMPARE(QtConcurrent::filteredReduced(intList, keepOddIntegers, intSumReduce, ro).result(),
sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced(intList, keepOddIntegers, intSumReduce, ro),
sum);
// With iterators
QCOMPARE(QtConcurrent::filteredReduced(intList.begin(), intList.end(), keepOddIntegers,
intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced(intList.begin(), intList.end(), keepOddIntegers,
intSumReduce, ro), sum);
// With custom QThreadPool;
QCOMPARE(QtConcurrent::filteredReduced(&p, intList, keepOddIntegers, intSumReduce, ro).result(),
sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced(&p, intList, keepOddIntegers, intSumReduce, ro),
sum);
QCOMPARE(QtConcurrent::filteredReduced(&p, intList.begin(), intList.end(), keepOddIntegers,
intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced(&p, intList.begin(), intList.end(),
keepOddIntegers, intSumReduce, ro), sum);
// The same as above, but specify the result type explicitly (this invokes different overloads)
QCOMPARE(QtConcurrent::filteredReduced<int>(intList, keepOddIntegers, intSumReduce,
ro).result(), sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced<int>(intList, keepOddIntegers, intSumReduce, ro),
sum);
QCOMPARE(QtConcurrent::filteredReduced<int>(intList.begin(), intList.end(), keepOddIntegers,
intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced<int>(intList.begin(), intList.end(),
keepOddIntegers, intSumReduce, ro), sum);
QCOMPARE(QtConcurrent::filteredReduced<int>(&p, intList, keepOddIntegers, intSumReduce,
ro).result(), sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced<int>(&p, intList, keepOddIntegers, intSumReduce,
ro), sum);
QCOMPARE(QtConcurrent::filteredReduced<int>(&p, intList.begin(), intList.end(), keepOddIntegers,
intSumReduce, ro).result(),sum);
QCOMPARE(QtConcurrent::blockingFilteredReduced<int>(&p, intList.begin(), intList.end(),
keepOddIntegers, intSumReduce, ro), sum);
}
bool filterfn(int i)
{
return (i % 2);

View File

@ -30,6 +30,7 @@ private slots:
void mappedReducedInitialValueThreadPool();
void mappedReducedInitialValueWithMoveOnlyCallable();
void mappedReducedDifferentTypeInitialValue();
void mappedReduceOptionConvertableToResultType();
void assignResult();
void functionOverloads();
void noExceptFunctionOverloads();
@ -1605,6 +1606,51 @@ void tst_QtConcurrentMap::mappedReducedDifferentTypeInitialValue()
CHECK_FAIL("lambda-lambda");
}
void tst_QtConcurrentMap::mappedReduceOptionConvertableToResultType()
{
const QList<int> intList { 1, 2, 3 };
const int sum = 12;
QThreadPool p;
ReduceOption ro = OrderedReduce;
// With container
QCOMPARE(QtConcurrent::mappedReduced(intList, multiplyBy2, intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingMappedReduced(intList, multiplyBy2, intSumReduce, ro), sum);
// With iterators
QCOMPARE(QtConcurrent::mappedReduced(intList.begin(), intList.end(), multiplyBy2, intSumReduce,
ro).result(), sum);
QCOMPARE(QtConcurrent::blockingMappedReduced(intList.begin(), intList.end(), multiplyBy2,
intSumReduce, ro), sum);
// With custom QThreadPool;
QCOMPARE(QtConcurrent::mappedReduced(&p, intList, multiplyBy2, intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingMappedReduced(&p, intList, multiplyBy2, intSumReduce, ro), sum);
QCOMPARE(QtConcurrent::mappedReduced(&p, intList.begin(), intList.end(), multiplyBy2,
intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingMappedReduced(&p, intList.begin(), intList.end(), multiplyBy2,
intSumReduce, ro), sum);
// The same as above, but specify the result type explicitly (this invokes different overloads)
QCOMPARE(QtConcurrent::mappedReduced<int>(intList, multiplyBy2, intSumReduce, ro).result(),
sum);
QCOMPARE(QtConcurrent::blockingMappedReduced<int>(intList, multiplyBy2, intSumReduce, ro), sum);
QCOMPARE(QtConcurrent::mappedReduced<int>(intList.begin(), intList.end(), multiplyBy2,
intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingMappedReduced<int>(intList.begin(), intList.end(), multiplyBy2,
intSumReduce, ro), sum);
QCOMPARE(QtConcurrent::mappedReduced<int>(&p, intList, multiplyBy2, intSumReduce, ro).result(),
sum);
QCOMPARE(QtConcurrent::blockingMappedReduced<int>(&p, intList, multiplyBy2, intSumReduce, ro),
sum);
QCOMPARE(QtConcurrent::mappedReduced<int>(&p, intList.begin(), intList.end(), multiplyBy2,
intSumReduce, ro).result(), sum);
QCOMPARE(QtConcurrent::blockingMappedReduced<int>(&p, intList.begin(), intList.end(),
multiplyBy2, intSumReduce, ro), sum);
}
int sleeper(int val)
{
QTest::qSleep(100);