diff options
Diffstat (limited to 'tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp')
-rw-r--r-- | tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp | 894 |
1 files changed, 761 insertions, 133 deletions
diff --git a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp index 39af0acd06..3e3165013f 100644 --- a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp +++ b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp @@ -1,55 +1,36 @@ -/**************************************************************************** -** -** 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 <QTest> +#include <QSet> +#include <QRandomGenerator> -#include <QtTest/QtTest> - -#include "functions.h" +#include "../testhelper_functions.h" class tst_QtConcurrentMap : public QObject { Q_OBJECT private slots: void map(); - void blocking_map(); + void blockingMap(); + 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(); @@ -69,7 +50,7 @@ public slots: using namespace QtConcurrent; -void multiplyBy2Immutable(int x) +void multiplyBy2Immutable([[maybe_unused]] int x) { x *= 2; } @@ -77,7 +58,7 @@ void multiplyBy2Immutable(int x) class MultiplyBy2Immutable { public: - void operator()(int x) + void operator()([[maybe_unused]] int x) { x *= 2; } @@ -97,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() @@ -137,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 @@ -163,12 +163,39 @@ 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<int> moveOnlyVector({ 1, 2, 3 }); + + // functor + QtConcurrent::map(moveOnlyVector, MultiplyBy2InPlace()).waitForFinished(); + 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 // not allowed: map() with immutable sequences makes no sense { @@ -199,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); @@ -211,7 +238,7 @@ void tst_QtConcurrentMap::map() #endif } -void tst_QtConcurrentMap::blocking_map() +void tst_QtConcurrentMap::blockingMap() { // functors take arguments by reference, modifying the sequence in place { @@ -249,6 +276,24 @@ void tst_QtConcurrentMap::blocking_map() 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<int> moveOnlyVector({ 1, 2, 3 }); + + // functor + QtConcurrent::blockingMap(moveOnlyVector, MultiplyBy2InPlace()); + QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 })); + QtConcurrent::blockingMap(moveOnlyVector.begin(), moveOnlyVector.end(), + MultiplyBy2InPlace()); + QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 4, 8, 12 })); } // functors don't take arguments by reference, making these no-ops @@ -275,12 +320,19 @@ void tst_QtConcurrentMap::blocking_map() 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 { @@ -311,7 +363,7 @@ void tst_QtConcurrentMap::blocking_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::blockingMap(list, MultiplyBy2InPlace()); QtConcurrent::blockingMap(list, multiplyBy2InPlace); @@ -323,6 +375,54 @@ void tst_QtConcurrentMap::blocking_map() #endif } +void tst_QtConcurrentMap::mapOnRvalue() +{ + struct ListRange + { + using iterator = QList<int>::iterator; + ListRange(iterator b, iterator e) : m_begin(b), m_end(e) { } + + iterator begin() const { return m_begin; } + iterator end() const { return m_end; } + + private: + iterator m_begin; + iterator m_end; + }; + + const QList expected { 1, 4, 6, 4 }; + { + QList list { 1, 2, 3, 4 }; + auto future = + QtConcurrent::map(ListRange(list.begin() + 1, list.end() - 1), multiplyBy2InPlace); + future.waitForFinished(); + QCOMPARE(list, expected); + } + + { + QList list { 1, 2, 3, 4 }; + QThreadPool pool; + auto future = QtConcurrent::map(&pool, ListRange(list.begin() + 1, list.end() - 1), + multiplyBy2InPlace); + future.waitForFinished(); + QCOMPARE(list, expected); + } + + { + QList list { 1, 2, 3, 4 }; + QtConcurrent::blockingMap(ListRange(list.begin() + 1, list.end() - 1), multiplyBy2InPlace); + QCOMPARE(list, expected); + } + + { + QList list { 1, 2, 3, 4 }; + QThreadPool pool; + QtConcurrent::blockingMap(&pool, ListRange(list.begin() + 1, list.end() - 1), + multiplyBy2InPlace); + QCOMPARE(list, expected); + } +} + int multiplyBy2(int x) { int y = x * 2; @@ -339,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); @@ -447,6 +564,36 @@ void tst_QtConcurrentMap::mapped() testMapped(stringList, intList, &QString::toInt); CHECK_FAIL("member"); #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 { 1, 2, 3 }, multiplyBy2); + QCOMPARE(result, std::vector<int>({ 2, 4, 6 })); + } + + { + // move only sequences + 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<int>({ 1, 2, 3 }), multiplyBy2); + QCOMPARE(result, std::vector<int>({ 2, 4, 6 })); + } } static QSemaphore semaphore(1); @@ -531,6 +678,80 @@ void tst_QtConcurrentMap::mappedThreadPool() CHECK_FAIL("function"); testMappedThreadPool(&pool, intList, intListMultipiedBy3, lambdaMultiplyBy3); 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 })); + + auto result = QtConcurrent::blockingMapped<std::vector<int>>(&pool, std::vector { 1, 2, 3 }, + multiplyBy2); + QCOMPARE(result, std::vector<int>({ 2, 4, 6 })); + } + { + // move only sequences + 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<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) @@ -564,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( @@ -609,7 +855,7 @@ void tst_QtConcurrentMap::mappedReduced() const int sum = 6; const int sumOfSquares = 14; - void (QList<int>::*push_back)(const int &) = &QList<int>::push_back; + void (QList<int>::*push_back)(QList<int>::parameter_type) = &QList<int>::push_back; auto lambdaSquare = [](int x) { return x * x; @@ -657,6 +903,38 @@ void tst_QtConcurrentMap::mappedReduced() CHECK_FAIL("lambda-member"); testMappedReduced(intList, sumOfSquares, lambdaSquare, lambdaSumReduce); 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.result(), sumOfSquares); + + auto result = QtConcurrent::blockingMappedReduced(std::vector { 1, 2, 3 }, intSquare, + intSumReduce); + QCOMPARE(result, sumOfSquares); + } + + { + // move only sequences + auto future = + QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare, intSumReduce); + QCOMPARE(future.result(), sumOfSquares); + + auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), + intSquare, intSumReduce); + QCOMPARE(result, sumOfSquares); + } } template <typename SourceObject, typename ResultObject, typename MapObject, typename ReduceObject> @@ -666,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) @@ -743,6 +1053,100 @@ void tst_QtConcurrentMap::mappedReducedThreadPool() CHECK_FAIL("lambda-function"); testMappedReducedThreadPool(&pool, intList, sumOfCubes, lambdaCube, lambdaSumReduce); 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.result(), sumOfCubes); + + auto result = QtConcurrent::blockingMappedReduced(&pool, std::vector { 1, 2, 3 }, intCube, + intSumReduce); + QCOMPARE(result, sumOfCubes); + } + + { + // move only sequences + auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube, + intSumReduce); + QCOMPARE(future.result(), sumOfCubes); + + 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() @@ -802,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> @@ -828,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( @@ -857,7 +1290,7 @@ void tst_QtConcurrentMap::mappedReducedInitialValue() const int sumOfSquares = 24; const int intInitial = 10; - void (QList<int>::*push_back)(const int &) = &QList<int>::push_back; + void (QList<int>::*push_back)(QList<int>::parameter_type) = &QList<int>::push_back; auto lambdaSquare = [](int x) { return x * x; @@ -905,6 +1338,40 @@ void tst_QtConcurrentMap::mappedReducedInitialValue() CHECK_FAIL("lambda-member"); testMappedReducedInitialValue(intList, sumOfSquares, lambdaSquare, lambdaSumReduce, intInitial); 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.result(), sumOfSquares); + + auto result = QtConcurrent::blockingMappedReduced(std::vector { 1, 2, 3 }, intSquare, + intSumReduce, intInitial); + QCOMPARE(result, sumOfSquares); + } + + { + // move only sequences + auto future = QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare, + intSumReduce, intInitial); + QCOMPARE(future.result(), sumOfSquares); + + auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), + intSquare, intSumReduce, intInitial); + QCOMPARE(result, sumOfSquares); + } } template <typename SourceObject, typename ResultObject, typename InitialObject, typename MapObject, typename ReduceObject> @@ -915,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() @@ -990,6 +1487,96 @@ void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool() testMappedReducedInitialValueThreadPool(&pool, intList, sumOfCubes, lambdaCube, lambdaSumReduce, intInitial); 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.result(), sumOfCubes); + + auto result = QtConcurrent::blockingMappedReduced(&pool, std::vector { 1, 2, 3 }, intCube, + intSumReduce, intInitial); + QCOMPARE(result, sumOfCubes); + } + + { + // move only sequences + auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube, + intSumReduce, intInitial); + QCOMPARE(future.result(), sumOfCubes); + + 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() @@ -1041,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); @@ -1221,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() { @@ -1344,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); } /* @@ -1400,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(); @@ -1421,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) |