diff options
Diffstat (limited to 'tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp')
-rw-r--r-- | tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp | 748 |
1 files changed, 590 insertions, 158 deletions
diff --git a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp index 06446321b3..3e3165013f 100644 --- a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp +++ b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp @@ -1,38 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qtconcurrentmap.h> #include <qexception.h> - #include <qdebug.h> + #include <QThread> #include <QMutex> - -#include <QtTest/QtTest> +#include <QTest> +#include <QSet> +#include <QRandomGenerator> #include "../testhelper_functions.h" @@ -45,12 +21,16 @@ private slots: void mapOnRvalue(); void mapped(); void mappedThreadPool(); + void mappedWithMoveOnlyCallable(); void mappedReduced(); void mappedReducedThreadPool(); + void mappedReducedWithMoveOnlyCallable(); void mappedReducedDifferentType(); void mappedReducedInitialValue(); void mappedReducedInitialValueThreadPool(); + void mappedReducedInitialValueWithMoveOnlyCallable(); void mappedReducedDifferentTypeInitialValue(); + void mappedReduceOptionConvertableToResultType(); void assignResult(); void functionOverloads(); void noExceptFunctionOverloads(); @@ -70,7 +50,7 @@ public slots: using namespace QtConcurrent; -void multiplyBy2Immutable(int x) +void multiplyBy2Immutable([[maybe_unused]] int x) { x *= 2; } @@ -78,7 +58,7 @@ void multiplyBy2Immutable(int x) class MultiplyBy2Immutable { public: - void operator()(int x) + void operator()([[maybe_unused]] int x) { x *= 2; } @@ -98,6 +78,19 @@ public: } }; +class MultiplyBy2InPlaceMoveOnly +{ +public: + MultiplyBy2InPlaceMoveOnly() = default; + MultiplyBy2InPlaceMoveOnly(MultiplyBy2InPlaceMoveOnly &&) = default; + MultiplyBy2InPlaceMoveOnly &operator=(MultiplyBy2InPlaceMoveOnly &&other) = default; + + MultiplyBy2InPlaceMoveOnly(const MultiplyBy2InPlaceMoveOnly &) = delete; + MultiplyBy2InPlaceMoveOnly &operator=(const MultiplyBy2InPlaceMoveOnly &) = delete; + + void operator()(int &x) { x *= 2; } +}; + Q_DECLARE_METATYPE(QList<Number>); void tst_QtConcurrentMap::map() @@ -138,6 +131,12 @@ void tst_QtConcurrentMap::map() QCOMPARE(list, QList<int>() << 128 << 256 << 384); QtConcurrent::map(list.begin(), list.end(), [](int &x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 256 << 512 << 768); + + // move-only functor + QtConcurrent::map(list, MultiplyBy2InPlaceMoveOnly()).waitForFinished(); + QCOMPARE(list, QList<int>() << 512 << 1024 << 1536); + QtConcurrent::map(list.begin(), list.end(), MultiplyBy2InPlaceMoveOnly()).waitForFinished(); + QCOMPARE(list, QList<int>() << 1024 << 2048 << 3072); } // functors don't take arguments by reference, making these no-ops @@ -164,19 +163,37 @@ void tst_QtConcurrentMap::map() QCOMPARE(list, QList<int>() << 1 << 2 << 3); // lambda - QtConcurrent::map(list, [](int x){x *= 2;}).waitForFinished(); + QtConcurrent::map(list, []([[maybe_unused]] int x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 1 << 2 << 3); - QtConcurrent::map(list.begin(), list.end(), [](int x){x *= 2;}).waitForFinished(); + QtConcurrent::map(list.begin(), list.end(), []([[maybe_unused]] int x){x *= 2;}).waitForFinished(); QCOMPARE(list, QList<int>() << 1 << 2 << 3); } // functors take arguments by reference, modifying the move-only sequence in place { - MoveOnlyVector moveOnlyVector({ 1, 2, 3 }); + MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 }); // functor QtConcurrent::map(moveOnlyVector, MultiplyBy2InPlace()).waitForFinished(); - QCOMPARE(moveOnlyVector, MoveOnlyVector({ 2, 4, 6 })); + QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 })); + } + + // non-template sequences + { + NonTemplateSequence list { 1, 2, 3 }; + QtConcurrent::map(list, multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, NonTemplateSequence({ 2, 4, 6 })); + } + + // custom pool with invalid number of threads + { + QList<int> list; + list << 1 << 2 << 3; + QThreadPool pool; + pool.setMaxThreadCount(0); // explicitly set incorrect value + // This should not crash + QtConcurrent::map(&pool, list, MultiplyBy2InPlace()).waitForFinished(); + QCOMPARE(list, QList<int>() << 2 << 4 << 6); } #if 0 @@ -209,7 +226,7 @@ void tst_QtConcurrentMap::map() #if 0 // not allowed: map() on a const list, where functors try to modify the items in the list { - const QList<int> list = QList<int>() << 1 << 2 << 3;; + const QList<int> list = QList<int>() << 1 << 2 << 3; QtConcurrent::map(list, MultiplyBy2InPlace()); QtConcurrent::map(list, multiplyBy2InPlace); @@ -259,18 +276,24 @@ void tst_QtConcurrentMap::blockingMap() QCOMPARE(list, QList<int>() << 128 << 256 << 384); QtConcurrent::blockingMap(list.begin(), list.end(), [](int &x) { x *= 2; }); QCOMPARE(list, QList<int>() << 256 << 512 << 768); + + // move-only functor + QtConcurrent::blockingMap(list, MultiplyBy2InPlaceMoveOnly()); + QCOMPARE(list, QList<int>() << 512 << 1024 << 1536); + QtConcurrent::blockingMap(list.begin(), list.end(), MultiplyBy2InPlaceMoveOnly()); + QCOMPARE(list, QList<int>() << 1024 << 2048 << 3072); } // functors take arguments by reference, modifying the move-only sequence in place { - MoveOnlyVector moveOnlyVector({ 1, 2, 3 }); + MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 }); // functor QtConcurrent::blockingMap(moveOnlyVector, MultiplyBy2InPlace()); - QCOMPARE(moveOnlyVector, MoveOnlyVector({ 2, 4, 6 })); + QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 })); QtConcurrent::blockingMap(moveOnlyVector.begin(), moveOnlyVector.end(), MultiplyBy2InPlace()); - QCOMPARE(moveOnlyVector, MoveOnlyVector({ 4, 8, 12 })); + QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 4, 8, 12 })); } // functors don't take arguments by reference, making these no-ops @@ -297,12 +320,19 @@ void tst_QtConcurrentMap::blockingMap() QCOMPARE(list, QList<int>() << 1 << 2 << 3); // lambda - QtConcurrent::blockingMap(list, [](int x) { x *= 2; }); + QtConcurrent::blockingMap(list, []([[maybe_unused]] int x) { x *= 2; }); QCOMPARE(list, QList<int>() << 1 << 2 << 3); - QtConcurrent::blockingMap(list.begin(), list.end(), [](int x) { x *= 2; }); + QtConcurrent::blockingMap(list.begin(), list.end(), []([[maybe_unused]] int x) { x *= 2; }); QCOMPARE(list, QList<int>() << 1 << 2 << 3); } + // non-template sequences + { + NonTemplateSequence list { 1, 2, 3 }; + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + QCOMPARE(list, NonTemplateSequence({ 2, 4, 6 })); + } + #if 0 // not allowed: map() with immutable sequences makes no sense { @@ -333,7 +363,7 @@ void tst_QtConcurrentMap::blockingMap() #if 0 // not allowed: map() on a const list, where functors try to modify the items in the list { - const QList<int> list = QList<int>() << 1 << 2 << 3;; + const QList<int> list = QList<int>() << 1 << 2 << 3; QtConcurrent::blockingMap(list, MultiplyBy2InPlace()); QtConcurrent::blockingMap(list, multiplyBy2InPlace); @@ -409,6 +439,23 @@ public: } }; +class MultiplyBy2MoveOnly +{ +public: + MultiplyBy2MoveOnly() = default; + MultiplyBy2MoveOnly(MultiplyBy2MoveOnly &&) = default; + MultiplyBy2MoveOnly &operator=(MultiplyBy2MoveOnly &&other) = default; + + MultiplyBy2MoveOnly(const MultiplyBy2MoveOnly &) = delete; + MultiplyBy2MoveOnly &operator=(const MultiplyBy2MoveOnly &) = delete; + + int operator()(int x) const + { + int y = x * 2; + return y; + } +}; + double intToDouble(int x) { return double(x); @@ -519,22 +566,32 @@ void tst_QtConcurrentMap::mapped() #endif { + // non-template sequences + NonTemplateSequence list { 1, 2, 3 }; + + auto future = QtConcurrent::mapped(list, multiplyBy2); + QCOMPARE(future.results(), QList({ 2, 4, 6 })); + + auto result = QtConcurrent::blockingMapped(list, multiplyBy2); + QCOMPARE(result, NonTemplateSequence({ 2, 4, 6 })); + } + + { // rvalue sequences auto future = QtConcurrent::mapped(std::vector { 1, 2, 3 }, multiplyBy2); QCOMPARE(future.results(), QList<int>({ 2, 4, 6 })); - auto result = QtConcurrent::blockingMapped<std::vector<int>>(std::vector { 1, 2, 3 }, - multiplyBy2); + auto result = QtConcurrent::blockingMapped(std::vector { 1, 2, 3 }, multiplyBy2); QCOMPARE(result, std::vector<int>({ 2, 4, 6 })); } { // move only sequences - auto future = QtConcurrent::mapped(MoveOnlyVector({ 1, 2, 3 }), multiplyBy2); + auto future = QtConcurrent::mapped(MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2); QCOMPARE(future.results(), QList<int>({ 2, 4, 6 })); - auto result = QtConcurrent::blockingMapped<std::vector<int>>(MoveOnlyVector({ 1, 2, 3 }), - multiplyBy2); + auto result = QtConcurrent::blockingMapped<std::vector<int>>( + MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2); QCOMPARE(result, std::vector<int>({ 2, 4, 6 })); } } @@ -623,6 +680,17 @@ void tst_QtConcurrentMap::mappedThreadPool() CHECK_FAIL("lambda"); { + // non-template sequences + NonTemplateSequence list { 1, 2, 3 }; + + auto future = QtConcurrent::mapped(&pool, list, multiplyBy2); + QCOMPARE(future.results(), QList({ 2, 4, 6 })); + + auto result = QtConcurrent::blockingMapped(&pool, list, multiplyBy2); + QCOMPARE(result, NonTemplateSequence({ 2, 4, 6 })); + } + + { // rvalue sequences auto future = QtConcurrent::mapped(&pool, std::vector { 1, 2, 3 }, multiplyBy2); QCOMPARE(future.results(), QList<int>({ 2, 4, 6 })); @@ -633,15 +701,59 @@ void tst_QtConcurrentMap::mappedThreadPool() } { // move only sequences - auto future = QtConcurrent::mapped(&pool, MoveOnlyVector({ 1, 2, 3 }), multiplyBy2); + auto future = QtConcurrent::mapped(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2); QCOMPARE(future.results(), QList<int>({ 2, 4, 6 })); auto result = QtConcurrent::blockingMapped<std::vector<int>>( - &pool, MoveOnlyVector({ 1, 2, 3 }), multiplyBy2); + &pool, MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2); QCOMPARE(result, std::vector<int>({ 2, 4, 6 })); } } +void tst_QtConcurrentMap::mappedWithMoveOnlyCallable() +{ + const QList<int> intList { 1, 2, 3 }; + const QList<int> intListMultipiedBy2 { 2, 4, 6 }; + { + const auto result = QtConcurrent::mapped(intList, MultiplyBy2()).results(); + QCOMPARE(result, intListMultipiedBy2); + } + { + const auto result = + QtConcurrent::mapped(intList.begin(), intList.end(), MultiplyBy2()).results(); + QCOMPARE(result, intListMultipiedBy2); + } + { + const auto result = QtConcurrent::blockingMapped(intList, MultiplyBy2()); + QCOMPARE(result, intListMultipiedBy2); + } + { + const auto result = QtConcurrent::blockingMapped<QList<int>>(intList.begin(), intList.end(), + MultiplyBy2()); + QCOMPARE(result, intListMultipiedBy2); + } + + QThreadPool pool; + { + const auto result = QtConcurrent::mapped(&pool, intList, MultiplyBy2()).results(); + QCOMPARE(result, intListMultipiedBy2); + } + { + const auto result = QtConcurrent::mapped( + &pool, intList.begin(), intList.end(), MultiplyBy2()).results(); + QCOMPARE(result, intListMultipiedBy2); + } + { + const auto result = QtConcurrent::blockingMapped(&pool, intList, MultiplyBy2()); + QCOMPARE(result, intListMultipiedBy2); + } + { + const auto result = QtConcurrent::blockingMapped<QList<int>>(&pool, intList.begin(), + intList.end(), MultiplyBy2()); + QCOMPARE(result, intListMultipiedBy2); + } +} + int intSquare(int x) { return x * x; @@ -673,32 +785,57 @@ public: template <typename SourceObject, typename ResultObject, typename MapObject, typename ReduceObject> void testMappedReduced(const QList<SourceObject> &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject) { - const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>( - sourceObjectList, mapObject, reduceObject); - QCOMPARE(result1, expectedResult); - - const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>( - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject); - QCOMPARE(result2, expectedResult); - - const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( - sourceObjectList, mapObject, reduceObject); - QCOMPARE(result3, expectedResult); + // Result type is passed explicitly + { + const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>( + sourceObjectList, mapObject, reduceObject).result(); + QCOMPARE(result1, expectedResult); + + const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject).result(); + QCOMPARE(result2, expectedResult); + + const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( + sourceObjectList, mapObject, reduceObject); + QCOMPARE(result3, expectedResult); + + const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject); + QCOMPARE(result4, expectedResult); + } - const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject); - QCOMPARE(result4, expectedResult); + // Result type is deduced + { + const ResultObject result1 = QtConcurrent::mappedReduced( + sourceObjectList, mapObject, reduceObject).result(); + QCOMPARE(result1, expectedResult); + + const ResultObject result2 = QtConcurrent::mappedReduced( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject).result(); + QCOMPARE(result2, expectedResult); + + const ResultObject result3 = QtConcurrent::blockingMappedReduced( + sourceObjectList, mapObject, reduceObject); + QCOMPARE(result3, expectedResult); + + const ResultObject result4 = QtConcurrent::blockingMappedReduced( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject); + QCOMPARE(result4, expectedResult); + } } template <typename SourceObject, typename ResultObject, typename MapObject, typename ReduceObject> void testMappedReduced(const QList<SourceObject> &sourceObjectList, const ResultObject &expectedResult, MapObject mapObject, ReduceObject reduceObject, QtConcurrent::ReduceOptions options) { const ResultObject result1 = QtConcurrent::mappedReduced( - sourceObjectList, mapObject, reduceObject, options); + sourceObjectList, mapObject, reduceObject, options).result(); QCOMPARE(result1, expectedResult); - const ResultObject result2 = QtConcurrent::mappedReduced( - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, options); + const ResultObject result2 = + QtConcurrent::mappedReduced(sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, options).result(); QCOMPARE(result2, expectedResult); const ResultObject result3 = QtConcurrent::blockingMappedReduced( @@ -768,9 +905,20 @@ void tst_QtConcurrentMap::mappedReduced() CHECK_FAIL("lambda-lambda"); { + // non-template sequences + NonTemplateSequence list { 1, 2, 3 }; + + auto future = QtConcurrent::mappedReduced(list, multiplyBy2, intSumReduce); + QCOMPARE(future.result(), 12); + + auto result = QtConcurrent::blockingMappedReduced(list, multiplyBy2, intSumReduce); + QCOMPARE(result, 12); + } + + { // rvalue sequences auto future = QtConcurrent::mappedReduced(std::vector { 1, 2, 3 }, intSquare, intSumReduce); - QCOMPARE(future, sumOfSquares); + QCOMPARE(future.result(), sumOfSquares); auto result = QtConcurrent::blockingMappedReduced(std::vector { 1, 2, 3 }, intSquare, intSumReduce); @@ -780,11 +928,11 @@ void tst_QtConcurrentMap::mappedReduced() { // move only sequences auto future = - QtConcurrent::mappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare, intSumReduce); - QCOMPARE(future, sumOfSquares); + QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare, intSumReduce); + QCOMPARE(future.result(), sumOfSquares); - auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare, - intSumReduce); + auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), + intSquare, intSumReduce); QCOMPARE(result, sumOfSquares); } } @@ -796,25 +944,57 @@ void testMappedReducedThreadPool(QThreadPool *pool, MapObject mapObject, ReduceObject reduceObject) { - const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>(pool, - sourceObjectList, mapObject, reduceObject); - QCOMPARE(result1, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working - - const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>(pool, - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject); - QCOMPARE(result2, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working - - const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>(pool, - sourceObjectList, mapObject, reduceObject); - QCOMPARE(result3, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working + // Result type is passed explicitly + { + const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>( + pool, sourceObjectList, mapObject, reduceObject).result(); + QCOMPARE(result1, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result2 = + QtConcurrent::mappedReduced<ResultObject>(pool, sourceObjectList.constBegin(), + sourceObjectList.constEnd(), mapObject, + reduceObject).result(); + QCOMPARE(result2, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( + pool, sourceObjectList, mapObject, reduceObject); + QCOMPARE(result3, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( + pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject); + QCOMPARE(result4, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + } - const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>(pool, - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject); - QCOMPARE(result4, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working + // Result type is deduced + { + const ResultObject result1 = QtConcurrent::mappedReduced( + pool, sourceObjectList, mapObject, reduceObject).result(); + QCOMPARE(result1, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result2 = + QtConcurrent::mappedReduced(pool, sourceObjectList.constBegin(), + sourceObjectList.constEnd(), mapObject, + reduceObject).result(); + QCOMPARE(result2, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result3 = QtConcurrent::blockingMappedReduced( + pool, sourceObjectList, mapObject, reduceObject); + QCOMPARE(result3, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result4 = QtConcurrent::blockingMappedReduced( + pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject); + QCOMPARE(result4, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + } } int intCube(int x) @@ -875,10 +1055,21 @@ void tst_QtConcurrentMap::mappedReducedThreadPool() CHECK_FAIL("lambda-lambda"); { + // non-template sequences + NonTemplateSequence list { 1, 2, 3 }; + + auto future = QtConcurrent::mappedReduced(&pool, list, multiplyBy2, intSumReduce); + QCOMPARE(future.result(), 12); + + auto result = QtConcurrent::blockingMappedReduced(&pool, list, multiplyBy2, intSumReduce); + QCOMPARE(result, 12); + } + + { // rvalue sequences auto future = QtConcurrent::mappedReduced(&pool, std::vector { 1, 2, 3 }, intCube, intSumReduce); - QCOMPARE(future, sumOfCubes); + QCOMPARE(future.result(), sumOfCubes); auto result = QtConcurrent::blockingMappedReduced(&pool, std::vector { 1, 2, 3 }, intCube, intSumReduce); @@ -887,14 +1078,75 @@ void tst_QtConcurrentMap::mappedReducedThreadPool() { // move only sequences - auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }), intCube, + auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube, intSumReduce); - QCOMPARE(future, sumOfCubes); + QCOMPARE(future.result(), sumOfCubes); - auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }), + auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube, intSumReduce); QCOMPARE(result, sumOfCubes); } + + { + // pool with invalid number of threads + QThreadPool pool; + pool.setMaxThreadCount(0); // explicitly set incorrect value + + // This should not crash + NonTemplateSequence list { 1, 2, 3 }; + auto future = QtConcurrent::mappedReduced(&pool, list, multiplyBy2, intSumReduce); + QCOMPARE(future.result(), 12); + } +} + +void tst_QtConcurrentMap::mappedReducedWithMoveOnlyCallable() +{ + const QList<int> intList { 1, 2, 3 }; + const auto sum = 12; + { + const auto result = QtConcurrent::mappedReduced( + intList, MultiplyBy2(), IntSumReduceMoveOnly()).result(); + QCOMPARE(result, sum); + } + { + const auto result = + QtConcurrent::mappedReduced(intList.begin(), intList.end(), + MultiplyBy2(), IntSumReduceMoveOnly()).result(); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced(intList, MultiplyBy2(), + IntSumReduceMoveOnly()); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced( + intList.begin(), intList.end(), MultiplyBy2(), IntSumReduceMoveOnly()); + QCOMPARE(result, sum); + } + + QThreadPool pool; + { + const auto result = QtConcurrent::mappedReduced(&pool, intList, MultiplyBy2(), + IntSumReduceMoveOnly()).result(); + QCOMPARE(result, sum); + } + { + const auto result = + QtConcurrent::mappedReduced(&pool, intList.begin(), intList.end(), + MultiplyBy2(), IntSumReduceMoveOnly()).result(); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced(&pool, intList, MultiplyBy2(), + IntSumReduceMoveOnly()); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced( + &pool, intList.begin(), intList.end(), MultiplyBy2(), IntSumReduceMoveOnly()); + QCOMPARE(result, sum); + } } void tst_QtConcurrentMap::mappedReducedDifferentType() @@ -954,21 +1206,49 @@ void testMappedReducedInitialValue(const QList<SourceObject> &sourceObjectList, ReduceObject reduceObject, InitialObject &&initialObject) { - const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>( - sourceObjectList, mapObject, reduceObject, initialObject); - QCOMPARE(result1, expectedResult); - - const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>( - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, initialObject); - QCOMPARE(result2, expectedResult); - - const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( - sourceObjectList, mapObject, reduceObject, initialObject); - QCOMPARE(result3, expectedResult); + // Result type is passed explicitly + { + const ResultObject result1 = + QtConcurrent::mappedReduced<ResultObject>(sourceObjectList, mapObject, reduceObject, + initialObject).result(); + QCOMPARE(result1, expectedResult); + + const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject).result(); + QCOMPARE(result2, expectedResult); + + const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( + sourceObjectList, mapObject, reduceObject, initialObject); + QCOMPARE(result3, expectedResult); + + const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject); + QCOMPARE(result4, expectedResult); + } - const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, initialObject); - QCOMPARE(result4, expectedResult); + // Result type is deduced + { + const ResultObject result1 = + QtConcurrent::mappedReduced(sourceObjectList, mapObject, reduceObject, + initialObject).result(); + QCOMPARE(result1, expectedResult); + + const ResultObject result2 = QtConcurrent::mappedReduced( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject).result(); + QCOMPARE(result2, expectedResult); + + const ResultObject result3 = QtConcurrent::blockingMappedReduced( + sourceObjectList, mapObject, reduceObject, initialObject); + QCOMPARE(result3, expectedResult); + + const ResultObject result4 = QtConcurrent::blockingMappedReduced( + sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject); + QCOMPARE(result4, expectedResult); + } } template <typename SourceObject, typename ResultObject, typename InitialObject, typename MapObject, typename ReduceObject> @@ -980,11 +1260,12 @@ void testMappedReducedInitialValue(const QList<SourceObject> &sourceObjectList, QtConcurrent::ReduceOptions options) { const ResultObject result1 = QtConcurrent::mappedReduced( - sourceObjectList, mapObject, reduceObject, initialObject, options); + sourceObjectList, mapObject, reduceObject, initialObject, options).result(); QCOMPARE(result1, expectedResult); - const ResultObject result2 = QtConcurrent::mappedReduced( - sourceObjectList.constBegin(), sourceObjectList.constEnd(), mapObject, reduceObject, initialObject, options); + const ResultObject result2 = + QtConcurrent::mappedReduced(sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject, options).result(); QCOMPARE(result2, expectedResult); const ResultObject result3 = QtConcurrent::blockingMappedReduced( @@ -1059,10 +1340,22 @@ void tst_QtConcurrentMap::mappedReducedInitialValue() CHECK_FAIL("lambda-lambda"); { + // non-template sequences + NonTemplateSequence list { 1, 2, 3 }; + + auto future = QtConcurrent::mappedReduced(list, multiplyBy2, intSumReduce, intInitial); + QCOMPARE(future.result(), intInitial + 12); + + auto result = + QtConcurrent::blockingMappedReduced(list, multiplyBy2, intSumReduce, intInitial); + QCOMPARE(result, intInitial + 12); + } + + { // rvalue sequences auto future = QtConcurrent::mappedReduced(std::vector { 1, 2, 3 }, intSquare, intSumReduce, intInitial); - QCOMPARE(future, sumOfSquares); + QCOMPARE(future.result(), sumOfSquares); auto result = QtConcurrent::blockingMappedReduced(std::vector { 1, 2, 3 }, intSquare, intSumReduce, intInitial); @@ -1071,12 +1364,12 @@ void tst_QtConcurrentMap::mappedReducedInitialValue() { // move only sequences - auto future = QtConcurrent::mappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare, + auto future = QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare, intSumReduce, intInitial); - QCOMPARE(future, sumOfSquares); + QCOMPARE(future.result(), sumOfSquares); - auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare, - intSumReduce, intInitial); + auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), + intSquare, intSumReduce, intInitial); QCOMPARE(result, sumOfSquares); } } @@ -1089,27 +1382,57 @@ void testMappedReducedInitialValueThreadPool(QThreadPool *pool, ReduceObject reduceObject, InitialObject &&initialObject) { - const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>( - pool, sourceObjectList, mapObject, reduceObject, initialObject); - QCOMPARE(result1, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working - - const ResultObject result2 = QtConcurrent::mappedReduced<ResultObject>( - pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(), - mapObject, reduceObject, initialObject); - QCOMPARE(result2, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working - - const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( - pool, sourceObjectList, mapObject, reduceObject, initialObject); - QCOMPARE(result3, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working + // Result type is passed explicitly + { + const ResultObject result1 = QtConcurrent::mappedReduced<ResultObject>( + pool, sourceObjectList, mapObject, reduceObject, initialObject).result(); + QCOMPARE(result1, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result2 = + QtConcurrent::mappedReduced<ResultObject>(pool, sourceObjectList.constBegin(), + sourceObjectList.constEnd(), mapObject, + reduceObject, initialObject).result(); + QCOMPARE(result2, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result3 = QtConcurrent::blockingMappedReduced<ResultObject>( + pool, sourceObjectList, mapObject, reduceObject, initialObject); + QCOMPARE(result3, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( + pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject); + QCOMPARE(result4, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + } - const ResultObject result4 = QtConcurrent::blockingMappedReduced<ResultObject>( - pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(), - mapObject, reduceObject, initialObject); - QCOMPARE(result4, expectedResult); - QCOMPARE(threadCount(), 1); // ensure the only one thread was working + // Result type is deduced + { + const ResultObject result1 = QtConcurrent::mappedReduced( + pool, sourceObjectList, mapObject, reduceObject, initialObject).result(); + QCOMPARE(result1, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result2 = + QtConcurrent::mappedReduced(pool, sourceObjectList.constBegin(), + sourceObjectList.constEnd(), mapObject, + reduceObject, initialObject).result(); + QCOMPARE(result2, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result3 = QtConcurrent::blockingMappedReduced( + pool, sourceObjectList, mapObject, reduceObject, initialObject); + QCOMPARE(result3, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + + const ResultObject result4 = QtConcurrent::blockingMappedReduced( + pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(), + mapObject, reduceObject, initialObject); + QCOMPARE(result4, expectedResult); + QCOMPARE(threadCount(), 1); // ensure the only one thread was working + } } void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool() @@ -1166,10 +1489,23 @@ void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool() CHECK_FAIL("lambda-lambda"); { + // non-template sequences + NonTemplateSequence list { 1, 2, 3 }; + + auto future = + QtConcurrent::mappedReduced(&pool, list, multiplyBy2, intSumReduce, intInitial); + QCOMPARE(future.result(), intInitial + 12); + + auto result = QtConcurrent::blockingMappedReduced(&pool, list, multiplyBy2, intSumReduce, + intInitial); + QCOMPARE(result, intInitial + 12); + } + + { // rvalue sequences auto future = QtConcurrent::mappedReduced(&pool, std::vector { 1, 2, 3 }, intCube, intSumReduce, intInitial); - QCOMPARE(future, sumOfCubes); + QCOMPARE(future.result(), sumOfCubes); auto result = QtConcurrent::blockingMappedReduced(&pool, std::vector { 1, 2, 3 }, intCube, intSumReduce, intInitial); @@ -1178,16 +1514,71 @@ void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool() { // move only sequences - auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }), intCube, + auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube, intSumReduce, intInitial); - QCOMPARE(future, sumOfCubes); + QCOMPARE(future.result(), sumOfCubes); - auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }), + auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube, intSumReduce, intInitial); QCOMPARE(result, sumOfCubes); } } +void tst_QtConcurrentMap::mappedReducedInitialValueWithMoveOnlyCallable() +{ + const QList<int> intList { 1, 2, 3 }; + const auto initialValue = 10; + const auto sum = 22; + { + const auto result = + QtConcurrent::mappedReduced(intList, MultiplyBy2(), + IntSumReduceMoveOnly(), initialValue).result(); + QCOMPARE(result, sum); + } + { + const auto result = + QtConcurrent::mappedReduced(intList.begin(), intList.end(), MultiplyBy2(), + IntSumReduceMoveOnly(), initialValue).result(); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced( + intList, MultiplyBy2(), IntSumReduceMoveOnly(), initialValue); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced( + intList.begin(), intList.end(), MultiplyBy2(), IntSumReduceMoveOnly(), + initialValue); + QCOMPARE(result, sum); + } + + QThreadPool pool; + { + const auto result = + QtConcurrent::mappedReduced(&pool, intList, MultiplyBy2(), + IntSumReduceMoveOnly(), initialValue).result(); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::mappedReduced(&pool, intList.begin(), intList.end(), + MultiplyBy2(), IntSumReduceMoveOnly(), + initialValue).result(); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced( + &pool, intList, MultiplyBy2(), IntSumReduceMoveOnly(), initialValue); + QCOMPARE(result, sum); + } + { + const auto result = QtConcurrent::blockingMappedReduced( + &pool, intList.begin(), intList.end(), MultiplyBy2(), IntSumReduceMoveOnly(), + initialValue); + QCOMPARE(result, sum); + } +} + void tst_QtConcurrentMap::mappedReducedDifferentTypeInitialValue() { // This is a copy of tst_QtConcurrentMap::mappedReducedDifferentType @@ -1237,6 +1628,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); @@ -1417,6 +1853,8 @@ public: { currentInstanceCount.fetchAndAddRelaxed(-1);} inline InstanceCounter(const InstanceCounter &) { currentInstanceCount.fetchAndAddRelaxed(1); updatePeak(); } + constexpr InstanceCounter &operator=(const InstanceCounter &) noexcept + { return *this; } void updatePeak() { @@ -1540,7 +1978,7 @@ void tst_QtConcurrentMap::incrementalResults() QCOMPARE(future.isFinished(), true); QCOMPARE(future.resultCount(), count); - QCOMPARE(future.results().count(), count); + QCOMPARE(future.results().size(), count); } /* @@ -1596,15 +2034,15 @@ void tst_QtConcurrentMap::stlContainers() vector.push_back(1); vector.push_back(2); - std::vector<int> vector2 = QtConcurrent::blockingMapped<std::vector<int> >(vector, mapper); - QCOMPARE(vector2.size(), (std::vector<int>::size_type)(2)); + std::vector<int> vector2 = QtConcurrent::blockingMapped(vector, mapper); + QCOMPARE(vector2.size(), 2u); std::list<int> list; list.push_back(1); list.push_back(2); - std::list<int> list2 = QtConcurrent::blockingMapped<std::list<int> >(list, mapper); - QCOMPARE(list2.size(), (std::vector<int>::size_type)(2)); + std::list<int> list2 = QtConcurrent::blockingMapped(list, mapper); + QCOMPARE(list2.size(), 2u); QtConcurrent::mapped(list, mapper).waitForFinished(); @@ -1617,27 +2055,21 @@ void tst_QtConcurrentMap::stlContainersLambda() vector.push_back(1); vector.push_back(2); - std::vector<int> vector2 = QtConcurrent::blockingMapped<std::vector<int> >(vector, - [](const int &i) { - return mapper(i); - } - ); - QCOMPARE(vector2.size(), (std::vector<int>::size_type)(2)); + std::vector<int> vector2 = + QtConcurrent::blockingMapped(vector, [](const int &i) { return mapper(i); }); + QCOMPARE(vector2.size(), 2u); std::list<int> list; list.push_back(1); list.push_back(2); - std::list<int> list2 = QtConcurrent::blockingMapped<std::list<int> >(list, - [](const int &i) { - return mapper(i); - } - ); - QCOMPARE(list2.size(), (std::vector<int>::size_type)(2)); + std::list<int> list2 = + QtConcurrent::blockingMapped(list, [](const int &i) { return mapper(i); }); + QCOMPARE(list2.size(), 2u); QtConcurrent::mapped(list, [](const int &i) { return mapper(i); }).waitForFinished(); - QtConcurrent::blockingMap(list, [](int x) { x *= 2; }); + QtConcurrent::blockingMap(list, []([[maybe_unused]] int x) { x *= 2; }); } InstanceCounter ic_fn(const InstanceCounter & ic) |