summaryrefslogtreecommitdiffstats
path: root/tests/auto/concurrent
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/concurrent')
-rw-r--r--tests/auto/concurrent/CMakeLists.txt10
-rw-r--r--tests/auto/concurrent/concurrent.pro10
-rw-r--r--tests/auto/concurrent/qtconcurrentfilter/.prev_CMakeLists.txt12
-rw-r--r--tests/auto/concurrent/qtconcurrentfilter/CMakeLists.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro4
-rw-r--r--tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp797
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/.gitignore1
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/CMakeLists.txt20
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/README.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generation_helpers.h265
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/function_signature.py138
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_excel.py46
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_gui.py156
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_testcase.py366
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generator_main.py33
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/helpers.py31
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/option_management.py195
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrent_selected_tests.cpp347
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.cpp59
-rw-r--r--tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.h27
-rw-r--r--tests/auto/concurrent/qtconcurrentiteratekernel/CMakeLists.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro4
-rw-r--r--tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp59
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/.prev_CMakeLists.txt17
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/CMakeLists.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/functions.h136
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro7
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp894
-rw-r--r--tests/auto/concurrent/qtconcurrentmedian/CMakeLists.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrentmedian/qtconcurrentmedian.pro4
-rw-r--r--tests/auto/concurrent/qtconcurrentmedian/tst_qtconcurrentmedian.cpp36
-rw-r--r--tests/auto/concurrent/qtconcurrentrun/CMakeLists.txt14
-rw-r--r--tests/auto/concurrent/qtconcurrentrun/qtconcurrentrun.pro7
-rw-r--r--tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp636
-rw-r--r--tests/auto/concurrent/qtconcurrenttask/CMakeLists.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrenttask/qtconcurrenttask.pro4
-rw-r--r--tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp91
-rw-r--r--tests/auto/concurrent/qtconcurrentthreadengine/CMakeLists.txt13
-rw-r--r--tests/auto/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro4
-rw-r--r--tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp181
-rw-r--r--tests/auto/concurrent/testhelper_functions.h183
41 files changed, 3969 insertions, 916 deletions
diff --git a/tests/auto/concurrent/CMakeLists.txt b/tests/auto/concurrent/CMakeLists.txt
index 2ef8cfd128..0088ebfcf6 100644
--- a/tests/auto/concurrent/CMakeLists.txt
+++ b/tests/auto/concurrent/CMakeLists.txt
@@ -1,9 +1,13 @@
-# Generated from concurrent.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qtconcurrentfilter)
add_subdirectory(qtconcurrentiteratekernel)
+add_subdirectory(qtconcurrentfiltermapgenerated)
add_subdirectory(qtconcurrentmap)
add_subdirectory(qtconcurrentmedian)
-add_subdirectory(qtconcurrentrun)
+if(NOT INTEGRITY)
+ add_subdirectory(qtconcurrentrun)
+ add_subdirectory(qtconcurrenttask)
+endif()
add_subdirectory(qtconcurrentthreadengine)
-add_subdirectory(qtconcurrenttask)
diff --git a/tests/auto/concurrent/concurrent.pro b/tests/auto/concurrent/concurrent.pro
deleted file mode 100644
index ad3231ff90..0000000000
--- a/tests/auto/concurrent/concurrent.pro
+++ /dev/null
@@ -1,10 +0,0 @@
-TEMPLATE=subdirs
-SUBDIRS=\
- qtconcurrentfilter \
- qtconcurrentiteratekernel \
- qtconcurrentmap \
- qtconcurrentmedian \
- qtconcurrentrun \
- qtconcurrentthreadengine \
- qtconcurrenttask
-
diff --git a/tests/auto/concurrent/qtconcurrentfilter/.prev_CMakeLists.txt b/tests/auto/concurrent/qtconcurrentfilter/.prev_CMakeLists.txt
deleted file mode 100644
index be8c936c48..0000000000
--- a/tests/auto/concurrent/qtconcurrentfilter/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# Generated from qtconcurrentfilter.pro.
-
-#####################################################################
-## tst_qtconcurrentfilter Test:
-#####################################################################
-
-add_qt_test(tst_qtconcurrentfilter
- SOURCES
- tst_qtconcurrentfilter.cpp
- PUBLIC_LIBRARIES
- Qt::Concurrent
-)
diff --git a/tests/auto/concurrent/qtconcurrentfilter/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentfilter/CMakeLists.txt
index 7868906178..3c00393d39 100644
--- a/tests/auto/concurrent/qtconcurrentfilter/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrentfilter/CMakeLists.txt
@@ -1,12 +1,19 @@
-# Generated from qtconcurrentfilter.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrentfilter Test:
#####################################################################
-qt_add_test(tst_qtconcurrentfilter
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentfilter LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentfilter
SOURCES
tst_qtconcurrentfilter.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
)
diff --git a/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro b/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro
deleted file mode 100644
index f2e3e0c8e1..0000000000
--- a/tests/auto/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrentfilter
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrentfilter.cpp
diff --git a/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp b/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp
index 945f286c9d..e19a596d5d 100644
--- a/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp
+++ b/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp
@@ -1,36 +1,12 @@
-/****************************************************************************
-**
-** 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 <qtconcurrentfilter.h>
#include <QCoreApplication>
#include <QList>
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QSet>
-#include "../qtconcurrentmap/functions.h"
+#include "../testhelper_functions.h"
class tst_QtConcurrentFilter : public QObject
{
@@ -39,14 +15,19 @@ class tst_QtConcurrentFilter : public QObject
private slots:
void filter();
void filterThreadPool();
+ void filterWithMoveOnlyCallable();
void filtered();
void filteredThreadPool();
+ void filteredWithMoveOnlyCallable();
void filteredReduced();
void filteredReducedThreadPool();
+ void filteredReducedWithMoveOnlyCallables();
void filteredReducedDifferentType();
void filteredReducedInitialValue();
void filteredReducedInitialValueThreadPool();
+ void filteredReducedInitialValueWithMoveOnlyCallables();
void filteredReducedDifferentTypeInitialValue();
+ void filteredReduceOptionConvertableToResultType();
void resultAt();
void incrementalResults();
void noDetach();
@@ -98,6 +79,19 @@ void tst_QtConcurrentFilter::filter()
CHECK_FAIL("member");
testFilter(intList, intListEven, lambdaIsEven);
CHECK_FAIL("lambda");
+
+ // non-template sequences
+ {
+
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ QtConcurrent::filter(list, keepEvenNumbers).waitForFinished();
+ QCOMPARE(list, NonTemplateSequence({ 2, 4 }));
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ QtConcurrent::blockingFilter(list, keepEvenNumbers);
+ QCOMPARE(list, NonTemplateSequence({ 2, 4 }));
+ }
}
static QSemaphore semaphore(1);
@@ -175,6 +169,47 @@ void tst_QtConcurrentFilter::filterThreadPool()
CHECK_FAIL("function");
testFilterThreadPool(&pool, intList, intListEven, lambdaIsOdd);
CHECK_FAIL("lambda");
+
+ // non-template sequences
+ {
+
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ QtConcurrent::filter(list, keepEvenIntegers).waitForFinished();
+ QCOMPARE(list, NonTemplateSequence({ 2, 4 }));
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ QtConcurrent::blockingFilter(list, keepEvenIntegers);
+ QCOMPARE(list, NonTemplateSequence({ 2, 4 }));
+ }
+}
+
+void tst_QtConcurrentFilter::filterWithMoveOnlyCallable()
+{
+ const QList<int> intListEven { 2, 4 };
+ {
+ QList<int> intList { 1, 2, 3, 4 };
+ QtConcurrent::filter(intList, KeepEvenIntegersMoveOnly()).waitForFinished();
+ QCOMPARE(intList, intListEven);
+ }
+
+ {
+ QList<int> intList { 1, 2, 3, 4 };
+ QtConcurrent::blockingFilter(intList, KeepEvenIntegersMoveOnly());
+ QCOMPARE(intList, intListEven);
+ }
+
+ QThreadPool pool;
+ {
+ QList<int> intList { 1, 2, 3, 4 };
+ QtConcurrent::filter(&pool, intList, KeepEvenIntegersMoveOnly()).waitForFinished();
+ QCOMPARE(intList, intListEven);
+ }
+ {
+ QList<int> intList { 1, 2, 3, 4 };
+ QtConcurrent::blockingFilter(&pool, intList, KeepEvenIntegersMoveOnly());
+ QCOMPARE(intList, intListEven);
+ }
}
template <typename SourceObject,
@@ -221,6 +256,40 @@ void tst_QtConcurrentFilter::filtered()
CHECK_FAIL("member");
testFiltered(intList, intListEven, lambdaIsEven);
CHECK_FAIL("lambda");
+
+ // non-template sequences
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto future = QtConcurrent::filtered(list, keepEvenIntegers);
+ QCOMPARE(future.results(), QList({ 2, 4 }));
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto result = QtConcurrent::blockingFiltered(list, keepEvenIntegers);
+ QCOMPARE(result, NonTemplateSequence({ 2, 4 }));
+ }
+
+ {
+ // rvalue sequences
+ auto future = QtConcurrent::filtered(std::vector { 1, 2, 3, 4 }, keepEvenIntegers);
+ QCOMPARE(future.results(), QList<int>({ 2, 4 }));
+
+ auto result = QtConcurrent::blockingFiltered(std::vector { 1, 2, 3, 4 }, keepEvenIntegers);
+ QCOMPARE(result, std::vector<int>({ 2, 4 }));
+ }
+
+ {
+ // move only types sequences
+ auto future = QtConcurrent::filtered(MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
+ QCOMPARE(future.results(), QList<int>({ 2, 4 }));
+
+#if 0
+ // does not work yet
+ auto result = QtConcurrent::blockingFiltered(
+ MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
+ QCOMPARE(result, std::vector<int>({ 2, 4 }));
+#endif
+ }
}
template <typename SourceObject,
@@ -274,6 +343,89 @@ void tst_QtConcurrentFilter::filteredThreadPool()
CHECK_FAIL("function");
testFilteredThreadPool(&pool, intList, intListEven, lambdaIsOdd);
CHECK_FAIL("lambda");
+
+ // non-template sequences
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto future = QtConcurrent::filtered(&pool, list, keepEvenIntegers);
+ QCOMPARE(future.results(), QList({ 2, 4 }));
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto result = QtConcurrent::blockingFiltered(&pool, list, keepEvenIntegers);
+ QCOMPARE(result, NonTemplateSequence({ 2, 4 }));
+ }
+
+ {
+ // rvalue sequences
+ auto future = QtConcurrent::filtered(&pool, std::vector { 1, 2, 3, 4 }, keepEvenIntegers);
+ QCOMPARE(future.results(), QList<int>({ 2, 4 }));
+
+ auto result =
+ QtConcurrent::blockingFiltered(&pool, std::vector { 1, 2, 3, 4 }, keepEvenIntegers);
+ QCOMPARE(result, std::vector<int>({ 2, 4 }));
+ }
+
+ {
+ // move-only sequences
+ auto future = QtConcurrent::filtered(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepEvenIntegers);
+ QCOMPARE(future.results(), QList<int>({ 2, 4 }));
+
+#if 0
+ // does not work yet
+ auto result =
+ QtConcurrent::blockingFiltered(
+ &pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
+ QCOMPARE(result, std::vector<int>({ 2, 4 }));
+#endif
+ }
+}
+
+void tst_QtConcurrentFilter::filteredWithMoveOnlyCallable()
+{
+ const QList<int> intList { 1, 2, 3, 4 };
+ const QList<int> intListEven { 2, 4 };
+ {
+ const auto result = QtConcurrent::filtered(intList, KeepEvenIntegersMoveOnly()).results();
+ QCOMPARE(result, intListEven);
+ }
+ {
+ const auto result = QtConcurrent::filtered(
+ intList.begin(), intList.end(), KeepEvenIntegersMoveOnly()).results();
+ QCOMPARE(result, intListEven);
+ }
+ {
+ const auto result = QtConcurrent::blockingFiltered(intList, KeepEvenIntegersMoveOnly());
+ QCOMPARE(result, intListEven);
+ }
+ {
+ const auto result = QtConcurrent::blockingFiltered<QList<int>>(
+ intList.begin(), intList.end(), KeepEvenIntegersMoveOnly());
+ QCOMPARE(result, intListEven);
+ }
+
+ QThreadPool pool;
+ {
+ const auto result =
+ QtConcurrent::filtered(&pool, intList, KeepEvenIntegersMoveOnly()).results();
+ QCOMPARE(result, intListEven);
+ }
+ {
+ const auto result = QtConcurrent::filtered(&pool, intList.begin(), intList.end(),
+ KeepEvenIntegersMoveOnly()).results();
+ QCOMPARE(result, intListEven);
+ }
+ {
+ const auto result =
+ QtConcurrent::blockingFiltered(&pool, intList, KeepEvenIntegersMoveOnly());
+ QCOMPARE(result, intListEven);
+ }
+ {
+ const auto result = QtConcurrent::blockingFiltered<QList<int>>(
+ &pool, intList.begin(), intList.end(), KeepEvenIntegersMoveOnly());
+ QCOMPARE(result, intListEven);
+ }
}
template <typename SourceObject,
@@ -285,23 +437,47 @@ void testFilteredReduced(const QList<SourceObject> &sourceObjectList,
FilterObject filterObject,
ReduceObject reduceObject)
{
- const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList, filterObject, reduceObject);
- QCOMPARE(result1, expectedResult);
-
- const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject);
- QCOMPARE(result2, expectedResult);
-
- const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- sourceObjectList, filterObject, reduceObject);
- QCOMPARE(result3, expectedResult);
+ // Result type is passed explicitly
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
+ sourceObjectList, filterObject, reduceObject).result();
+ QCOMPARE(result1, expectedResult);
+
+ const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject).result();
+ QCOMPARE(result2, expectedResult);
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ sourceObjectList, filterObject, reduceObject);
+ QCOMPARE(result3, expectedResult);
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject);
+ QCOMPARE(result4, expectedResult);
+ }
- const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject);
- QCOMPARE(result4, expectedResult);
+ // Result type is deduced
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced(
+ sourceObjectList, filterObject, reduceObject).result();
+ QCOMPARE(result1, expectedResult);
+
+ const ResultObject result2 = QtConcurrent::filteredReduced(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject).result();
+ QCOMPARE(result2, expectedResult);
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
+ sourceObjectList, filterObject, reduceObject);
+ QCOMPARE(result3, expectedResult);
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject);
+ QCOMPARE(result4, expectedResult);
+ }
}
template <typename SourceObject,
@@ -315,12 +491,13 @@ void testFilteredReduced(const QList<SourceObject> &sourceObjectList,
QtConcurrent::ReduceOptions options)
{
const ResultObject result1 = QtConcurrent::filteredReduced(
- sourceObjectList, filterObject, reduceObject, options);
+ sourceObjectList, filterObject, reduceObject, options).result();
QCOMPARE(result1, expectedResult);
- const ResultObject result2 = QtConcurrent::filteredReduced(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(), filterObject,
- reduceObject, options);
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced(sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(),
+ filterObject, reduceObject, options).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
@@ -356,8 +533,9 @@ void tst_QtConcurrentFilter::filteredReduced()
const int intSum = 6; // sum of even values
const Number numberSum = 6; // sum of even values
- void (QList<int>::*pushBackInt)(const int &) = &QList<int>::push_back;
- void (QList<Number>::*pushBackNumber)(const Number &) = &QList<Number>::push_back;
+ void (QList<int>::*pushBackInt)(QList<int>::parameter_type) = &QList<int>::push_back;
+ void (QList<Number>::*pushBackNumber)(QList<Number>::parameter_type) =
+ &QList<Number>::push_back;
auto lambdaIsEven = [](const int &x) {
return (x & 1) == 0;
@@ -409,6 +587,40 @@ void tst_QtConcurrentFilter::filteredReduced()
CHECK_FAIL("lambda-member");
testFilteredReduced(intList, intSum, lambdaIsEven, lambdaIntSumReduce);
CHECK_FAIL("lambda-lambda");
+
+ // non-template sequences
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto future = QtConcurrent::filteredReduced(list, keepEvenIntegers, intSumReduce);
+ QCOMPARE(future.result(), intSum);
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto result = QtConcurrent::blockingFilteredReduced(list, keepEvenIntegers, intSumReduce);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // rvalue sequences
+ auto future = QtConcurrent::filteredReduced(std::vector { 1, 2, 3, 4 }, keepEvenIntegers,
+ intSumReduce);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(std::vector { 1, 2, 3, 4 },
+ keepEvenIntegers, intSumReduce);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // move only sequences
+ auto future = QtConcurrent::filteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepEvenIntegers, intSumReduce);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepEvenIntegers, intSumReduce);
+ QCOMPARE(result, intSum);
+ }
}
template <typename SourceObject,
@@ -421,27 +633,57 @@ void testFilteredReducedThreadPool(QThreadPool *pool,
FilterObject filterObject,
ReduceObject reduceObject)
{
- const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList, filterObject, reduceObject);
- QCOMPARE(result1, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
-
- const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject);
- QCOMPARE(result2, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
-
- const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- pool, sourceObjectList, filterObject, reduceObject);
- QCOMPARE(result3, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ // Result type is passed explicitly
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
+ pool, sourceObjectList, filterObject, reduceObject).result();
+ QCOMPARE(result1, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced<ResultObject>(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject,
+ reduceObject).result();
+ QCOMPARE(result2, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ pool, sourceObjectList, filterObject, reduceObject);
+ QCOMPARE(result3, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject);
+ QCOMPARE(result4, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ }
- const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject);
- QCOMPARE(result4, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ // Result type is deduced
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced(
+ pool, sourceObjectList, filterObject, reduceObject).result();
+ QCOMPARE(result1, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject,
+ reduceObject).result();
+ QCOMPARE(result2, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
+ pool, sourceObjectList, filterObject, reduceObject);
+ QCOMPARE(result3, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced(
+ pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject);
+ QCOMPARE(result4, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ }
}
void tst_QtConcurrentFilter::filteredReducedThreadPool()
@@ -485,6 +727,96 @@ void tst_QtConcurrentFilter::filteredReducedThreadPool()
CHECK_FAIL("lambda-function");
testFilteredReducedThreadPool(&pool, intList, intSum, lambdaIsOdd, lambdaSumReduce);
CHECK_FAIL("lambda-lambda");
+
+ // non-template sequences
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto future = QtConcurrent::filteredReduced(&pool, list, keepOddIntegers, intSumReduce);
+ QCOMPARE(future.result(), intSum);
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto result =
+ QtConcurrent::blockingFilteredReduced(&pool, list, keepOddIntegers, intSumReduce);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // rvalue sequences
+ auto future = QtConcurrent::filteredReduced(&pool, std::vector { 1, 2, 3, 4 },
+ keepOddIntegers, intSumReduce);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(&pool, std::vector { 1, 2, 3, 4 },
+ keepOddIntegers, intSumReduce);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // move only sequences
+ auto future = QtConcurrent::filteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepOddIntegers, intSumReduce);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepOddIntegers, intSumReduce);
+ QCOMPARE(result, intSum);
+ }
+}
+
+void tst_QtConcurrentFilter::filteredReducedWithMoveOnlyCallables()
+{
+ const QList<int> intList { 1, 2, 3, 4 };
+ const QList<int> intListEven { 2, 4 };
+ const auto sum = 6;
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(intList, KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly()).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(intList.begin(), intList.end(),
+ KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly()).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ intList, KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly());
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ intList.begin(), intList.end(), KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly());
+ QCOMPARE(result, sum);
+ }
+
+ QThreadPool pool;
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(&pool, intList, KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly()).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::filteredReduced(
+ &pool, intList.begin(), intList.end(),
+ KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly()).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, intList, KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly());
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, intList.begin(), intList.end(), KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly());
+ QCOMPARE(result, sum);
+ }
}
void tst_QtConcurrentFilter::filteredReducedDifferentType()
@@ -547,23 +879,47 @@ void testFilteredReducedInitialValue(const QList<SourceObject> &sourceObjectList
ReduceObject reduceObject,
InitialObject &&initialObject)
{
- const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList, filterObject, reduceObject, initialObject);
- QCOMPARE(result1, expectedResult);
-
- const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject);
- QCOMPARE(result2, expectedResult);
-
- const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- sourceObjectList, filterObject, reduceObject, initialObject);
- QCOMPARE(result3, expectedResult);
+ // Result type is passed explicitly
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
+ sourceObjectList, filterObject, reduceObject, initialObject).result();
+ QCOMPARE(result1, expectedResult);
+
+ const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject).result();
+ QCOMPARE(result2, expectedResult);
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ sourceObjectList, filterObject, reduceObject, initialObject);
+ QCOMPARE(result3, expectedResult);
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject);
+ QCOMPARE(result4, expectedResult);
+ }
- const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject);
- QCOMPARE(result4, expectedResult);
+ // Result type is deduced
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced(
+ sourceObjectList, filterObject, reduceObject, initialObject).result();
+ QCOMPARE(result1, expectedResult);
+
+ const ResultObject result2 = QtConcurrent::filteredReduced(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject).result();
+ QCOMPARE(result2, expectedResult);
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
+ sourceObjectList, filterObject, reduceObject, initialObject);
+ QCOMPARE(result3, expectedResult);
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced(
+ sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject);
+ QCOMPARE(result4, expectedResult);
+ }
}
template <typename SourceObject,
@@ -579,12 +935,13 @@ void testFilteredReducedInitialValue(const QList<SourceObject> &sourceObjectList
QtConcurrent::ReduceOptions options)
{
const ResultObject result1 = QtConcurrent::filteredReduced(
- sourceObjectList, filterObject, reduceObject, initialObject, options);
+ sourceObjectList, filterObject, reduceObject, initialObject, options).result();
QCOMPARE(result1, expectedResult);
- const ResultObject result2 = QtConcurrent::filteredReduced(
- sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject, options);
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced(sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject, reduceObject,
+ initialObject, options).result();
QCOMPARE(result2, expectedResult);
const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
@@ -612,8 +969,9 @@ void tst_QtConcurrentFilter::filteredReducedInitialValue()
const int intSum = 16; // sum of even values and initial value
const Number numberSum = 16; // sum of even values and initial value
- void (QList<int>::*pushBackInt)(const int &) = &QList<int>::push_back;
- void (QList<Number>::*pushBackNumber)(const Number &) = &QList<Number>::push_back;
+ void (QList<int>::*pushBackInt)(QList<int>::parameter_type) = &QList<int>::push_back;
+ void (QList<Number>::*pushBackNumber)(QList<Number>::parameter_type) =
+ &QList<Number>::push_back;
auto lambdaIsEven = [](const int &x) {
return (x & 1) == 0;
@@ -680,6 +1038,42 @@ void tst_QtConcurrentFilter::filteredReducedInitialValue()
testFilteredReducedInitialValue(intList, intSum, lambdaIsEven,
lambdaIntSumReduce, intInitial);
CHECK_FAIL("lambda-lambda");
+
+ // non-template sequences
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto future =
+ QtConcurrent::filteredReduced(list, keepEvenIntegers, intSumReduce, intInitial);
+ QCOMPARE(future.result(), intSum);
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto result = QtConcurrent::blockingFilteredReduced(list, keepEvenIntegers, intSumReduce,
+ intInitial);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // rvalue sequences
+ auto future = QtConcurrent::filteredReduced(std::vector { 1, 2, 3, 4 }, keepEvenIntegers,
+ intSumReduce, intInitial);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(
+ std::vector { 1, 2, 3, 4 }, keepEvenIntegers, intSumReduce, intInitial);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // move only sequences
+ auto future = QtConcurrent::filteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepEvenIntegers, intSumReduce, intInitial);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(
+ MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers, intSumReduce, intInitial);
+ QCOMPARE(result, intSum);
+ }
}
template <typename SourceObject,
@@ -694,27 +1088,57 @@ void testFilteredReducedInitialValueThreadPool(QThreadPool *pool,
ReduceObject reduceObject,
InitialObject &&initialObject)
{
- const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList, filterObject, reduceObject, initialObject);
- QCOMPARE(result1, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
-
- const ResultObject result2 = QtConcurrent::filteredReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject);
- QCOMPARE(result2, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
-
- const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- pool, sourceObjectList, filterObject, reduceObject, initialObject);
- QCOMPARE(result3, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ // Result type is passed explicitly
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced<ResultObject>(
+ pool, sourceObjectList, filterObject, reduceObject, initialObject).result();
+ QCOMPARE(result1, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced<ResultObject>(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject,
+ reduceObject, initialObject).result();
+ QCOMPARE(result2, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ pool, sourceObjectList, filterObject, reduceObject, initialObject);
+ QCOMPARE(result3, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
+ pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject);
+ QCOMPARE(result4, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ }
- const ResultObject result4 = QtConcurrent::blockingFilteredReduced<ResultObject>(
- pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
- filterObject, reduceObject, initialObject);
- QCOMPARE(result4, expectedResult);
- QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ // Result type is deduced
+ {
+ const ResultObject result1 = QtConcurrent::filteredReduced(
+ pool, sourceObjectList, filterObject, reduceObject, initialObject).result();
+ QCOMPARE(result1, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result2 =
+ QtConcurrent::filteredReduced(pool, sourceObjectList.constBegin(),
+ sourceObjectList.constEnd(), filterObject,
+ reduceObject, initialObject).result();
+ QCOMPARE(result2, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result3 = QtConcurrent::blockingFilteredReduced(
+ pool, sourceObjectList, filterObject, reduceObject, initialObject);
+ QCOMPARE(result3, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+
+ const ResultObject result4 = QtConcurrent::blockingFilteredReduced(
+ pool, sourceObjectList.constBegin(), sourceObjectList.constEnd(),
+ filterObject, reduceObject, initialObject);
+ QCOMPARE(result4, expectedResult);
+ QCOMPARE(threadCount(), 1); // ensure the only one thread was working
+ }
}
void tst_QtConcurrentFilter::filteredReducedInitialValueThreadPool()
@@ -768,6 +1192,101 @@ void tst_QtConcurrentFilter::filteredReducedInitialValueThreadPool()
testFilteredReducedInitialValueThreadPool(&pool, intList, intSum, lambdaIsOdd,
lambdaSumReduce, intInitial);
CHECK_FAIL("lambda-lambda");
+
+ // non-template sequences
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto future =
+ QtConcurrent::filteredReduced(list, keepOddIntegers, intSumReduce, intInitial);
+ QCOMPARE(future.result(), intSum);
+ }
+ {
+ NonTemplateSequence list({ 1, 2, 3, 4 });
+ auto result = QtConcurrent::blockingFilteredReduced(list, keepOddIntegers, intSumReduce,
+ intInitial);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // rvalue sequences
+ auto future = QtConcurrent::filteredReduced(&pool, std::vector { 1, 2, 3, 4 },
+ keepOddIntegers, intSumReduce, intInitial);
+ QCOMPARE(future.result(), intSum);
+
+ auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, std::vector { 1, 2, 3, 4 }, keepOddIntegers, intSumReduce, intInitial);
+ QCOMPARE(result, intSum);
+ }
+
+ {
+ // move only sequences
+ auto future = QtConcurrent::filteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepOddIntegers, intSumReduce, intInitial);
+ QCOMPARE(future.result(), intSum);
+
+ auto result =
+ QtConcurrent::blockingFilteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
+ keepOddIntegers, intSumReduce, intInitial);
+ QCOMPARE(result, intSum);
+ }
+}
+
+void tst_QtConcurrentFilter::filteredReducedInitialValueWithMoveOnlyCallables()
+{
+ const QList<int> intList { 1, 2, 3, 4 };
+ const QList<int> intListEven { 2, 4 };
+ const auto initial = 10;
+ const auto sum = 16;
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(intList, KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly(), initial).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(intList.begin(), intList.end(),
+ KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly(), initial).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ intList, KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly(), initial);
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ intList.begin(), intList.end(), KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly(),
+ initial);
+ QCOMPARE(result, sum);
+ }
+
+ QThreadPool pool;
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(&pool, intList, KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly(), initial).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result =
+ QtConcurrent::filteredReduced(
+ &pool, intList.begin(), intList.end(),
+ KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly(), initial).result();
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, intList, KeepEvenIntegersMoveOnly(), IntSumReduceMoveOnly(), initial);
+ QCOMPARE(result, sum);
+ }
+ {
+ const auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, intList.begin(), intList.end(), KeepEvenIntegersMoveOnly(),
+ IntSumReduceMoveOnly(), initial);
+ QCOMPARE(result, sum);
+ }
}
void tst_QtConcurrentFilter::filteredReducedDifferentTypeInitialValue()
@@ -820,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);
@@ -865,7 +1434,7 @@ void tst_QtConcurrentFilter::incrementalResults()
QCOMPARE(future.isFinished(), true);
QCOMPARE(future.resultCount(), count / 2);
- QCOMPARE(future.results().count(), count / 2);
+ QCOMPARE(future.results().size(), count / 2);
}
void tst_QtConcurrentFilter::noDetach()
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/.gitignore b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/.gitignore
new file mode 100644
index 0000000000..6e6bf470c9
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/.gitignore
@@ -0,0 +1 @@
+tst_qtconcurrentfiltermapgenerated
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/CMakeLists.txt
new file mode 100644
index 0000000000..12545702eb
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qtconcurrentfiltermapgenerated Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentfiltermapgenerated LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentfiltermapgenerated
+ SOURCES
+ tst_qtconcurrent_selected_tests.cpp
+ tst_qtconcurrentfiltermapgenerated.cpp tst_qtconcurrentfiltermapgenerated.h
+ LIBRARIES
+ Qt::Concurrent
+)
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/README.txt b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/README.txt
new file mode 100644
index 0000000000..63766a2a56
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/README.txt
@@ -0,0 +1,13 @@
+This directory contains a generator for unit tests for QtConcurrent.
+
+The subdirectory 'generator' contains the generator. Run the file
+"generate_gui.py" therein.
+Python3.8 and PySide2 are required.
+
+The generator writes on each click a testcase into the file
+tst_qtconcurrentfiltermapgenerated.cpp
+and
+tst_qtconcurrentfiltermapgenerated.h.
+
+Testcases which should be preserved can be copy-pasted into
+tst_qtconcurrent_selected_tests.cpp.
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generation_helpers.h b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generation_helpers.h
new file mode 100644
index 0000000000..aaa0d85002
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generation_helpers.h
@@ -0,0 +1,265 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QTBASE_GENERATION_HELPERS_H
+#define QTBASE_GENERATION_HELPERS_H
+
+#include "qglobal.h"
+
+#include <vector>
+
+struct tag_input
+{
+};
+struct tag_mapped
+{
+};
+struct tag_reduction
+{
+};
+
+template<typename tag>
+struct SequenceItem
+{
+ SequenceItem() = default;
+ // bool as a stronger "explicit": should never be called inside of QtConcurrent
+ SequenceItem(int val, bool) : value(val) { }
+
+ bool operator==(const SequenceItem<tag> &other) const { return value == other.value; }
+ bool isOdd() const { return value & 1; }
+ void multiplyByTwo() { value *= 2; }
+
+ int value = 0;
+};
+
+template<typename tag>
+struct NoConstructSequenceItem
+{
+ NoConstructSequenceItem() = delete;
+ // bool as a stronger "explicit": should never be called inside of QtConcurrent
+ NoConstructSequenceItem(int val, bool) : value(val) { }
+
+ bool operator==(const NoConstructSequenceItem<tag> &other) const
+ {
+ return value == other.value;
+ }
+ bool isOdd() const { return value & 1; }
+ void multiplyByTwo() { value *= 2; }
+
+ int value = 0;
+};
+
+template<typename tag>
+struct MoveOnlySequenceItem
+{
+ MoveOnlySequenceItem() = default;
+ ~MoveOnlySequenceItem() = default;
+ MoveOnlySequenceItem(const MoveOnlySequenceItem &) = delete;
+ MoveOnlySequenceItem(MoveOnlySequenceItem &&other) : value(other.value) { other.value = -1; }
+ MoveOnlySequenceItem &operator=(const MoveOnlySequenceItem &) = delete;
+ MoveOnlySequenceItem &operator=(MoveOnlySequenceItem &&other)
+ {
+ value = other.value;
+ other.value = -1;
+ }
+
+ // bool as a stronger "explicit": should never be called inside of QtConcurrent
+ MoveOnlySequenceItem(int val, bool) : value(val) { }
+
+ bool operator==(const MoveOnlySequenceItem<tag> &other) const { return value == other.value; }
+ bool isOdd() const { return value & 1; }
+ void multiplyByTwo() { value *= 2; }
+
+ int value = 0;
+};
+
+template<typename tag>
+struct MoveOnlyNoConstructSequenceItem
+{
+ MoveOnlyNoConstructSequenceItem() = delete;
+ ~MoveOnlyNoConstructSequenceItem() = default;
+ MoveOnlyNoConstructSequenceItem(const MoveOnlyNoConstructSequenceItem &) = delete;
+ MoveOnlyNoConstructSequenceItem(MoveOnlyNoConstructSequenceItem &&other) : value(other.value)
+ {
+ other.value = -1;
+ }
+ MoveOnlyNoConstructSequenceItem &operator=(const MoveOnlyNoConstructSequenceItem &) = delete;
+ MoveOnlyNoConstructSequenceItem &operator=(MoveOnlyNoConstructSequenceItem &&other)
+ {
+ value = other.value;
+ other.value = -1;
+ }
+
+ // bool as a stronger "explicit": should never be called inside of QtConcurrent
+ MoveOnlyNoConstructSequenceItem(int val, bool) : value(val) { }
+
+ bool operator==(const MoveOnlyNoConstructSequenceItem<tag> &other) const
+ {
+ return value == other.value;
+ }
+ bool isOdd() const { return value & 1; }
+ void multiplyByTwo() { value *= 2; }
+
+ int value = 0;
+};
+
+template<typename T>
+bool myfilter(const T &el)
+{
+ return el.isOdd();
+}
+
+template<typename T>
+class MyFilter
+{
+public:
+ bool operator()(const T &el) { return el.isOdd(); }
+};
+
+template<typename T>
+class MyMoveOnlyFilter
+{
+ bool movedFrom = false;
+
+public:
+ MyMoveOnlyFilter() = default;
+ MyMoveOnlyFilter(const MyMoveOnlyFilter<T> &) = delete;
+ MyMoveOnlyFilter &operator=(const MyMoveOnlyFilter<T> &) = delete;
+
+ MyMoveOnlyFilter(MyMoveOnlyFilter<T> &&other) { other.movedFrom = true; }
+ MyMoveOnlyFilter &operator=(MyMoveOnlyFilter<T> &&other) { other.movedFrom = true; }
+
+ bool operator()(const T &el)
+ {
+ return movedFrom || el.isOdd();
+ }
+};
+
+template<typename From, typename To>
+To myMap(const From &f)
+{
+ return To(f.value * 2, true);
+}
+
+template<typename T>
+void myInplaceMap(T &el)
+{
+ el.multiplyByTwo();
+}
+
+template<typename From, typename To>
+class MyMap
+{
+public:
+ To operator()(const From &el) { return To(el.value * 2, true); }
+};
+
+template<typename T>
+class MyInplaceMap
+{
+public:
+ void operator()(T &el) { el.multiplyByTwo(); }
+};
+
+template<typename From, typename To>
+class MyMoveOnlyMap
+{
+ bool movedFrom = false;
+
+public:
+ MyMoveOnlyMap() = default;
+ MyMoveOnlyMap(const MyMoveOnlyMap<From, To> &) = delete;
+ MyMoveOnlyMap &operator=(const MyMoveOnlyMap<From, To> &) = delete;
+
+ MyMoveOnlyMap(MyMoveOnlyMap<From, To> &&other) { other.movedFrom = true; }
+ MyMoveOnlyMap &operator=(MyMoveOnlyMap<From, To> &&other) { other.movedFrom = true; }
+
+ To operator()(const From &el)
+ {
+ if (!movedFrom)
+ return To(el.value * 2, true);
+ else
+ return To(-1, true);
+ }
+};
+
+template<typename T>
+class MyMoveOnlyInplaceMap
+{
+ bool movedFrom = false;
+
+public:
+ MyMoveOnlyInplaceMap() = default;
+ MyMoveOnlyInplaceMap(const MyMoveOnlyInplaceMap<T> &) = delete;
+ MyMoveOnlyInplaceMap &operator=(const MyMoveOnlyInplaceMap<T> &) = delete;
+
+ MyMoveOnlyInplaceMap(MyMoveOnlyInplaceMap<T> &&other) { other.movedFrom = true; }
+ MyMoveOnlyInplaceMap &operator=(MyMoveOnlyInplaceMap<T> &&other) { other.movedFrom = true; }
+
+ void operator()(T &el)
+ {
+ if (!movedFrom)
+ el.multiplyByTwo();
+ }
+};
+
+template<typename From, typename To>
+void myReduce(To &sum, const From &val)
+{
+ sum.value += val.value;
+}
+
+template<typename From, typename To>
+class MyReduce
+{
+public:
+ void operator()(To &sum, const From &val) { sum.value += val.value; }
+};
+
+template<typename From, typename To>
+class MyMoveOnlyReduce
+{
+ bool movedFrom = false;
+
+public:
+ MyMoveOnlyReduce() = default;
+ MyMoveOnlyReduce(const MyMoveOnlyReduce<From, To> &) = delete;
+ MyMoveOnlyReduce &operator=(const MyMoveOnlyReduce<From, To> &) = delete;
+
+ MyMoveOnlyReduce(MyMoveOnlyReduce<From, To> &&other) { other.movedFrom = true; }
+ MyMoveOnlyReduce &operator=(MyMoveOnlyReduce<From, To> &&other) { other.movedFrom = true; }
+
+ void operator()(To &sum, const From &val)
+ {
+ if (!movedFrom)
+ sum.value += val.value;
+ }
+};
+
+QT_BEGIN_NAMESPACE
+
+// pretty printing
+template<typename tag>
+char *toString(const SequenceItem<tag> &i)
+{
+ using QTest::toString;
+ return toString(QString::number(i.value));
+}
+
+// pretty printing
+template<typename T>
+char *toString(const std::vector<T> &vec)
+{
+ using QTest::toString;
+ QString result("");
+ for (const auto &i : vec) {
+ result.append(QString::number(i.value) + ", ");
+ }
+ if (result.size())
+ result.chop(2);
+ return toString(result);
+}
+
+QT_END_NAMESPACE
+
+#endif // QTBASE_GENERATION_HELPERS_H
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/function_signature.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/function_signature.py
new file mode 100644
index 0000000000..d87c8a2e9b
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/function_signature.py
@@ -0,0 +1,138 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+from option_management import need_separate_output_sequence
+
+
+# ["hallo", "welt"] -> "halloWelt"
+def build_camel_case(*args):
+ assert all(isinstance(x, str) for x in args)
+ if len(args) == 0:
+ return ""
+ if len(args) == 1:
+ return args[0]
+ return args[0] + "".join(x.capitalize() for x in args[1:])
+
+
+def build_function_name(options):
+ result = []
+ for part in ["blocking", "filter", "map", "reduce"]:
+ if options[part]:
+ result.append(part)
+
+ def make_potentially_passive(verb):
+ if verb == "map":
+ return "mapped"
+ if verb == "blocking":
+ return "blocking"
+
+ if verb[-1] == "e":
+ verb += "d"
+ else:
+ verb += "ed"
+
+ return verb
+
+ if not options["inplace"]:
+ result = [make_potentially_passive(x) for x in result]
+
+ result = build_camel_case(*result)
+ return result
+
+
+def build_blocking_return_type(options):
+ if options["inplace"]:
+ if options["filter"] and options["iterators"] and not options["reduce"]:
+ return "Iterator" # have to mark new end
+ else:
+ return "void"
+ else:
+ if options["reduce"]:
+ return "ResultType"
+
+ if need_separate_output_sequence(options):
+ return "OutputSequence"
+ else:
+ return "Sequence"
+
+
+def build_return_type(options):
+ if options["blocking"]:
+ return build_blocking_return_type(options)
+ else:
+ return f"QFuture<{build_blocking_return_type(options)}>"
+
+
+def build_template_argument_list(options):
+ required_types = []
+ if options["reduce"]:
+ required_types.append("typename ResultType")
+
+ need_output_sequence = need_separate_output_sequence(options)
+ if need_output_sequence:
+ required_types.append("OutputSequence")
+
+ if options["iterators"]:
+ required_types.append("Iterator")
+ else:
+ if need_output_sequence:
+ required_types.append("InputSequence")
+ else:
+ required_types.append("Sequence")
+
+ # Functors
+ if options["filter"]:
+ required_types.append("KeepFunctor")
+
+ if options["map"]:
+ required_types.append("MapFunctor")
+
+ if options["reduce"]:
+ required_types.append("ReduceFunctor")
+
+ if options["initialvalue"]:
+ required_types.append("reductionitemtype")
+
+ return "template<" + ", ".join(["typename "+x for x in required_types]) + ">"
+
+
+def build_argument_list(options):
+ required_arguments = []
+ if options["pool"]:
+ required_arguments.append("QThreadPool* pool")
+
+ if options["iterators"]:
+ required_arguments.append("Iterator begin")
+ required_arguments.append("Iterator end")
+ else:
+ if options["inplace"]:
+ required_arguments.append("Sequence & sequence")
+ else:
+ if need_separate_output_sequence(options):
+ required_arguments.append("InputSequence && sequence")
+ else:
+ required_arguments.append("const Sequence & sequence")
+
+ if options["filter"]:
+ required_arguments.append("KeepFunctor filterFunction")
+
+ if options["map"]:
+ required_arguments.append("MapFunctor function")
+
+ if options["reduce"]:
+ required_arguments.append("ReduceFunctor reduceFunction")
+ if options["initialvalue"]:
+ required_arguments.append("reductionitemtype && initialValue")
+
+ required_arguments.append("ReduceOptions")
+
+ return "(" + ", ".join(required_arguments) + ")"
+
+
+def build_function_signature(options):
+ return (build_template_argument_list(options) + "\n" +
+ build_return_type(
+ options) + " " + build_function_name(options) + build_argument_list(options)
+ + ";"
+ )
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_excel.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_excel.py
new file mode 100644
index 0000000000..d05e31fc21
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_excel.py
@@ -0,0 +1,46 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import pandas as pd
+from option_management import function_describing_options
+from function_signature import build_function_signature
+
+
+def generate_excel_file_of_functions(filename):
+ olist = []
+ for options in function_describing_options():
+ # filter out unneccesary cases:
+ if options["reduce"] and options["inplace"]:
+ # we cannot do a reduction in-place
+ options["comment"] = "reduce-inplace:nonsense"
+ options["signature"] = ""
+
+ elif options["initialvalue"] and not options["reduce"]:
+ options["comment"] = "initial-noreduce:nonsense"
+ options["signature"] = ""
+
+ elif not options["reduce"] and not options["map"] and not options["filter"]:
+ # no operation at all
+ options["comment"] = "noop"
+ options["signature"] = ""
+
+ else:
+ options["comment"] = ""
+ if options["map"] and options["filter"]:
+ options["implemented"] = "no:filter+map"
+ elif not options["map"] and not options["filter"]:
+ options["implemented"] = "no:nofilter+nomap"
+ elif options["inplace"] and options["iterators"] and options["filter"]:
+ options["implemented"] = "no:inplace+iterator+filter"
+ else:
+ options["implemented"] = "yes"
+
+ options["signature"] = build_function_signature(options)
+
+ olist.append(options)
+
+ df = pd.DataFrame(olist)
+ df.to_excel(filename)
+
+
+generate_excel_file_of_functions("functions.xls")
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_gui.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_gui.py
new file mode 100644
index 0000000000..54c1285e74
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_gui.py
@@ -0,0 +1,156 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import importlib
+import sys
+import PySide2
+from PySide2.QtCore import Signal
+from PySide2.QtWidgets import QVBoxLayout, QRadioButton, QGroupBox, QWidget, QApplication, QPlainTextEdit, QHBoxLayout
+
+import generate_testcase
+from helpers import insert_testcases_into_file
+from option_management import (Option, OptionManager, testcase_describing_options, function_describing_options,
+ skip_function_description, disabled_testcase_describing_options,
+ skip_testcase_description)
+
+
+class MyRadioButton(QRadioButton):
+ def __init__(self, value):
+ super(MyRadioButton, self).__init__(text=str(value))
+ self.value = value
+
+ self.toggled.connect(lambda x: x and self.activated.emit(self.value))
+
+ activated = Signal(object)
+
+
+class OptionSelector(QGroupBox):
+ def __init__(self, parent: QWidget, option: Option):
+ super(OptionSelector, self).__init__(title=option.name, parent=parent)
+ self.layout = QVBoxLayout()
+ self.setLayout(self.layout)
+
+ self.radiobuttons = []
+ for val in option.possible_options:
+ rb = MyRadioButton(val)
+ self.layout.addWidget(rb)
+ rb.activated.connect(lambda value: self.valueSelected.emit(option.name, value))
+ self.radiobuttons.append(rb)
+
+ self.radiobuttons[0].setChecked(True)
+
+ valueSelected = Signal(str, object)
+
+
+class OptionsSelector(QGroupBox):
+ def __init__(self, parent: QWidget, option_manager: OptionManager):
+ super(OptionsSelector, self).__init__(title=option_manager.name, parent=parent)
+ self.vlayout = QVBoxLayout()
+ self.setLayout(self.vlayout)
+ self.layout1 = QHBoxLayout()
+ self.layout2 = QHBoxLayout()
+ self.layout3 = QHBoxLayout()
+ self.vlayout.addLayout(self.layout1)
+ self.vlayout.addLayout(self.layout2)
+ self.vlayout.addLayout(self.layout3)
+ self.disabledOptions = []
+
+ self.selectors = {}
+ for option in option_manager.options.values():
+ os = OptionSelector(parent=self, option=option)
+ if "type" in option.name:
+ self.layout2.addWidget(os)
+ elif "passing" in option.name:
+ self.layout3.addWidget(os)
+ else:
+ self.layout1.addWidget(os)
+ os.valueSelected.connect(self._handle_slection)
+ self.selectors[option.name] = os
+
+ self.selectedOptionsDict = {option.name: option.possible_options[0] for option in
+ option_manager.options.values()}
+
+ def get_current_option_set(self):
+ return {k: v for k, v in self.selectedOptionsDict.items() if k not in self.disabledOptions}
+
+ def _handle_slection(self, name: str, value: object):
+ self.selectedOptionsDict[name] = value
+ self.optionsSelected.emit(self.get_current_option_set())
+
+ def set_disabled_options(self, options):
+ self.disabledOptions = options
+ for name, selector in self.selectors.items():
+ if name in self.disabledOptions:
+ selector.setEnabled(False)
+ else:
+ selector.setEnabled(True)
+
+ optionsSelected = Signal(dict)
+
+
+class MainWindow(QWidget):
+ def __init__(self):
+ super(MainWindow, self).__init__()
+ self.layout = QVBoxLayout()
+ self.setLayout(self.layout)
+
+ self.functionSelector = OptionsSelector(parent=self, option_manager=function_describing_options())
+ self.layout.addWidget(self.functionSelector)
+ self.testcaseSelector = OptionsSelector(parent=self, option_manager=testcase_describing_options())
+ self.layout.addWidget(self.testcaseSelector)
+
+ self.plainTextEdit = QPlainTextEdit()
+ self.plainTextEdit.setReadOnly(True)
+ self.layout.addWidget(self.plainTextEdit)
+ self.plainTextEdit.setFont(PySide2.QtGui.QFont("Fira Code", 8))
+
+ # temp
+ self.functionSelector.optionsSelected.connect(lambda o: self._handle_function_change())
+ self.testcaseSelector.optionsSelected.connect(lambda o: self._handle_testcase_change())
+
+ self._handle_function_change()
+
+ def _handle_function_change(self):
+ options = self.functionSelector.get_current_option_set()
+ if m := skip_function_description(options):
+ self.plainTextEdit.setPlainText(m)
+ return
+
+ options_to_disable = disabled_testcase_describing_options(options)
+ self.testcaseSelector.set_disabled_options(options_to_disable)
+
+ options.update(self.testcaseSelector.get_current_option_set())
+ if m := skip_testcase_description(options):
+ self.plainTextEdit.setPlainText(m)
+ return
+
+ self._generate_new_testcase()
+
+ def _handle_testcase_change(self):
+ options = self.functionSelector.get_current_option_set()
+ options.update(self.testcaseSelector.get_current_option_set())
+ if m := skip_testcase_description(options):
+ self.plainTextEdit.setPlainText(m)
+ return
+
+ self._generate_new_testcase()
+
+ def _generate_new_testcase(self):
+ foptions = self.functionSelector.get_current_option_set()
+ toptions = self.testcaseSelector.get_current_option_set()
+ importlib.reload(generate_testcase)
+ testcase = generate_testcase.generate_testcase(foptions, toptions)
+ self.plainTextEdit.setPlainText(testcase[1])
+ filename = "../tst_qtconcurrentfiltermapgenerated.cpp"
+ insert_testcases_into_file(filename, [testcase])
+ filename = "../tst_qtconcurrentfiltermapgenerated.h"
+ insert_testcases_into_file(filename, [testcase])
+
+
+if __name__ == "__main__":
+ app = QApplication(sys.argv)
+
+ m = MainWindow()
+ m.show()
+
+ app.exec_()
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_testcase.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_testcase.py
new file mode 100644
index 0000000000..d35a7e9065
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generate_testcase.py
@@ -0,0 +1,366 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+import textwrap
+import time
+from subprocess import Popen, PIPE
+
+from function_signature import build_function_signature, build_function_name
+from option_management import need_separate_output_sequence, qt_quirk_case
+
+
+def InputSequenceItem(toptions):
+ if toptions["inputitemtype"] == "standard":
+ return "SequenceItem<tag_input>"
+ if toptions["inputitemtype"] == "noconstruct":
+ return "NoConstructSequenceItem<tag_input>"
+ if toptions["inputitemtype"] == "moveonly":
+ return "MoveOnlySequenceItem<tag_input>"
+ if toptions["inputitemtype"] == "moveonlynoconstruct":
+ return "MoveOnlyNoConstructSequenceItem<tag_input>"
+ assert False
+
+
+def InputSequence(toptions):
+ item = InputSequenceItem(toptions)
+ if toptions["inputsequence"] == "standard":
+ return "std::vector<{}>".format(item)
+ if toptions["inputsequence"] == "moveonly":
+ return "MoveOnlyVector<{}>".format(item)
+ assert False
+
+
+def InputSequenceInitializationString(toptions):
+ t = InputSequenceItem(toptions)
+ # construct IILE
+ mystring = ("[](){" + InputSequence(toptions) + " result;\n"
+ + "\n".join("result.push_back({}({}, true));".format(t, i) for i in range(1, 7))
+ + "\n return result; }()")
+ return mystring
+
+
+def OutputSequenceItem(toptions):
+ if toptions["map"] and (toptions["inplace"] or toptions["maptype"] == "same"):
+ return InputSequenceItem(toptions)
+
+ if toptions["map"]:
+ if toptions["mappeditemtype"] == "standard":
+ return "SequenceItem<tag_mapped>"
+ if toptions["mappeditemtype"] == "noconstruct":
+ return "NoConstructSequenceItem<tag_mapped>"
+ if toptions["mappeditemtype"] == "moveonly":
+ return "MoveOnlySequenceItem<tag_mapped>"
+ if toptions["mappeditemtype"] == "moveonlynoconstruct":
+ return "MoveOnlyNoConstructSequenceItem<tag_mapped>"
+ assert(False)
+ else:
+ return InputSequenceItem(toptions)
+
+
+def ReducedItem(toptions):
+ if toptions["reductiontype"] == "same":
+ return OutputSequenceItem(toptions)
+ else:
+ if toptions["reductionitemtype"] == "standard":
+ return "SequenceItem<tag_reduction>"
+ if toptions["reductionitemtype"] == "noconstruct":
+ return "NoConstructSequenceItem<tag_reduction>"
+ if toptions["reductionitemtype"] == "moveonly":
+ return "MoveOnlySequenceItem<tag_reduction>"
+ if toptions["reductionitemtype"] == "moveonlynoconstruct":
+ return "MoveOnlyNoConstructSequenceItem<tag_reduction>"
+ assert(False)
+
+
+def OutputSequence(toptions):
+ item = OutputSequenceItem(toptions)
+ # quirk of qt: not a QFuture<Sequence> is returned
+ if qt_quirk_case(toptions):
+ return "QList<{}>".format(item)
+
+ needs_extra = need_separate_output_sequence(toptions)
+ if not needs_extra:
+ return InputSequence(toptions)
+
+
+ if toptions["outputsequence"] == "standard":
+ return "std::vector<{}>".format(item)
+ if toptions["outputsequence"] == "moveonly":
+ return "MoveOnlyVector<{}>".format(item)
+ assert False
+
+
+def resultData(toptions):
+ result = [1, 2, 3, 4, 5, 6]
+ if toptions["filter"]:
+ result = filter(lambda x: x % 2 == 1, result)
+ if toptions["map"]:
+ result = map(lambda x: 2 * x, result)
+ if toptions["reduce"]:
+ result = sum(result)
+ return result
+
+
+def OutputSequenceInitializationString(toptions):
+ t = OutputSequenceItem(toptions)
+ # construct IILE
+ mystring = ("[](){" + OutputSequence(toptions) + " result;\n"
+ + "\n".join("result.push_back({}({}, true));".format(t, i) for i in resultData(toptions))
+ + "\n return result; }()")
+ return mystring
+
+
+def OutputScalarInitializationString(toptions):
+ result = resultData(toptions)
+ assert isinstance(result, int)
+ return ReducedItem(toptions) + "(" + str(result) + ", true)"
+
+
+def FilterInitializationString(toptions):
+ item = InputSequenceItem(toptions)
+ if toptions["filterfunction"] == "function":
+ return "myfilter<{}>".format(item)
+ if toptions["filterfunction"] == "functor":
+ return "MyFilter<{}>{{}}".format(item)
+ if toptions["filterfunction"] == "memberfunction":
+ return "&{}::isOdd".format(item)
+ if toptions["filterfunction"] == "lambda":
+ return "[](const {}& x){{ return myfilter<{}>(x); }}".format(item, item)
+ if toptions["filterfunction"] == "moveonlyfunctor":
+ return "MyMoveOnlyFilter<{}>{{}}".format(item)
+ assert False
+
+
+def MapInitializationString(toptions):
+ oldtype = InputSequenceItem(toptions)
+ newtype = OutputSequenceItem(toptions)
+ if toptions["inplace"]:
+ assert oldtype == newtype
+ if toptions["mapfunction"] == "function":
+ return "myInplaceMap<{}>".format(oldtype)
+ if toptions["mapfunction"] == "functor":
+ return "MyInplaceMap<{}>{{}}".format(oldtype)
+ if toptions["mapfunction"] == "memberfunction":
+ return "&{}::multiplyByTwo".format(oldtype)
+ if toptions["mapfunction"] == "lambda":
+ return "[]({}& x){{ return myInplaceMap<{}>(x); }}".format(oldtype, oldtype)
+ if toptions["mapfunction"] == "moveonlyfunctor":
+ return "MyMoveOnlyInplaceMap<{}>{{}}".format(oldtype)
+ assert False
+ else:
+ if toptions["mapfunction"] == "function":
+ return "myMap<{f},{t}>".format(f=oldtype, t=newtype)
+ if toptions["mapfunction"] == "functor":
+ return "MyMap<{f},{t}>{{}}".format(f=oldtype, t=newtype)
+ if toptions["mapfunction"] == "memberfunction":
+ return "&{}::multiplyByTwo".format(newtype)
+ if toptions["mapfunction"] == "lambda":
+ return "[](const {f}& x){{ return myMap<{f},{t}>(x); }}".format(f=oldtype, t=newtype)
+ if toptions["mapfunction"] == "moveonlyfunctor":
+ return "MyMoveOnlyMap<{f},{t}>{{}}".format(f=oldtype, t=newtype)
+ assert False
+
+
+def ReductionInitializationString(toptions):
+ elementtype = OutputSequenceItem(toptions)
+ sumtype = ReducedItem(toptions)
+
+ if toptions["reductionfunction"] == "function":
+ return "myReduce<{f},{t}>".format(f=elementtype, t=sumtype)
+ if toptions["reductionfunction"] == "functor":
+ return "MyReduce<{f},{t}>{{}}".format(f=elementtype, t=sumtype)
+ if toptions["reductionfunction"] == "lambda":
+ return "[]({t}& sum, const {f}& x){{ return myReduce<{f},{t}>(sum, x); }}".format(f=elementtype, t=sumtype)
+ if toptions["reductionfunction"] == "moveonlyfunctor":
+ return "MyMoveOnlyReduce<{f},{t}>{{}}".format(f=elementtype, t=sumtype)
+ assert False
+
+
+def ReductionInitialvalueInitializationString(options):
+ return ReducedItem(options) + "(0, true)"
+
+
+def function_template_args(options):
+ args = []
+ out_s = OutputSequence(options)
+ in_s = InputSequence(options)
+ if options["reduce"] and options["reductionfunction"] == "lambda":
+ args.append(ReducedItem(options))
+ elif out_s != in_s:
+ if not qt_quirk_case(options):
+ args.append(out_s)
+
+ if len(args):
+ return "<" + ", ".join(args) + ">"
+
+ return ""
+
+
+numcall = 0
+
+
+def generate_testcase(function_options, testcase_options):
+ options = {**function_options, **testcase_options}
+
+ option_description = "\n".join(" {}={}".format(
+ a, b) for a, b in testcase_options.items())
+ option_description = textwrap.indent(option_description, " "*12)
+ function_signature = textwrap.indent(build_function_signature(function_options), " "*12)
+ testcase_name = "_".join("{}_{}".format(x, y) for x, y in options.items())
+ global numcall
+ numcall += 1
+ testcase_name = "test" + str(numcall)
+ function_name = build_function_name(options)
+
+ arguments = []
+
+ template_args = function_template_args(options)
+
+ # care about the thread pool
+ if options["pool"]:
+ pool_initialization = """QThreadPool pool;
+ pool.setMaxThreadCount(1);"""
+ arguments.append("&pool")
+ else:
+ pool_initialization = ""
+
+ # care about the input sequence
+ input_sequence_initialization_string = InputSequenceInitializationString(options)
+
+ if "inputsequencepassing" in options and options["inputsequencepassing"] == "lvalue" or options["inplace"]:
+ input_sequence_initialization = "auto input_sequence = " + \
+ input_sequence_initialization_string + ";"
+ arguments.append("input_sequence")
+ elif "inputsequencepassing" in options and options["inputsequencepassing"] == "rvalue":
+ input_sequence_initialization = ""
+ arguments.append(input_sequence_initialization_string)
+ else:
+ input_sequence_initialization = "auto input_sequence = " + \
+ input_sequence_initialization_string + ";"
+ arguments.append("input_sequence.begin()")
+ arguments.append("input_sequence.end()")
+
+ # care about the map:
+ if options["map"]:
+ map_initialization_string = MapInitializationString(options)
+ if options["mapfunctionpassing"] == "lvalue":
+ map_initialization = "auto map = " + map_initialization_string + ";"
+ arguments.append("map")
+ elif options["mapfunctionpassing"] == "rvalue":
+ map_initialization = ""
+ arguments.append(map_initialization_string)
+ else:
+ assert False
+ else:
+ map_initialization = ""
+
+ # care about the filter
+ if options["filter"]:
+ filter_initialization_string = FilterInitializationString(options)
+ if options["filterfunctionpassing"] == "lvalue":
+ filter_initialization = "auto filter = " + filter_initialization_string + ";"
+ arguments.append("filter")
+ elif options["filterfunctionpassing"] == "rvalue":
+ filter_initialization = ""
+ arguments.append(filter_initialization_string)
+ else:
+ assert (False)
+ else:
+ filter_initialization = ""
+
+ reduction_initialvalue_initialization = ""
+ # care about reduction
+ if options["reduce"]:
+ reduction_initialization_expression = ReductionInitializationString(options)
+ if options["reductionfunctionpassing"] == "lvalue":
+ reduction_initialization = "auto reductor = " + reduction_initialization_expression + ";"
+ arguments.append("reductor")
+ elif options["reductionfunctionpassing"] == "rvalue":
+ reduction_initialization = ""
+ arguments.append(reduction_initialization_expression)
+ else:
+ assert (False)
+
+ # initialvalue:
+ if options["initialvalue"]:
+ reduction_initialvalue_initialization_expression = ReductionInitialvalueInitializationString(options)
+ if options["reductioninitialvaluepassing"] == "lvalue":
+ reduction_initialvalue_initialization = "auto initialvalue = " + reduction_initialvalue_initialization_expression + ";"
+ arguments.append("initialvalue")
+ elif options["reductioninitialvaluepassing"] == "rvalue":
+ reduction_initialvalue_initialization = ""
+ arguments.append(reduction_initialvalue_initialization_expression)
+ else:
+ assert (False)
+
+ if options["reductionoptions"] == "UnorderedReduce":
+ arguments.append("QtConcurrent::UnorderedReduce")
+ elif options["reductionoptions"] == "OrderedReduce":
+ arguments.append("QtConcurrent::OrderedReduce")
+ elif options["reductionoptions"] == "SequentialReduce":
+ arguments.append("QtConcurrent::SequentialReduce")
+ else:
+ assert options["reductionoptions"] == "unspecified"
+ else:
+ reduction_initialization = ""
+
+ # what is the expected result
+ if options["filter"]:
+ if not options["reduce"]:
+ expected_result_expression = OutputSequenceInitializationString(options)
+ else:
+ expected_result_expression = OutputScalarInitializationString(options)
+ elif options["map"]:
+ if not options["reduce"]:
+ expected_result_expression = OutputSequenceInitializationString(options)
+ else:
+ expected_result_expression = OutputScalarInitializationString(options)
+
+ wait_result_expression = ""
+ if options["inplace"]:
+ if options["blocking"]:
+ result_accepting = ""
+ result_variable = "input_sequence"
+ else:
+ result_accepting = "auto future = "
+ result_variable = "input_sequence"
+ wait_result_expression = "future.waitForFinished();"
+ elif options["blocking"]:
+ result_accepting = "auto result = "
+ result_variable = "result"
+ else:
+ if not options["reduce"]:
+ result_accepting = "auto result = "
+ result_variable = "result.results()"
+ else:
+ result_accepting = "auto result = "
+ result_variable = "result.takeResult()"
+
+ arguments_passing = ", ".join(arguments)
+ final_string = f"""
+ void tst_QtConcurrentFilterMapGenerated::{testcase_name}()
+ {{
+ /* test for
+{function_signature}
+
+ with
+{option_description}
+ */
+
+ {pool_initialization}
+ {input_sequence_initialization}
+ {filter_initialization}
+ {map_initialization}
+ {reduction_initialization}
+ {reduction_initialvalue_initialization}
+
+ {result_accepting}QtConcurrent::{function_name}{template_args}({arguments_passing});
+
+ auto expected_result = {expected_result_expression};
+ {wait_result_expression}
+ QCOMPARE({result_variable}, expected_result);
+ }}
+ """
+ p = Popen(["clang-format"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ final_string = p.communicate(final_string.encode())[0].decode()
+
+ return (f" void {testcase_name}();\n", final_string)
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generator_main.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generator_main.py
new file mode 100644
index 0000000000..87cb4c7bc4
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/generator_main.py
@@ -0,0 +1,33 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+from option_management import function_describing_options, skip_function_description, testcase_describing_options
+from generate_testcase import generate_testcase
+from helpers import insert_testcases_into_file
+filename = "../tst_qtconcurrentfiltermapgenerated.cpp"
+
+testcases = []
+counter = 0
+for fo in function_describing_options():
+ if skip_function_description(fo):
+ continue
+
+ if not (
+ fo["blocking"]
+ and fo["filter"]
+ # and not fo["map"]
+ and fo["reduce"]
+ and not fo["inplace"]
+ and not fo["iterators"]
+ and not fo["initialvalue"]
+ and not fo["pool"]
+ ):
+ continue
+
+ for to in testcase_describing_options(fo):
+ print("generate test")
+ testcases.append(generate_testcase(fo, to))
+ counter += 1
+
+print(counter)
+insert_testcases_into_file(filename, testcases)
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/helpers.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/helpers.py
new file mode 100644
index 0000000000..fbe969789c
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/helpers.py
@@ -0,0 +1,31 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+
+def insert_testcases_into_file(filename, testcases):
+ # assume testcases is an array of tuples of (declaration, definition)
+ with open(filename) as f:
+ inputlines = f.readlines()
+ outputlines = []
+ skipping = False
+ for line in inputlines:
+ if not skipping:
+ outputlines.append(line)
+ else:
+ if "END_GENERATED" in line:
+ outputlines.append(line)
+ skipping = False
+
+ if "START_GENERATED_SLOTS" in line:
+ # put in testcases
+ outputlines += [t[0] for t in testcases]
+ skipping = True
+
+ if "START_GENERATED_IMPLEMENTATIONS" in line:
+ # put in testcases
+ outputlines += [t[1] for t in testcases]
+ skipping = True
+
+ if outputlines != inputlines:
+ with open(filename, "w") as f:
+ f.writelines(outputlines)
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/option_management.py b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/option_management.py
new file mode 100644
index 0000000000..6a1fc87f9f
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/generator/option_management.py
@@ -0,0 +1,195 @@
+# Copyright (C) 2020 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import itertools
+
+
+class Option:
+ def __init__(self, name, possible_options):
+ self.name = name
+ self.possible_options = possible_options
+
+
+class OptionManager:
+ def __init__(self, name):
+ self.options = {}
+ self.name = name
+
+ def add_option(self, option: Option):
+ self.options[option.name] = option
+
+ def iterate(self):
+ for x in itertools.product(*[
+ [(name, x) for x in self.options[name]]
+ for name in self.options.keys()
+ ]):
+ yield dict(x)
+
+
+def function_describing_options():
+ om = OptionManager("function options")
+
+ om.add_option(Option("blocking", [True, False]))
+ om.add_option(Option("filter", [True, False]))
+ om.add_option(Option("map", [False, True]))
+ om.add_option(Option("reduce", [False, True]))
+ om.add_option(Option("inplace", [True, False]))
+ om.add_option(Option("iterators", [False, True]))
+ om.add_option(Option("initialvalue", [False, True]))
+ om.add_option(Option("pool", [True, False]))
+
+ return om
+
+
+def skip_function_description(options):
+ if options["reduce"] and options["inplace"]:
+ return "we cannot do a reduction in-place"
+
+ if options["initialvalue"] and not options["reduce"]:
+ return "without reduction, we do not need an initial value"
+
+ if not options["reduce"] and not options["map"] and not options["filter"]:
+ return "no operation at all"
+
+ # the following things are skipped because Qt does not support them
+ if options["filter"] and options["map"]:
+ return "Not supported by Qt: both map and filter operation"
+
+ if not options["filter"] and not options["map"]:
+ return "Not supported by Qt: no map and no filter operation"
+
+ if options["inplace"] and options["iterators"] and options["filter"]:
+ return "Not supported by Qt: filter operation in-place with iterators"
+
+ return False
+
+
+def qt_quirk_case(options):
+ # whenever a function should return a QFuture<Sequence>,
+ # it returns a QFuture<item> instead
+ if options["inplace"] or options["reduce"] or options["blocking"]:
+ return False
+
+ return True
+
+
+def need_separate_output_sequence(options):
+ # do we need an output sequence?
+ if not (options["inplace"] or options["reduce"]):
+ # transforming a sequence into a sequence
+ if options["iterators"] or options["map"]:
+ return True
+
+ return False
+
+
+def testcase_describing_options():
+ om = OptionManager("testcase options")
+
+ om.add_option(Option("inputsequence", ["standard", "moveonly"]))
+ om.add_option(Option("inputsequencepassing", ["lvalue", "rvalue"]))
+ om.add_option(Option("inputitemtype", ["standard", "noconstruct", "moveonly", "moveonlynoconstruct"]))
+
+ om.add_option(Option("outputsequence", ["standard", "moveonly"]))
+
+ om.add_option(Option("maptype", ["same", "different"]))
+ om.add_option(Option("mappeditemtype", ["standard", "noconstruct", "moveonly", "moveonlynoconstruct"]))
+
+ om.add_option(Option("reductiontype", ["same", "different"]))
+
+ om.add_option(Option("reductionitemtype", [
+ "standard", "noconstruct", "moveonly", "moveonlynoconstruct"]))
+
+ om.add_option(Option("filterfunction", ["functor", "function", "memberfunction", "lambda", "moveonlyfunctor"]))
+ om.add_option(Option("filterfunctionpassing", ["lvalue", "rvalue"]))
+
+ om.add_option(Option("mapfunction", ["functor", "function", "memberfunction", "lambda", "moveonlyfunctor"]))
+ om.add_option(Option("mapfunctionpassing", ["lvalue", "rvalue"]))
+
+ om.add_option(Option("reductionfunction", ["functor", "function", "lambda", "moveonlyfunctor"]))
+ om.add_option(Option("reductionfunctionpassing", ["lvalue", "rvalue"]))
+
+ om.add_option(Option("reductioninitialvaluepassing", ["lvalue", "rvalue"]))
+
+ om.add_option(Option("reductionoptions", [
+ "unspecified", "UnorderedReduce", "OrderedReduce", "SequentialReduce"]))
+
+ return om
+
+
+def disabled_testcase_describing_options(options):
+ disabled_options = []
+
+ if options["inplace"] or options["iterators"]:
+ disabled_options.append("inputsequencepassing")
+
+ if not need_separate_output_sequence(options):
+ disabled_options.append("outputsequence")
+
+ if not options["map"]:
+ disabled_options.append("mappeditemtype")
+
+ if options["map"] and options["inplace"]:
+ disabled_options.append("mappeditemtype")
+
+ if not options["filter"]:
+ disabled_options.append("filterfunction")
+ disabled_options.append("filterfunctionpassing")
+
+ if not options["map"]:
+ disabled_options.append("mapfunction")
+ disabled_options.append("mapfunctionpassing")
+
+ if not options["reduce"]:
+ disabled_options.append("reductionfunction")
+ disabled_options.append("reductionfunctionpassing")
+
+ if not options["reduce"]:
+ disabled_options.append("reductiontype")
+ disabled_options.append("reductioninitialvaluepassing")
+ disabled_options.append("reductionoptions")
+ disabled_options.append("reductionitemtype")
+
+ if not options["initialvalue"]:
+ disabled_options.append("reductioninitialvaluepassing")
+
+ if not options["map"]:
+ disabled_options.append("maptype")
+ else:
+ if options["inplace"]:
+ disabled_options.append("maptype")
+
+ return disabled_options
+
+
+def skip_testcase_description(options):
+ if (
+ "maptype" in options and
+ options["maptype"] == "same" and
+ "inputitemtype" in options and "mappeditemtype" in options and
+ (options["inputitemtype"] != options["mappeditemtype"])
+ ):
+ return ("Not possible: map should map to same type, "
+ "but mapped item type should differ from input item type.")
+
+ if (
+ "reductiontype" in options and
+ options["reductiontype"] == "same"):
+ # we have to check that this is possible
+ if ("mappeditemtype" in options and "reductionitemtype" in options
+ and (options["mappeditemtype"] != options["reductionitemtype"])
+ ):
+ return ("Not possible: should reduce in the same type, "
+ "but reduction item type should differ from mapped item type.")
+ if ("mappeditemtype" not in options
+ and (options["inputitemtype"] != options["reductionitemtype"])):
+ return ("Not possible: should reduce in the same type, "
+ "but reduction item type should differ from input item type.")
+
+ if (
+ options["map"] and not options["inplace"]
+ and options["mapfunction"] == "memberfunction"
+ ):
+ return "map with memberfunction only available for in-place map"
+
+ return False
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrent_selected_tests.cpp b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrent_selected_tests.cpp
new file mode 100644
index 0000000000..edb7cce4c9
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrent_selected_tests.cpp
@@ -0,0 +1,347 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "tst_qtconcurrentfiltermapgenerated.h"
+
+void tst_QtConcurrentFilterMapGenerated::mapReduceThroughDifferentTypes()
+{
+ /* test for
+ template<typename typename ResultType, typename Iterator, typename MapFunctor, typename
+ ReduceFunctor, typename reductionitemtype> ResultType blockingMappedReduced(Iterator begin,
+ Iterator end, MapFunctor function, ReduceFunctor reduceFunction, reductionitemtype &&
+ initialValue, ReduceOptions);
+
+ with
+ inputsequence=standard
+ inputitemtype=standard
+ maptype=different
+ mappeditemtype=standard
+ reductiontype=different
+ reductionitemtype=standard
+ mapfunction=function
+ mapfunctionpassing=lvalue
+ reductionfunction=function
+ reductionfunctionpassing=lvalue
+ reductioninitialvaluepassing=lvalue
+ reductionoptions=unspecified
+ */
+
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ auto map = myMap<SequenceItem<tag_input>, SequenceItem<tag_mapped>>;
+ auto reductor = myReduce<SequenceItem<tag_mapped>, SequenceItem<tag_reduction>>;
+ auto initialvalue = SequenceItem<tag_reduction>(0, true);
+
+ auto result = QtConcurrent::blockingMappedReduced(input_sequence.begin(), input_sequence.end(),
+ map, reductor, initialvalue);
+
+ auto expected_result = SequenceItem<tag_reduction>(42, true);
+ QCOMPARE(result, expected_result);
+}
+
+void tst_QtConcurrentFilterMapGenerated::moveOnlyFilterObject()
+{
+ /* test for
+ template<typename Sequence, typename KeepFunctor>
+ void blockingFilter(QThreadPool* pool, Sequence & sequence, KeepFunctor filterFunction);
+
+ with
+ inputsequence=standard
+ inputitemtype=standard
+ filterfunction=moveonlyfunctor
+ filterfunctionpassing=rvalue
+ */
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ QtConcurrent::blockingFilter(&pool, input_sequence,
+ MyMoveOnlyFilter<SequenceItem<tag_input>> {});
+
+ auto expected_result = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ return result;
+ }();
+
+ QCOMPARE(input_sequence, expected_result);
+}
+
+void tst_QtConcurrentFilterMapGenerated::moveOnlyMapObject()
+{
+ /* test for
+ template<typename Sequence, typename MapFunctor>
+ void blockingMap(QThreadPool* pool, Sequence & sequence, MapFunctor function);
+
+ with
+ inputsequence=standard
+ inputitemtype=standard
+ mapfunction=moveonlyfunctor
+ mapfunctionpassing=rvalue
+ */
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ QtConcurrent::blockingMap(&pool, input_sequence,
+ MyMoveOnlyInplaceMap<SequenceItem<tag_input>> {});
+
+ auto expected_result = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ result.push_back(SequenceItem<tag_input>(8, true));
+ result.push_back(SequenceItem<tag_input>(10, true));
+ result.push_back(SequenceItem<tag_input>(12, true));
+ return result;
+ }();
+
+ QCOMPARE(input_sequence, expected_result);
+}
+
+void tst_QtConcurrentFilterMapGenerated::moveOnlyReduceObject()
+{
+ /* test for
+ template<typename typename ResultType, typename Sequence, typename MapFunctor, typename
+ ReduceFunctor> ResultType blockingMappedReduced(QThreadPool* pool, const Sequence & sequence,
+ MapFunctor function, ReduceFunctor reduceFunction, ReduceOptions);
+
+ with
+ inputsequence=standard
+ inputsequencepassing=lvalue
+ inputitemtype=standard
+ maptype=same
+ mappeditemtype=standard
+ reductiontype=same
+ reductionitemtype=standard
+ mapfunction=functor
+ mapfunctionpassing=lvalue
+ reductionfunction=moveonlyfunctor
+ reductionfunctionpassing=rvalue
+ reductionoptions=unspecified
+ */
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ auto map = MyMap<SequenceItem<tag_input>, SequenceItem<tag_input>> {};
+
+ auto result = QtConcurrent::blockingMappedReduced<SequenceItem<tag_input>>(
+ &pool, input_sequence, map,
+ MyMoveOnlyReduce<SequenceItem<tag_input>, SequenceItem<tag_input>> {});
+
+ auto expected_result = SequenceItem<tag_input>(42, true);
+
+ QCOMPARE(result, expected_result);
+}
+
+void tst_QtConcurrentFilterMapGenerated::functorAsReduction()
+{
+ /* test for
+ template<typename typename ResultType, typename Sequence, typename KeepFunctor, typename
+ ReduceFunctor, typename reductionitemtype> ResultType blockingFilteredReduced(QThreadPool* pool,
+ const Sequence & sequence, KeepFunctor filterFunction, ReduceFunctor reduceFunction,
+ reductionitemtype && initialValue, ReduceOptions);
+
+ with
+ inputsequence=standard
+ inputsequencepassing=lvalue
+ inputitemtype=standard
+ reductiontype=same
+ reductionitemtype=standard
+ filterfunction=functor
+ filterfunctionpassing=lvalue
+ reductionfunction=functor
+ reductionfunctionpassing=lvalue
+ reductioninitialvaluepassing=lvalue
+ reductionoptions=unspecified
+ */
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+ auto filter = MyFilter<SequenceItem<tag_input>> {};
+
+ auto reductor = MyReduce<SequenceItem<tag_input>, SequenceItem<tag_input>> {};
+ auto initialvalue = SequenceItem<tag_input>(0, true);
+
+ auto result = QtConcurrent::blockingFilteredReduced<SequenceItem<tag_input>>(
+ &pool, input_sequence, filter, reductor, initialvalue);
+
+ auto expected_result = SequenceItem<tag_input>(9, true);
+
+ QCOMPARE(result, expected_result);
+}
+
+void tst_QtConcurrentFilterMapGenerated::moveOnlyReductionItem()
+{
+ /* test for
+ template<typename typename ResultType, typename Sequence, typename KeepFunctor, typename
+ ReduceFunctor, typename reductionitemtype> ResultType blockingFilteredReduced(QThreadPool* pool,
+ const Sequence & sequence, KeepFunctor filterFunction, ReduceFunctor reduceFunction,
+ reductionitemtype && initialValue, ReduceOptions);
+
+ with
+ inputsequence=standard
+ inputsequencepassing=lvalue
+ inputitemtype=standard
+ reductiontype=different
+ reductionitemtype=moveonly
+ filterfunction=moveonlyfunctor
+ filterfunctionpassing=rvalue
+ reductionfunction=function
+ reductionfunctionpassing=lvalue
+ reductioninitialvaluepassing=rvalue
+ reductionoptions=unspecified
+ */
+/* TODO: does not work yet
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ auto reductor = myReduce<SequenceItem<tag_input>, MoveOnlySequenceItem<tag_reduction>>;
+
+ auto result = QtConcurrent::blockingFilteredReduced(
+ &pool, input_sequence, MyMoveOnlyFilter<SequenceItem<tag_input>> {}, reductor,
+ MoveOnlySequenceItem<tag_reduction>(0, true));
+
+ auto expected_result = MoveOnlySequenceItem<tag_reduction>(9, true);
+
+ QCOMPARE(result, expected_result);*/
+}
+
+void tst_QtConcurrentFilterMapGenerated::noDefaultConstructorItemMapped()
+{
+ /* test for
+ template<typename typename ResultType, typename Sequence, typename MapFunctor, typename
+ ReduceFunctor, typename reductionitemtype> ResultType blockingMappedReduced(QThreadPool* pool,
+ const Sequence & sequence, MapFunctor function, ReduceFunctor reduceFunction, reductionitemtype
+ && initialValue, ReduceOptions);
+
+ with
+ inputsequence=standard
+ inputsequencepassing=lvalue
+ inputitemtype=standard
+ maptype=same
+ mappeditemtype=standard
+ reductiontype=different
+ reductionitemtype=noconstruct
+ mapfunction=functor
+ mapfunctionpassing=lvalue
+ reductionfunction=function
+ reductionfunctionpassing=lvalue
+ reductioninitialvaluepassing=lvalue
+ reductionoptions=unspecified
+ */
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ auto map = MyMap<SequenceItem<tag_input>, SequenceItem<tag_input>> {};
+ auto reductor = myReduce<SequenceItem<tag_input>, NoConstructSequenceItem<tag_reduction>>;
+ auto initialvalue = NoConstructSequenceItem<tag_reduction>(0, true);
+
+ auto result =
+ QtConcurrent::blockingMappedReduced(&pool, input_sequence, map, reductor, initialvalue);
+
+ auto expected_result = NoConstructSequenceItem<tag_reduction>(42, true);
+
+ QCOMPARE(result, expected_result);
+}
+
+void tst_QtConcurrentFilterMapGenerated::noDefaultConstructorItemFiltered()
+{
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+
+ auto filter = MyFilter<SequenceItem<tag_input>> {};
+ auto reductor = myReduce<SequenceItem<tag_input>, NoConstructSequenceItem<tag_reduction>>;
+ auto initialvalue = NoConstructSequenceItem<tag_reduction>(0, true);
+
+ auto result = QtConcurrent::blockingFilteredReduced(&pool, input_sequence, filter, reductor,
+ initialvalue);
+
+ auto expected_result = NoConstructSequenceItem<tag_reduction>(9, true);
+
+ QCOMPARE(result, expected_result);
+}
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.cpp b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.cpp
new file mode 100644
index 0000000000..089ca3f867
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <qtconcurrentfilter.h>
+#include <qtconcurrentmap.h>
+#include <QCoreApplication>
+#include <QList>
+#include <QTest>
+
+#include "../testhelper_functions.h"
+#include "generation_helpers.h"
+
+#include "tst_qtconcurrentfiltermapgenerated.h"
+
+using namespace QtConcurrent;
+
+// START_GENERATED_IMPLEMENTATIONS (see generate_tests.py)
+
+void tst_QtConcurrentFilterMapGenerated::test1()
+{
+ /* test for
+ template<typename Sequence, typename KeepFunctor>
+ void blockingFilter(QThreadPool* pool, Sequence & sequence, KeepFunctor filterFunction);
+
+ with
+ inputsequence=standard
+ inputitemtype=standard
+ filterfunction=functor
+ filterfunctionpassing=lvalue
+ */
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(1);
+ auto input_sequence = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(2, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(4, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ result.push_back(SequenceItem<tag_input>(6, true));
+ return result;
+ }();
+ auto filter = MyFilter<SequenceItem<tag_input>> {};
+
+ QtConcurrent::blockingFilter(&pool, input_sequence, filter);
+
+ auto expected_result = []() {
+ std::vector<SequenceItem<tag_input>> result;
+ result.push_back(SequenceItem<tag_input>(1, true));
+ result.push_back(SequenceItem<tag_input>(3, true));
+ result.push_back(SequenceItem<tag_input>(5, true));
+ return result;
+ }();
+
+ QCOMPARE(input_sequence, expected_result);
+}
+// END_GENERATED_IMPLEMENTATION (see generate_tests.py)
+
+QTEST_MAIN(tst_QtConcurrentFilterMapGenerated)
diff --git a/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.h b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.h
new file mode 100644
index 0000000000..31b62ac4fd
--- /dev/null
+++ b/tests/auto/concurrent/qtconcurrentfiltermapgenerated/tst_qtconcurrentfiltermapgenerated.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <qtconcurrentfilter.h>
+#include <qtconcurrentmap.h>
+#include <QTest>
+
+#include "generation_helpers.h"
+
+using namespace QtConcurrent;
+
+class tst_QtConcurrentFilterMapGenerated : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void mapReduceThroughDifferentTypes();
+ void moveOnlyFilterObject();
+ void moveOnlyMapObject();
+ void moveOnlyReduceObject();
+ void functorAsReduction();
+ void moveOnlyReductionItem();
+ void noDefaultConstructorItemMapped();
+ void noDefaultConstructorItemFiltered();
+ // START_GENERATED_SLOTS (see generate_tests.py)
+ void test1();
+ // END_GENERATED_SLOTS (see generate_tests.py)
+};
diff --git a/tests/auto/concurrent/qtconcurrentiteratekernel/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentiteratekernel/CMakeLists.txt
index e73d574fcb..2eea340795 100644
--- a/tests/auto/concurrent/qtconcurrentiteratekernel/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrentiteratekernel/CMakeLists.txt
@@ -1,12 +1,19 @@
-# Generated from qtconcurrentiteratekernel.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrentiteratekernel Test:
#####################################################################
-qt_add_test(tst_qtconcurrentiteratekernel
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentiteratekernel LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentiteratekernel
SOURCES
tst_qtconcurrentiteratekernel.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
)
diff --git a/tests/auto/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro b/tests/auto/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro
deleted file mode 100644
index f599372c6f..0000000000
--- a/tests/auto/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrentiteratekernel
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrentiteratekernel.cpp
diff --git a/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp b/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp
index 574c82b78e..27113ad8b7 100644
--- a/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp
+++ b/tests/auto/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp
@@ -1,31 +1,7 @@
-/****************************************************************************
-**
-** 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 <QThread>
+#include <QSet>
struct TestIterator
{
@@ -67,7 +43,7 @@ int distance(TestIterator &a, TestIterator &b)
}
#include <qtconcurrentiteratekernel.h>
-#include <QtTest/QtTest>
+#include <QTest>
using namespace QtConcurrent;
@@ -126,7 +102,8 @@ public:
void tst_QtConcurrentIterateKernel::instantiate()
{
- startThreadEngine(new PrintFor(0, 40)).startBlocking();
+ auto future = startThreadEngine(new PrintFor(0, 40)).startAsynchronously();
+ future.waitForFinished();
QCOMPARE(iterations.loadRelaxed(), 40);
}
@@ -165,8 +142,10 @@ void tst_QtConcurrentIterateKernel::stresstest()
const int times = 50;
for (int i = 0; i < times; ++i) {
counter.storeRelaxed(0);
- CountFor f(0, iterations);
- f.startBlocking();
+ // ThreadEngine will delete f when it finishes
+ auto f = new CountFor(0, iterations);
+ auto future = f->startAsynchronously();
+ future.waitForFinished();
QCOMPARE(counter.loadRelaxed(), iterations);
}
}
@@ -174,8 +153,12 @@ void tst_QtConcurrentIterateKernel::stresstest()
void tst_QtConcurrentIterateKernel::noIterations()
{
const int times = 20000;
- for (int i = 0; i < times; ++i)
- startThreadEngine(new IterateKernel<TestIterator, void>(QThreadPool::globalInstance(), 0, 0)).startBlocking();
+ for (int i = 0; i < times; ++i) {
+ auto future = startThreadEngine(new IterateKernel<TestIterator, void>(
+ QThreadPool::globalInstance(), 0, 0))
+ .startAsynchronously();
+ future.waitForFinished();
+ }
}
QMutex threadsMutex;
@@ -230,13 +213,15 @@ void tst_QtConcurrentIterateKernel::throttling()
threads.clear();
- ThrottleFor f(0, totalIterations);
- f.startBlocking();
+ // ThreadEngine will delete f when it finishes
+ auto f = new ThrottleFor(0, totalIterations);
+ auto future = f->startAsynchronously();
+ future.waitForFinished();
QCOMPARE(iterations.loadRelaxed(), totalIterations);
- QCOMPARE(threads.count(), 1);
+ QCOMPARE(threads.size(), 1);
}
class MultipleResultsFor : public IterateKernel<TestIterator, int>
@@ -254,7 +239,7 @@ public:
void tst_QtConcurrentIterateKernel::multipleResults()
{
QFuture<int> f = startThreadEngine(new MultipleResultsFor(0, 10)).startAsynchronously();
- QCOMPARE(f.results().count() , 10);
+ QCOMPARE(f.results().size() , 10);
QCOMPARE(f.resultAt(0), 0);
QCOMPARE(f.resultAt(5), 5);
QCOMPARE(f.resultAt(9), 9);
diff --git a/tests/auto/concurrent/qtconcurrentmap/.prev_CMakeLists.txt b/tests/auto/concurrent/qtconcurrentmap/.prev_CMakeLists.txt
deleted file mode 100644
index be51bf09bd..0000000000
--- a/tests/auto/concurrent/qtconcurrentmap/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated from qtconcurrentmap.pro.
-
-#####################################################################
-## tst_qtconcurrentmap Test:
-#####################################################################
-
-add_qt_test(tst_qtconcurrentmap
- SOURCES
- tst_qtconcurrentmap.cpp
- DEFINES
- -QT_NO_LINKED_LIST
- PUBLIC_LIBRARIES
- Qt::Concurrent
-)
-
-## Scopes:
-#####################################################################
diff --git a/tests/auto/concurrent/qtconcurrentmap/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentmap/CMakeLists.txt
index c14780e0de..62b434a25f 100644
--- a/tests/auto/concurrent/qtconcurrentmap/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrentmap/CMakeLists.txt
@@ -1,13 +1,20 @@
-# Generated from qtconcurrentmap.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrentmap Test:
#####################################################################
-qt_add_test(tst_qtconcurrentmap
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentmap LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentmap
SOURCES
tst_qtconcurrentmap.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
)
diff --git a/tests/auto/concurrent/qtconcurrentmap/functions.h b/tests/auto/concurrent/qtconcurrentmap/functions.h
deleted file mode 100644
index b37ea08716..0000000000
--- a/tests/auto/concurrent/qtconcurrentmap/functions.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-#ifndef FUNCTIONS_H
-#define FUNCTIONS_H
-
-bool keepEvenIntegers(const int &x)
-{
- return (x & 1) == 0;
-}
-
-class KeepEvenIntegers
-{
-public:
- bool operator()(const int &x)
- {
- return (x & 1) == 0;
- }
-};
-
-class Number
-{
- int n;
-
-public:
- Number()
- : n(0)
- { }
-
- Number(int n)
- : n(n)
- { }
-
- void multiplyBy2()
- {
- n *= 2;
- }
-
- Number multipliedBy2() const
- {
- return n * 2;
- }
-
- bool isEven() const
- {
- return (n & 1) == 0;
- }
-
- int toInt() const
- {
- return n;
- }
-
- QString toString() const
- {
- return QString::number(n);
- }
-
- Number squared() const
- {
- return Number(n * n);
- }
-
- bool operator==(const Number &other) const
- {
- return n == other.n;
- }
-};
-
-bool keepEvenNumbers(const Number &x)
-{
- return (x.toInt() & 1) == 0;
-}
-
-class KeepEvenNumbers
-{
-public:
- bool operator()(const Number &x)
- {
- return (x.toInt() & 1) == 0;
- }
-};
-
-void intSumReduce(int &sum, int x)
-{
- sum += x;
-}
-
-class IntSumReduce
-{
-public:
- void operator()(int &sum, int x)
- {
- sum += x;
- }
-};
-
-void numberSumReduce(int &sum, const Number &x)
-{
- sum += x.toInt();
-}
-
-class NumberSumReduce
-{
-public:
- void operator()(int &sum, const Number &x)
- {
- sum += x.toInt();
- }
-};
-
-#endif
diff --git a/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro b/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro
deleted file mode 100644
index bbadd1ada1..0000000000
--- a/tests/auto/concurrent/qtconcurrentmap/qtconcurrentmap.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrentmap
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrentmap.cpp
-
-# Force C++17 if available
-contains(QT_CONFIG, c++1z): CONFIG += c++1z
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)
diff --git a/tests/auto/concurrent/qtconcurrentmedian/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentmedian/CMakeLists.txt
index 5d7e95049f..63f0135467 100644
--- a/tests/auto/concurrent/qtconcurrentmedian/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrentmedian/CMakeLists.txt
@@ -1,12 +1,19 @@
-# Generated from qtconcurrentmedian.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrentmedian Test:
#####################################################################
-qt_add_test(tst_qtconcurrentmedian
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentmedian LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentmedian
SOURCES
tst_qtconcurrentmedian.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
)
diff --git a/tests/auto/concurrent/qtconcurrentmedian/qtconcurrentmedian.pro b/tests/auto/concurrent/qtconcurrentmedian/qtconcurrentmedian.pro
deleted file mode 100644
index 59e22d24a1..0000000000
--- a/tests/auto/concurrent/qtconcurrentmedian/qtconcurrentmedian.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrentmedian
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrentmedian.cpp
diff --git a/tests/auto/concurrent/qtconcurrentmedian/tst_qtconcurrentmedian.cpp b/tests/auto/concurrent/qtconcurrentmedian/tst_qtconcurrentmedian.cpp
index 22e555d2db..7eea013c8b 100644
--- a/tests/auto/concurrent/qtconcurrentmedian/tst_qtconcurrentmedian.cpp
+++ b/tests/auto/concurrent/qtconcurrentmedian/tst_qtconcurrentmedian.cpp
@@ -1,33 +1,9 @@
-/****************************************************************************
-**
-** 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 <qtconcurrentmedian.h>
-#include <QtTest/QtTest>
+#include <QTest>
class tst_QtConcurrentMedian: public QObject
{
@@ -73,11 +49,11 @@ void tst_QtConcurrentMedian::median_data()
void tst_QtConcurrentMedian::median()
{
- QFETCH(QList<double> , values);
+ QFETCH(const QList<double> , values);
QFETCH(double, expectedMedian);
QtConcurrent::Median m;
- foreach (double value, values)
+ for (double value : values)
m.addValue(value);
QCOMPARE(m.median(), expectedMedian);
}
diff --git a/tests/auto/concurrent/qtconcurrentrun/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentrun/CMakeLists.txt
index 07cb4d360f..a8b6792570 100644
--- a/tests/auto/concurrent/qtconcurrentrun/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrentrun/CMakeLists.txt
@@ -1,14 +1,22 @@
-# Generated from qtconcurrentrun.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrentrun Test:
#####################################################################
-qt_add_test(tst_qtconcurrentrun
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentrun LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentrun
SOURCES
tst_qtconcurrentrun.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
+ Qt::TestPrivate
)
## Scopes:
diff --git a/tests/auto/concurrent/qtconcurrentrun/qtconcurrentrun.pro b/tests/auto/concurrent/qtconcurrentrun/qtconcurrentrun.pro
deleted file mode 100644
index 44891b7ba5..0000000000
--- a/tests/auto/concurrent/qtconcurrentrun/qtconcurrentrun.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrentrun
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrentrun.cpp
-
-# Force C++17 if available
-contains(QT_CONFIG, c++1z): CONFIG += c++1z
diff --git a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
index e4b728f950..0bc2961903 100644
--- a/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
+++ b/tests/auto/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp
@@ -1,34 +1,16 @@
-/****************************************************************************
-**
-** 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 <qtconcurrentrun.h>
-#include <qfuture.h>
+#include <QFuture>
+#include <QMutex>
+#include <QMutexLocker>
#include <QString>
-#include <QtTest/QtTest>
+#include <QWaitCondition>
+#include <QTest>
+#include <QTimer>
+#include <QFutureSynchronizer>
+
+#include <QtTest/private/qemulationdetector_p.h>
using namespace QtConcurrent;
@@ -36,6 +18,7 @@ class tst_QtConcurrentRun: public QObject
{
Q_OBJECT
private slots:
+ void initTestCase();
void runLightFunction();
void runHeavyFunction();
void returnValue();
@@ -48,14 +31,20 @@ private slots:
void recursive();
#ifndef QT_NO_EXCEPTIONS
void exceptions();
+ void unhandledException();
#endif
void functor();
void lambda();
void callableObjectWithState();
void withPromise();
void withPromiseInThreadPool();
+ void withPromiseAndThen();
void moveOnlyType();
void crefFunction();
+ void customPromise();
+ void nonDefaultConstructibleValue();
+ void nullThreadPool();
+ void nullThreadPoolNoLeak();
};
void light()
@@ -97,6 +86,13 @@ void heavy()
qDebug("done function");
}
+void tst_QtConcurrentRun::initTestCase()
+{
+ // proxy check for QEMU; catches slightly more though
+ if (QTestPrivate::isRunningArmOnX86())
+ QSKIP("Runs into spurious crashes on QEMU -- QTBUG-106906");
+}
+
void tst_QtConcurrentRun::runLightFunction()
{
qDebug("starting function");
@@ -121,14 +117,14 @@ void tst_QtConcurrentRun::runLightFunction()
void (*f3)(QPromise<int> &) = lightOverloaded;
qDebug("starting function with promise");
- QFuture<void> future3 = runWithPromise(f3);
+ QFuture<int> future3 = run(f3);
qDebug("waiting");
future3.waitForFinished();
qDebug("done");
void (*f4)(QPromise<double> &, int v) = lightOverloaded;
qDebug("starting function with promise and with arg");
- QFuture<void> future4 = runWithPromise(f4, 2);
+ QFuture<double> future4 = run(f4, 2);
qDebug("waiting");
future4.waitForFinished();
qDebug("done");
@@ -428,141 +424,141 @@ void tst_QtConcurrentRun::reportValueWithPromise()
QThreadPool pool;
QFuture<int> f;
- f = runWithPromise(reportInt0);
+ f = run(reportInt0);
QCOMPARE(f.result(), 0);
- f = runWithPromise(&pool, reportInt0);
+ f = run(&pool, reportInt0);
QCOMPARE(f.result(), 0);
- f = runWithPromise(reportIntPlusOne, 5);
+ f = run(reportIntPlusOne, 5);
QCOMPARE(f.result(), 6);
- f = runWithPromise(&pool, reportIntPlusOne, 5);
+ f = run(&pool, reportIntPlusOne, 5);
QCOMPARE(f.result(), 6);
AWithPromise a;
- f = runWithPromise(&AWithPromise::member0, &a);
+ f = run(&AWithPromise::member0, &a);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &AWithPromise::member0, &a);
+ f = run(&pool, &AWithPromise::member0, &a);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&AWithPromise::member1, &a, 20);
+ f = run(&AWithPromise::member1, &a, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &AWithPromise::member1, &a, 20);
+ f = run(&pool, &AWithPromise::member1, &a, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&AWithPromise::member0, a);
+ f = run(&AWithPromise::member0, a);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &AWithPromise::member0, a);
+ f = run(&pool, &AWithPromise::member0, a);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&AWithPromise::member1, a, 20);
+ f = run(&AWithPromise::member1, a, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &AWithPromise::member1, a, 20);
+ f = run(&pool, &AWithPromise::member1, a, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(a);
+ f = run(a);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, a);
+ f = run(&pool, a);
QCOMPARE(f.result(), 10);
- f = runWithPromise(std::ref(a));
+ f = run(std::ref(a));
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, std::ref(a));
+ f = run(&pool, std::ref(a));
QCOMPARE(f.result(), 10);
const AConstWithPromise aConst = AConstWithPromise();
- f = runWithPromise(&AConstWithPromise::member0, &aConst);
+ f = run(&AConstWithPromise::member0, &aConst);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &AConstWithPromise::member0, &aConst);
+ f = run(&pool, &AConstWithPromise::member0, &aConst);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&AConstWithPromise::member1, &aConst, 20);
+ f = run(&AConstWithPromise::member1, &aConst, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &AConstWithPromise::member1, &aConst, 20);
+ f = run(&pool, &AConstWithPromise::member1, &aConst, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&AConstWithPromise::member0, aConst);
+ f = run(&AConstWithPromise::member0, aConst);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &AConstWithPromise::member0, aConst);
+ f = run(&pool, &AConstWithPromise::member0, aConst);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&AConstWithPromise::member1, aConst, 20);
+ f = run(&AConstWithPromise::member1, aConst, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &AConstWithPromise::member1, aConst, 20);
+ f = run(&pool, &AConstWithPromise::member1, aConst, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(aConst);
+ f = run(aConst);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, aConst);
+ f = run(&pool, aConst);
QCOMPARE(f.result(), 10);
- f = runWithPromise(std::ref(a));
+ f = run(std::ref(a));
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, std::ref(a));
+ f = run(&pool, std::ref(a));
QCOMPARE(f.result(), 10);
ANoExceptWithPromise aNoExcept;
- f = runWithPromise(&ANoExceptWithPromise::member0, &aNoExcept);
+ f = run(&ANoExceptWithPromise::member0, &aNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &ANoExceptWithPromise::member0, &aNoExcept);
+ f = run(&pool, &ANoExceptWithPromise::member0, &aNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&ANoExceptWithPromise::member1, &aNoExcept, 20);
+ f = run(&ANoExceptWithPromise::member1, &aNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20);
+ f = run(&pool, &ANoExceptWithPromise::member1, &aNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&ANoExceptWithPromise::member0, aNoExcept);
+ f = run(&ANoExceptWithPromise::member0, aNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &ANoExceptWithPromise::member0, aNoExcept);
+ f = run(&pool, &ANoExceptWithPromise::member0, aNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&ANoExceptWithPromise::member1, aNoExcept, 20);
+ f = run(&ANoExceptWithPromise::member1, aNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20);
+ f = run(&pool, &ANoExceptWithPromise::member1, aNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(aNoExcept);
+ f = run(aNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, aNoExcept);
+ f = run(&pool, aNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(std::ref(aNoExcept));
+ f = run(std::ref(aNoExcept));
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, std::ref(aNoExcept));
+ f = run(&pool, std::ref(aNoExcept));
QCOMPARE(f.result(), 10);
const AConstNoExceptWithPromise aConstNoExcept = AConstNoExceptWithPromise();
- f = runWithPromise(&AConstNoExceptWithPromise::member0, &aConstNoExcept);
+ f = run(&AConstNoExceptWithPromise::member0, &aConstNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept);
+ f = run(&pool, &AConstNoExceptWithPromise::member0, &aConstNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
+ f = run(&AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
+ f = run(&pool, &AConstNoExceptWithPromise::member1, &aConstNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&AConstNoExceptWithPromise::member0, aConstNoExcept);
+ f = run(&AConstNoExceptWithPromise::member0, aConstNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept);
+ f = run(&pool, &AConstNoExceptWithPromise::member0, aConstNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
+ f = run(&AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
+ f = run(&pool, &AConstNoExceptWithPromise::member1, aConstNoExcept, 20);
QCOMPARE(f.result(), 20);
- f = runWithPromise(aConstNoExcept);
+ f = run(aConstNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, aConstNoExcept);
+ f = run(&pool, aConstNoExcept);
QCOMPARE(f.result(), 10);
- f = runWithPromise(std::ref(aConstNoExcept));
+ f = run(std::ref(aConstNoExcept));
QCOMPARE(f.result(), 10);
- f = runWithPromise(&pool, std::ref(aConstNoExcept));
+ f = run(&pool, std::ref(aConstNoExcept));
QCOMPARE(f.result(), 10);
}
@@ -670,10 +666,10 @@ void tst_QtConcurrentRun::implicitConvertibleTypes()
{
QThreadPool pool;
- double d;
+ double d = 0.0;
run(doubleFunction, d).waitForFinished();
run(&pool, doubleFunction, d).waitForFinished();
- int i;
+ int i = 0;
run(doubleFunction, d).waitForFinished();
run(&pool, doubleFunction, d).waitForFinished();
run(doubleFunction, i).waitForFinished();
@@ -819,7 +815,7 @@ public:
void run() override {
int iter = 60;
while (--iter && !cancel.loadRelaxed())
- QThread::currentThread()->msleep(25);
+ QThread::currentThread()->sleep(std::chrono::milliseconds{25});
}
};
@@ -890,6 +886,25 @@ void tst_QtConcurrentRun::exceptions()
QVERIFY2(caught, "did not get exception");
}
+
+void tst_QtConcurrentRun::unhandledException()
+{
+ struct Exception {};
+ bool caught = false;
+ try {
+ auto f = QtConcurrent::run([] { throw Exception {}; });
+ f.waitForFinished();
+ } catch (const QUnhandledException &e) {
+ try {
+ if (e.exception())
+ std::rethrow_exception(e.exception());
+ } catch (const Exception &) {
+ caught = true;
+ }
+ }
+
+ QVERIFY(caught);
+}
#endif
// Compiler supports decltype
@@ -940,14 +955,14 @@ void tst_QtConcurrentRun::functor()
}
FunctorWithPromise fWithPromise;
{
- QtConcurrent::runWithPromise(fWithPromise, 1.5).waitForFinished();
+ QtConcurrent::run(fWithPromise, 1.5).waitForFinished();
}
OverloadedFunctorWithPromise ofWithPromise;
{
- QtConcurrent::runWithPromise<int>(ofWithPromise).waitForFinished();
- QtConcurrent::runWithPromise<double>(ofWithPromise).waitForFinished();
- QtConcurrent::runWithPromise<int>(ofWithPromise, 1).waitForFinished();
- QtConcurrent::runWithPromise<double>(ofWithPromise, 1).waitForFinished();
+ QtConcurrent::run<int>(ofWithPromise).waitForFinished();
+ QtConcurrent::run<double>(ofWithPromise).waitForFinished();
+ QtConcurrent::run<int>(ofWithPromise, 1).waitForFinished();
+ QtConcurrent::run<double>(ofWithPromise, 1).waitForFinished();
}
// and now with explicit pool:
QThreadPool pool;
@@ -975,13 +990,17 @@ void tst_QtConcurrentRun::functor()
// Compiler supports lambda
void tst_QtConcurrentRun::lambda()
{
- QCOMPARE(QtConcurrent::run([](){ return 45; }).result(), 45);
- QCOMPARE(QtConcurrent::run([](int a){ return a+15; }, 12).result(), 12+15);
- QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15));
- QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
+ QCOMPARE(QtConcurrent::run([]() { return 45; }).result(), 45);
+ QCOMPARE(QtConcurrent::run([](int a) { return a+15; }, 12).result(), 12+15);
+ QCOMPARE(QtConcurrent::run([](int a, double b) { return a + b; }, 12, 15).result(),
+ double(12+15));
+ QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b)
+ { return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
- QCOMPARE(QtConcurrent::runWithPromise([](QPromise<int> &promise){ promise.addResult(45); }).result(), 45);
- QCOMPARE(QtConcurrent::runWithPromise([](QPromise<int> &promise, double input){ promise.addResult(input / 2.0); }, 15.0).result(), 7);
+ QCOMPARE(QtConcurrent::run([](QPromise<int> &promise)
+ { promise.addResult(45); }).result(), 45);
+ QCOMPARE(QtConcurrent::run([](QPromise<int> &promise, double input)
+ { promise.addResult(input / 2.0); }, 15.0).result(), 7);
{
QString str { "Hello World Foo" };
@@ -992,10 +1011,12 @@ void tst_QtConcurrentRun::lambda()
// and now with explicit pool:
QThreadPool pool;
- QCOMPARE(QtConcurrent::run(&pool, [](){ return 45; }).result(), 45);
- QCOMPARE(QtConcurrent::run(&pool, [](int a){ return a+15; }, 12).result(), 12+15);
- QCOMPARE(QtConcurrent::run(&pool, [](int a, double b){ return a + b; }, 12, 15).result(), double(12+15));
- QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
+ QCOMPARE(QtConcurrent::run(&pool, []() { return 45; }).result(), 45);
+ QCOMPARE(QtConcurrent::run(&pool, [](int a) { return a + 15; }, 12).result(), 12 + 15);
+ QCOMPARE(QtConcurrent::run(&pool, [](int a, double b)
+ { return a + b; }, 12, 15).result(), double(12 + 15));
+ QCOMPARE(QtConcurrent::run(&pool, [](int a , int, int, int, int b)
+ { return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5);
{
QString str { "Hello World Foo" };
@@ -1045,19 +1066,20 @@ void tst_QtConcurrentRun::callableObjectWithState()
CallableWithStateWithPromise oWithPromise;
// Run method setNewState explicitly
- runWithPromise(&CallableWithStateWithPromise::setNewState, &oWithPromise, CallableWithStateWithPromise::defaultState() + 1).waitForFinished();
+ run(&CallableWithStateWithPromise::setNewState, &oWithPromise,
+ CallableWithStateWithPromise::defaultState() + 1).waitForFinished();
QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 1);
// Run operator()(int) explicitly
- runWithPromise(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished();
+ run(std::ref(oWithPromise), CallableWithStateWithPromise::defaultState() + 2).waitForFinished();
QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2);
// Run on a copy of object (original object remains unchanged)
- runWithPromise(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished();
+ run(oWithPromise, CallableWithStateWithPromise::defaultState() + 3).waitForFinished();
QCOMPARE(oWithPromise.state, CallableWithStateWithPromise::defaultState() + 2);
// Explicitly run on a temporary object
- QCOMPARE(runWithPromise(CallableWithStateWithPromise(), 15).result(), 15);
+ QCOMPARE(run(CallableWithStateWithPromise(), 15).result(), 15);
}
void report3(QPromise<int> &promise)
@@ -1067,12 +1089,25 @@ void report3(QPromise<int> &promise)
promise.addResult(1);
}
+static void staticReport3(QPromise<int> &promise)
+{
+ promise.addResult(0);
+ promise.addResult(2);
+ promise.addResult(1);
+}
+
void reportN(QPromise<double> &promise, int n)
{
for (int i = 0; i < n; ++i)
promise.addResult(0);
}
+static void staticReportN(QPromise<double> &promise, int n)
+{
+ for (int i = 0; i < n; ++i)
+ promise.addResult(0);
+}
+
void reportString1(QPromise<QString> &promise, const QString &s)
{
promise.addResult(s);
@@ -1141,40 +1176,50 @@ public:
void tst_QtConcurrentRun::withPromise()
{
// free function pointer
- QCOMPARE(runWithPromise(&report3).results(),
+ QCOMPARE(run(&report3).results(),
QList<int>({0, 2, 1}));
- QCOMPARE(runWithPromise(report3).results(),
+ QCOMPARE(run(report3).results(),
QList<int>({0, 2, 1}));
- QCOMPARE(runWithPromise(reportN, 4).results(),
- QList<double>({0, 0, 0, 0}));
- QCOMPARE(runWithPromise(reportN, 2).results(),
+ QCOMPARE(run(&staticReport3).results(),
+ QList<int>({0, 2, 1}));
+ QCOMPARE(run(staticReport3).results(),
+ QList<int>({0, 2, 1}));
+
+ QCOMPARE(run(&reportN, 2).results(),
+ QList<double>({0, 0}));
+ QCOMPARE(run(reportN, 2).results(),
+ QList<double>({0, 0}));
+
+ QCOMPARE(run(&staticReportN, 2).results(),
+ QList<double>({0, 0}));
+ QCOMPARE(run(staticReportN, 2).results(),
QList<double>({0, 0}));
QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string");
- QCOMPARE(runWithPromise(reportString1, s).results(),
+ QCOMPARE(run(reportString1, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(reportString1, crs).results(),
+ QCOMPARE(run(reportString1, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(reportString1, cs).results(),
+ QCOMPARE(run(reportString1, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(reportString1, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(reportString1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
- QCOMPARE(runWithPromise(reportString2, s).results(),
+ QCOMPARE(run(reportString2, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(reportString2, crs).results(),
+ QCOMPARE(run(reportString2, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(reportString2, cs).results(),
+ QCOMPARE(run(reportString2, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(reportString2, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(reportString2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda
- QCOMPARE(runWithPromise([](QPromise<double> &promise, int n) {
+ QCOMPARE(run([](QPromise<double> &promise, int n) {
for (int i = 0; i < n; ++i)
promise.addResult(0);
}, 3).results(),
@@ -1185,46 +1230,46 @@ void tst_QtConcurrentRun::withPromise()
for (int i = 0; i < n; ++i)
promise.addResult(0);
};
- QCOMPARE(runWithPromise(fun, 2).results(),
+ QCOMPARE(run(fun, 2).results(),
QList<double>({0, 0}));
// operator()
- QCOMPARE(runWithPromise(Callable(), 3).results(),
+ QCOMPARE(run(Callable(), 3).results(),
QList<double>({0, 0, 0}));
const Callable c{};
- QCOMPARE(runWithPromise(c, 2).results(),
+ QCOMPARE(run(c, 2).results(),
QList<double>({0, 0}));
// static member functions
- QCOMPARE(runWithPromise(&MyObject::staticMember0).results(),
+ QCOMPARE(run(&MyObject::staticMember0).results(),
QList<double>({0, 2, 1}));
- QCOMPARE(runWithPromise(&MyObject::staticMember1, 2).results(),
+ QCOMPARE(run(&MyObject::staticMember1, 2).results(),
QList<double>({0, 0}));
// member functions
const MyObject obj{};
- QCOMPARE(runWithPromise(&MyObject::member0, &obj).results(),
+ QCOMPARE(run(&MyObject::member0, &obj).results(),
QList<double>({0, 2, 1}));
- QCOMPARE(runWithPromise(&MyObject::member1, &obj, 4).results(),
+ QCOMPARE(run(&MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0}));
- QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, s).results(),
+ QCOMPARE(run(&MyObject::memberString1, &obj, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, crs).results(),
+ QCOMPARE(run(&MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, cs).results(),
+ QCOMPARE(run(&MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(&MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
- QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, s).results(),
+ QCOMPARE(run(&MyObject::memberString2, &obj, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, crs).results(),
+ QCOMPARE(run(&MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, cs).results(),
+ QCOMPARE(run(&MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(&MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
MyObject nonConstObj{};
- QCOMPARE(runWithPromise(&MyObject::nonConstMember, &nonConstObj).results(),
+ QCOMPARE(run(&MyObject::nonConstMember, &nonConstObj).results(),
QList<double>({0, 2, 1}));
}
@@ -1232,40 +1277,50 @@ void tst_QtConcurrentRun::withPromiseInThreadPool()
{
QScopedPointer<QThreadPool> pool(new QThreadPool);
// free function pointer
- QCOMPARE(runWithPromise(pool.data(), &report3).results(),
+ QCOMPARE(run(pool.data(), &report3).results(),
QList<int>({0, 2, 1}));
- QCOMPARE(runWithPromise(pool.data(), report3).results(),
+ QCOMPARE(run(pool.data(), report3).results(),
QList<int>({0, 2, 1}));
- QCOMPARE(runWithPromise(pool.data(), reportN, 4).results(),
- QList<double>({0, 0, 0, 0}));
- QCOMPARE(runWithPromise(pool.data(), reportN, 2).results(),
+ QCOMPARE(run(pool.data(), &staticReport3).results(),
+ QList<int>({0, 2, 1}));
+ QCOMPARE(run(pool.data(), staticReport3).results(),
+ QList<int>({0, 2, 1}));
+
+ QCOMPARE(run(pool.data(), &reportN, 2).results(),
+ QList<double>({0, 0}));
+ QCOMPARE(run(pool.data(), reportN, 2).results(),
+ QList<double>({0, 0}));
+
+ QCOMPARE(run(pool.data(), &staticReportN, 2).results(),
+ QList<double>({0, 0}));
+ QCOMPARE(run(pool.data(), staticReportN, 2).results(),
QList<double>({0, 0}));
QString s = QLatin1String("string");
const QString &crs = QLatin1String("cr string");
const QString cs = QLatin1String("c string");
- QCOMPARE(runWithPromise(pool.data(), reportString1, s).results(),
+ QCOMPARE(run(pool.data(), reportString1, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(pool.data(), reportString1, crs).results(),
+ QCOMPARE(run(pool.data(), reportString1, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(pool.data(), reportString1, cs).results(),
+ QCOMPARE(run(pool.data(), reportString1, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(pool.data(), reportString1, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
- QCOMPARE(runWithPromise(pool.data(), reportString2, s).results(),
+ QCOMPARE(run(pool.data(), reportString2, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(pool.data(), reportString2, crs).results(),
+ QCOMPARE(run(pool.data(), reportString2, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(pool.data(), reportString2, cs).results(),
+ QCOMPARE(run(pool.data(), reportString2, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(pool.data(), reportString2, QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
// lambda
- QCOMPARE(runWithPromise(pool.data(), [](QPromise<double> &promise, int n) {
+ QCOMPARE(run(pool.data(), [](QPromise<double> &promise, int n) {
for (int i = 0; i < n; ++i)
promise.addResult(0);
}, 3).results(),
@@ -1276,46 +1331,153 @@ void tst_QtConcurrentRun::withPromiseInThreadPool()
for (int i = 0; i < n; ++i)
promise.addResult(0);
};
- QCOMPARE(runWithPromise(pool.data(), fun, 2).results(),
+ QCOMPARE(run(pool.data(), fun, 2).results(),
QList<double>({0, 0}));
// operator()
- QCOMPARE(runWithPromise(pool.data(), Callable(), 3).results(),
+ QCOMPARE(run(pool.data(), Callable(), 3).results(),
QList<double>({0, 0, 0}));
const Callable c{};
- QCOMPARE(runWithPromise(pool.data(), c, 2).results(),
+ QCOMPARE(run(pool.data(), c, 2).results(),
QList<double>({0, 0}));
// static member functions
- QCOMPARE(runWithPromise(pool.data(), &MyObject::staticMember0).results(),
+ QCOMPARE(run(pool.data(), &MyObject::staticMember0).results(),
QList<double>({0, 2, 1}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::staticMember1, 2).results(),
+ QCOMPARE(run(pool.data(), &MyObject::staticMember1, 2).results(),
QList<double>({0, 0}));
// member functions
const MyObject obj{};
- QCOMPARE(runWithPromise(pool.data(), &MyObject::member0, &obj).results(),
+ QCOMPARE(run(pool.data(), &MyObject::member0, &obj).results(),
QList<double>({0, 2, 1}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::member1, &obj, 4).results(),
+ QCOMPARE(run(pool.data(), &MyObject::member1, &obj, 4).results(),
QList<double>({0, 0, 0, 0}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, s).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, crs).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, cs).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString1, &obj, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString1, &obj,
+ QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, s).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, s).results(),
QList<QString>({s}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, crs).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, crs).results(),
QList<QString>({crs}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, cs).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj, cs).results(),
QList<QString>({cs}));
- QCOMPARE(runWithPromise(pool.data(), &MyObject::memberString2, &obj, QString(QLatin1String("rvalue"))).results(),
+ QCOMPARE(run(pool.data(), &MyObject::memberString2, &obj,
+ QString(QLatin1String("rvalue"))).results(),
QList<QString>({QString(QLatin1String("rvalue"))}));
}
+void tst_QtConcurrentRun::withPromiseAndThen()
+{
+ bool runExecuted = false;
+ bool cancelReceivedBeforeSync = false;
+ bool cancelReceivedAfterSync = false;
+
+ bool syncBegin = false;
+ bool syncEnd = false;
+
+ QMutex mutex;
+ QWaitCondition condition;
+
+ auto reset = [&]() {
+ runExecuted = false;
+ cancelReceivedBeforeSync = false;
+ cancelReceivedAfterSync = false;
+ syncBegin = false;
+ syncEnd = false;
+ };
+
+ auto setFlag = [&mutex, &condition] (bool &flag) {
+ QMutexLocker locker(&mutex);
+ flag = true;
+ condition.wakeOne();
+ };
+
+ auto waitForFlag = [&mutex, &condition] (const bool &flag) {
+ QMutexLocker locker(&mutex);
+ while (!flag)
+ condition.wait(&mutex);
+ };
+
+ auto report1WithCancel = [&](QPromise<int> &promise) {
+ runExecuted = true;
+ cancelReceivedBeforeSync = promise.isCanceled();
+
+ setFlag(syncBegin);
+ waitForFlag(syncEnd);
+
+ cancelReceivedAfterSync = promise.isCanceled();
+ if (cancelReceivedAfterSync)
+ return;
+ promise.addResult(1);
+ };
+
+ {
+ auto future = run(report1WithCancel);
+
+ waitForFlag(syncBegin);
+ future.cancel();
+ setFlag(syncEnd);
+
+ future.waitForFinished();
+ QCOMPARE(future.results().size(), 0);
+ QVERIFY(runExecuted);
+ QVERIFY(!cancelReceivedBeforeSync);
+ QVERIFY(cancelReceivedAfterSync);
+ }
+
+ reset();
+
+ {
+ bool thenExecuted = false;
+ bool cancelExecuted = false;
+ auto future = run(report1WithCancel);
+ auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; })
+ .onCanceled([&]() { cancelExecuted = true; });
+
+ waitForFlag(syncBegin);
+ // no cancel this time
+ setFlag(syncEnd);
+
+ resultFuture.waitForFinished();
+ QCOMPARE(future.results().size(), 1);
+ QCOMPARE(future.result(), 1);
+ QVERIFY(runExecuted);
+ QVERIFY(thenExecuted);
+ QVERIFY(!cancelExecuted);
+ QVERIFY(!cancelReceivedBeforeSync);
+ QVERIFY(!cancelReceivedAfterSync);
+ }
+
+ reset();
+
+ {
+ bool thenExecuted = false;
+ bool cancelExecuted = false;
+ auto future = run(report1WithCancel);
+ auto resultFuture = future.then(QtFuture::Launch::Async, [&](int) { thenExecuted = true; })
+ .onCanceled([&]() { cancelExecuted = true; });
+
+ waitForFlag(syncBegin);
+ future.cancel();
+ setFlag(syncEnd);
+
+ resultFuture.waitForFinished();
+ QCOMPARE(future.results().size(), 0);
+ QVERIFY(runExecuted);
+ QVERIFY(!thenExecuted);
+ QVERIFY(cancelExecuted);
+ QVERIFY(!cancelReceivedBeforeSync);
+ QVERIFY(cancelReceivedAfterSync);
+ }
+}
+
class MoveOnlyType
{
public:
@@ -1337,43 +1499,135 @@ public:
void tst_QtConcurrentRun::moveOnlyType()
{
- QCOMPARE(runWithPromise(MoveOnlyCallable(), MoveOnlyType()).results(),
+ QCOMPARE(run(MoveOnlyCallable(), MoveOnlyType()).results(),
QList<int>({1}));
}
void tst_QtConcurrentRun::crefFunction()
{
- // free function pointer with promise
- auto fun = &report3;
- QCOMPARE(runWithPromise(std::cref(fun)).results(),
- QList<int>({0, 2, 1}));
+ {
+ // free function pointer with promise
+ auto fun = &returnInt0;
+ QCOMPARE(run(std::cref(fun)).result(), 10);
+
+ // lambda with promise
+ auto lambda = [](int n) {
+ return 2 * n;
+ };
+ QCOMPARE(run(std::cref(lambda), 3).result(), 6);
+
+ // std::function with promise
+ const std::function<int(int)> funObj = [](int n) {
+ return 2 * n;
+ };
+ QCOMPARE(run(std::cref(funObj), 2).result(), 4);
+
+ // callable with promise
+ const AConst c{};
+ QCOMPARE(run(std::cref(c), 2).result(), 2);
+
+ // member functions with promise
+ auto member = &AConst::member0;
+ const AConst obj{};
+ QCOMPARE(run(std::cref(member), &obj).result(), 10);
+ }
- // lambda with promise
- auto lambda = [](QPromise<double> &promise, int n) {
- for (int i = 0; i < n; ++i)
- promise.addResult(0);
- };
- QCOMPARE(runWithPromise(std::cref(lambda), 3).results(),
- QList<double>({0, 0, 0}));
+ {
+ // free function pointer with promise
+ auto fun = &report3;
+ QCOMPARE(run(std::cref(fun)).results(),
+ QList<int>({0, 2, 1}));
+
+ // lambda with promise
+ auto lambda = [](QPromise<double> &promise, int n) {
+ for (int i = 0; i < n; ++i)
+ promise.addResult(0);
+ };
+ QCOMPARE(run(std::cref(lambda), 3).results(),
+ QList<double>({0, 0, 0}));
+
+ // std::function with promise
+ const std::function<void(QPromise<double> &, int)> funObj =
+ [](QPromise<double> &promise, int n) {
+ for (int i = 0; i < n; ++i)
+ promise.addResult(0);
+ };
+ QCOMPARE(run(std::cref(funObj), 2).results(),
+ QList<double>({0, 0}));
+
+ // callable with promise
+ const Callable c{};
+ QCOMPARE(run(std::cref(c), 2).results(),
+ QList<double>({0, 0}));
+
+ // member functions with promise
+ auto member = &MyObject::member0;
+ const MyObject obj{};
+ QCOMPARE(run(std::cref(member), &obj).results(),
+ QList<double>({0, 2, 1}));
+ }
+}
- // std::function with promise
- const std::function<void(QPromise<double> &, int)> funObj = [](QPromise<double> &promise, int n) {
- for (int i = 0; i < n; ++i)
- promise.addResult(0);
+int explicitPromise(QPromise<int> &promise, int &i)
+{
+ promise.setProgressRange(-10, 10);
+ ++i;
+ return i * 2;
+}
+
+void tst_QtConcurrentRun::customPromise()
+{
+ QPromise<int> p;
+ int i = 4;
+ QCOMPARE(QtConcurrent::run(explicitPromise, std::ref(p), std::ref(i)).result(), 10);
+ QCOMPARE(i, 5);
+ QCOMPARE(p.future().progressMinimum(), -10);
+ QCOMPARE(p.future().progressMaximum(), 10);
+}
+
+void tst_QtConcurrentRun::nonDefaultConstructibleValue()
+{
+ struct NonDefaultConstructible
+ {
+ explicit NonDefaultConstructible(int v) : value(v) { }
+ int value = 0;
};
- QCOMPARE(runWithPromise(std::cref(funObj), 2).results(),
- QList<double>({0, 0}));
- // callable with promise
- const Callable c{};
- QCOMPARE(runWithPromise(std::cref(c), 2).results(),
- QList<double>({0, 0}));
+ auto future = QtConcurrent::run([] { return NonDefaultConstructible(42); });
+ QCOMPARE(future.result().value, 42);
+}
- // member functions with promise
- auto member = &MyObject::member0;
- const MyObject obj{};
- QCOMPARE(runWithPromise(std::cref(member), &obj).results(),
- QList<double>({0, 2, 1}));
+// QTBUG-98901
+void tst_QtConcurrentRun::nullThreadPool()
+{
+ QThreadPool *pool = nullptr;
+ std::atomic<bool> isInvoked = false;
+ auto future = run(pool, [&] { isInvoked = true; });
+ future.waitForFinished();
+ QVERIFY(future.isCanceled());
+ QVERIFY(!isInvoked);
+}
+
+struct LifetimeChecker
+{
+ LifetimeChecker() { ++count; }
+ LifetimeChecker(const LifetimeChecker &) { ++count; }
+ ~LifetimeChecker() { --count; }
+
+ void operator()() { }
+
+ static std::atomic<int> count;
+};
+std::atomic<int> LifetimeChecker::count = 0;
+
+void tst_QtConcurrentRun::nullThreadPoolNoLeak()
+{
+ {
+ QThreadPool *pool = nullptr;
+ auto future = run(pool, LifetimeChecker());
+ future.waitForFinished();
+ }
+ QCOMPARE(LifetimeChecker::count, 0);
}
QTEST_MAIN(tst_QtConcurrentRun)
diff --git a/tests/auto/concurrent/qtconcurrenttask/CMakeLists.txt b/tests/auto/concurrent/qtconcurrenttask/CMakeLists.txt
index 23a0d45e83..89226eaacc 100644
--- a/tests/auto/concurrent/qtconcurrenttask/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrenttask/CMakeLists.txt
@@ -1,12 +1,19 @@
-# Generated from qtconcurrenttask.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrenttask Test:
#####################################################################
-qt_add_test(tst_qtconcurrenttask
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrenttask LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrenttask
SOURCES
tst_qtconcurrenttask.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
)
diff --git a/tests/auto/concurrent/qtconcurrenttask/qtconcurrenttask.pro b/tests/auto/concurrent/qtconcurrenttask/qtconcurrenttask.pro
deleted file mode 100644
index 4404efa0b3..0000000000
--- a/tests/auto/concurrent/qtconcurrenttask/qtconcurrenttask.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrenttask
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrenttask.cpp
diff --git a/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp b/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp
index f4e6f99660..d570b0f974 100644
--- a/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp
+++ b/tests/auto/concurrent/qtconcurrenttask/tst_qtconcurrenttask.cpp
@@ -1,34 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtconcurrenttask.h>
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QSemaphore>
+
+#include <random>
class tst_QtConcurrentTask : public QObject
{
@@ -41,9 +19,11 @@ private Q_SLOTS:
void taskWithLambda();
void taskWithArguments();
void useCustomThreadPool();
+ void setPriority_data();
void setPriority();
void adjustAllSettings();
void ignoreFutureResult();
+ void withPromise();
};
using namespace QtConcurrent;
@@ -52,13 +32,14 @@ void tst_QtConcurrentTask::taskWithFreeFunction()
{
QVariant value(42);
- auto result = task(&qvariant_cast<int>)
+ auto result = task([](const QVariant &var){ return qvariant_cast<int>(var); })
.withArguments(value)
.spawn()
.result();
QCOMPARE(result, 42);
}
+
void tst_QtConcurrentTask::taskWithClassMethod()
{
QString result("foobar");
@@ -67,6 +48,7 @@ void tst_QtConcurrentTask::taskWithClassMethod()
QCOMPARE(result, "foo");
}
+
void tst_QtConcurrentTask::taskWithCallableObject()
{
QCOMPARE(task(std::plus<int>())
@@ -100,8 +82,18 @@ void tst_QtConcurrentTask::useCustomThreadPool()
QCOMPARE(result, 42);
}
+void tst_QtConcurrentTask::setPriority_data()
+{
+ QTest::addColumn<bool>("runWithPromise");
+
+ QTest::addRow("without promise") << false;
+ QTest::addRow("with promise") << true;
+}
+
void tst_QtConcurrentTask::setPriority()
{
+ QFETCH(bool, runWithPromise);
+
QThreadPool pool;
pool.setMaxThreadCount(1);
@@ -115,15 +107,25 @@ void tst_QtConcurrentTask::setPriority()
const int tasksCount = 10;
QList<int> priorities(tasksCount);
std::iota(priorities.begin(), priorities.end(), 1);
- auto seed = std::chrono::system_clock::now().time_since_epoch().count();
+ auto seed = std::random_device {}();
std::shuffle(priorities.begin(), priorities.end(), std::default_random_engine(seed));
+ qDebug() << "Generated priorities list" << priorities << "using seed" << seed;
+
QList<int> actual;
- for (int priority : priorities)
- futureResults << task([priority, &actual] { actual << priority; })
- .onThreadPool(pool)
- .withPriority(priority)
- .spawn();
+ for (int priority : priorities) {
+ if (runWithPromise) {
+ futureResults << task([priority, &actual] (QPromise<void> &) { actual << priority; })
+ .onThreadPool(pool)
+ .withPriority(priority)
+ .spawn();
+ } else {
+ futureResults << task([priority, &actual] { actual << priority; })
+ .onThreadPool(pool)
+ .withPriority(priority)
+ .spawn();
+ }
+ }
sem.release();
pool.waitForDone();
@@ -156,6 +158,7 @@ void tst_QtConcurrentTask::adjustAllSettings()
QCOMPARE(result, QList<int>({ 1, 2, 3 }));
}
+
void tst_QtConcurrentTask::ignoreFutureResult()
{
QThreadPool pool;
@@ -171,5 +174,23 @@ void tst_QtConcurrentTask::ignoreFutureResult()
QCOMPARE(value, 10);
}
+void incrementWithPromise(QPromise<int> &promise, int i)
+{
+ promise.addResult(i + 1);
+}
+
+void return0WithPromise(QPromise<int> &promise)
+{
+ promise.addResult(0);
+}
+
+void tst_QtConcurrentTask::withPromise()
+{
+ QCOMPARE(task(&return0WithPromise).spawn().result(), 0);
+ QCOMPARE(task(&return0WithPromise).withPriority(7).spawn().result(), 0);
+ QCOMPARE(task(&incrementWithPromise).withArguments(1).spawn().result(), 2);
+ QCOMPARE(task(&incrementWithPromise).withArguments(1).withPriority(7).spawn().result(), 2);
+}
+
QTEST_MAIN(tst_QtConcurrentTask)
#include "tst_qtconcurrenttask.moc"
diff --git a/tests/auto/concurrent/qtconcurrentthreadengine/CMakeLists.txt b/tests/auto/concurrent/qtconcurrentthreadengine/CMakeLists.txt
index 9c24dd1662..c3c8c9ea59 100644
--- a/tests/auto/concurrent/qtconcurrentthreadengine/CMakeLists.txt
+++ b/tests/auto/concurrent/qtconcurrentthreadengine/CMakeLists.txt
@@ -1,12 +1,19 @@
-# Generated from qtconcurrentthreadengine.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtconcurrentthreadengine Test:
#####################################################################
-qt_add_test(tst_qtconcurrentthreadengine
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtconcurrentthreadengine LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtconcurrentthreadengine
SOURCES
tst_qtconcurrentthreadengine.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Concurrent
)
diff --git a/tests/auto/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro b/tests/auto/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro
deleted file mode 100644
index b98b8f56e8..0000000000
--- a/tests/auto/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtconcurrentthreadengine
-QT = core testlib concurrent
-SOURCES = tst_qtconcurrentthreadengine.cpp
diff --git a/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp b/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp
index a39488fd62..0151b13693 100644
--- a/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp
+++ b/tests/auto/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp
@@ -1,35 +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
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include <qtconcurrentthreadengine.h>
#include <qexception.h>
#include <QThread>
#include <QElapsedTimer>
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QSet>
using namespace QtConcurrent;
@@ -66,16 +45,9 @@ public:
void tst_QtConcurrentThreadEngine::runDirectly()
{
- {
- PrintUser engine;
- engine.startSingleThreaded();
- engine.startBlocking();
- }
- {
- PrintUser *engine = new PrintUser();
- QFuture<void> f = engine->startAsynchronously();
- f.waitForFinished();
- }
+ PrintUser *engine = new PrintUser();
+ QFuture<void> f = engine->startAsynchronously();
+ f.waitForFinished();
}
class StringResultUser : public ThreadEngine<QString>
@@ -108,8 +80,10 @@ public:
void tst_QtConcurrentThreadEngine::result()
{
- StringResultUser engine;
- QCOMPARE(*engine.startBlocking(), QString("Foo"));
+ // ThreadEngine will delete 'engine' when it finishes
+ auto engine = new StringResultUser();
+ auto future = engine->startAsynchronously();
+ QCOMPARE(future.result(), QString("Foo"));
}
class VoidResultUser : public ThreadEngine<void>
@@ -137,17 +111,9 @@ public:
void tst_QtConcurrentThreadEngine::runThroughStarter()
{
- {
- ThreadEngineStarter<QString> starter = startThreadEngine(new StringResultUser());
- QFuture<QString> f = starter.startAsynchronously();
- QCOMPARE(f.result(), QString("Foo"));
- }
-
- {
- ThreadEngineStarter<QString> starter = startThreadEngine(new StringResultUser());
- QString str = starter.startBlocking();
- QCOMPARE(str, QString("Foo"));
- }
+ ThreadEngineStarter<QString> starter = startThreadEngine(new StringResultUser());
+ QFuture<QString> f = starter.startAsynchronously();
+ QCOMPARE(f.result(), QString("Foo"));
}
class CancelUser : public ThreadEngine<void>
@@ -233,12 +199,6 @@ void tst_QtConcurrentThreadEngine::throttle()
f.waitForFinished();
QCOMPARE(count.loadRelaxed(), 0);
}
-
- for (int i = 0; i < repeats; ++i) {
- ThrottleAlwaysUser t;
- t.startBlocking();
- QCOMPARE(count.loadRelaxed(), 0);
- }
}
QSet<QThread *> threads;
@@ -274,40 +234,21 @@ public:
void tst_QtConcurrentThreadEngine::threadCount()
{
- //QTBUG-23333: This test is unstable
-
const int repeats = 10;
for (int i = 0; i < repeats; ++i) {
- ThreadCountUser t;
- t.startBlocking();
- int count = threads.count();
- int count_expected = QThreadPool::globalInstance()->maxThreadCount() + 1; // +1 for the main thread.
- if (count != count_expected)
- QEXPECT_FAIL("", "QTBUG-23333", Abort);
- QCOMPARE(count, count_expected);
-
(new ThreadCountUser())->startAsynchronously().waitForFinished();
- count = threads.count();
- count_expected = QThreadPool::globalInstance()->maxThreadCount();
- if (count != count_expected)
- QEXPECT_FAIL("", "QTBUG-23333", Abort);
- QCOMPARE(count, count_expected);
+ const auto count = threads.size();
+ const auto maxThreadCount = QThreadPool::globalInstance()->maxThreadCount();
+ QVERIFY(count <= maxThreadCount);
+ QVERIFY(!threads.contains(QThread::currentThread()));
}
// Set the finish flag immediately, this should give us one thread only.
for (int i = 0; i < repeats; ++i) {
- ThreadCountUser t(true /*finishImmediately*/);
- t.startBlocking();
- int count = threads.count();
- if (count != 1)
- QEXPECT_FAIL("", "QTBUG-23333", Abort);
- QCOMPARE(count, 1);
-
(new ThreadCountUser(true /*finishImmediately*/))->startAsynchronously().waitForFinished();
- count = threads.count();
- if (count != 1)
- QEXPECT_FAIL("", "QTBUG-23333", Abort);
+ const auto count = threads.size();
QCOMPARE(count, 1);
+ QVERIFY(!threads.contains(QThread::currentThread()));
}
}
@@ -333,7 +274,7 @@ void tst_QtConcurrentThreadEngine::multipleResults()
{
MultipleResultsUser *engine = new MultipleResultsUser();
QFuture<int> f = engine->startAsynchronously();
- QCOMPARE(f.results().count() , 10);
+ QCOMPARE(f.results().size() , 10);
QCOMPARE(f.resultAt(0), 0);
QCOMPARE(f.resultAt(5), 5);
QCOMPARE(f.resultAt(9), 9);
@@ -415,13 +356,13 @@ void tst_QtConcurrentThreadEngine::cancelQueuedSlowUser()
class QtConcurrentExceptionThrower : public ThreadEngine<void>
{
public:
- QtConcurrentExceptionThrower(QThread *blockThread = 0)
+ QtConcurrentExceptionThrower(QThread *blockThread = nullptr)
: ThreadEngine(QThreadPool::globalInstance())
{
this->blockThread = blockThread;
}
- ThreadFunctionResult threadFunction()
+ ThreadFunctionResult threadFunction() override
{
QTest::qSleep(50);
throw QException();
@@ -430,16 +371,16 @@ public:
QThread *blockThread;
};
-class UnrelatedExceptionThrower : public ThreadEngine<void>
+class IntExceptionThrower : public ThreadEngine<void>
{
public:
- UnrelatedExceptionThrower(QThread *blockThread = 0)
+ IntExceptionThrower(QThread *blockThread = nullptr)
: ThreadEngine(QThreadPool::globalInstance())
{
this->blockThread = blockThread;
}
- ThreadFunctionResult threadFunction()
+ ThreadFunctionResult threadFunction() override
{
QTest::qSleep(50);
throw int();
@@ -450,7 +391,6 @@ public:
void tst_QtConcurrentThreadEngine::exceptions()
{
- // Asynchronous mode:
{
bool caught = false;
try {
@@ -463,65 +403,20 @@ void tst_QtConcurrentThreadEngine::exceptions()
QVERIFY2(caught, "did not get exception");
}
- // Blocking mode:
- // test throwing the exception from a worker thread.
- {
- bool caught = false;
- try {
- QtConcurrentExceptionThrower e(QThread::currentThread());
- e.startBlocking();
- } catch (const QException &) {
- caught = true;
- }
- QVERIFY2(caught, "did not get exception");
- }
-
- // test throwing the exception from the main thread (different code path)
{
bool caught = false;
try {
- QtConcurrentExceptionThrower e(0);
- e.startBlocking();
- } catch (const QException &) {
- caught = true;
- }
- QVERIFY2(caught, "did not get exception");
- }
-
- // Asynchronous mode:
- {
- bool caught = false;
- try {
- UnrelatedExceptionThrower *e = new UnrelatedExceptionThrower();
+ IntExceptionThrower *e = new IntExceptionThrower();
QFuture<void> f = e->startAsynchronously();
f.waitForFinished();
- } catch (const QUnhandledException &) {
- caught = true;
- }
- QVERIFY2(caught, "did not get exception");
- }
-
- // Blocking mode:
- // test throwing the exception from a worker thread.
- {
- bool caught = false;
- try {
- UnrelatedExceptionThrower e(QThread::currentThread());
- e.startBlocking();
- } catch (const QUnhandledException &) {
- caught = true;
- }
- QVERIFY2(caught, "did not get exception");
- }
-
- // test throwing the exception from the main thread (different code path)
- {
- bool caught = false;
- try {
- UnrelatedExceptionThrower e(0);
- e.startBlocking();
- } catch (const QUnhandledException &) {
- caught = true;
+ } catch (const QUnhandledException &ex) {
+ // Make sure the exception info is not lost
+ try {
+ if (ex.exception())
+ std::rethrow_exception(ex.exception());
+ } catch (int) {
+ caught = true;
+ }
}
QVERIFY2(caught, "did not get exception");
}
diff --git a/tests/auto/concurrent/testhelper_functions.h b/tests/auto/concurrent/testhelper_functions.h
new file mode 100644
index 0000000000..88c2e28910
--- /dev/null
+++ b/tests/auto/concurrent/testhelper_functions.h
@@ -0,0 +1,183 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#ifndef FUNCTIONS_H
+#define FUNCTIONS_H
+
+#include <QList>
+
+#include <vector>
+
+bool keepEvenIntegers(const int &x)
+{
+ return (x & 1) == 0;
+}
+
+class KeepEvenIntegers
+{
+public:
+ bool operator()(const int &x)
+ {
+ return (x & 1) == 0;
+ }
+};
+
+class KeepEvenIntegersMoveOnly
+{
+public:
+ KeepEvenIntegersMoveOnly() = default;
+ KeepEvenIntegersMoveOnly(KeepEvenIntegersMoveOnly &&) = default;
+ KeepEvenIntegersMoveOnly &operator=(KeepEvenIntegersMoveOnly &&other) = default;
+
+ KeepEvenIntegersMoveOnly(const KeepEvenIntegersMoveOnly &) = delete;
+ KeepEvenIntegersMoveOnly &operator=(const KeepEvenIntegersMoveOnly &) = delete;
+
+ bool operator()(int x) { return (x & 1) == 0; }
+};
+
+class Number
+{
+ int n;
+
+public:
+ Number()
+ : n(0)
+ { }
+
+ Number(int n)
+ : n(n)
+ { }
+
+ void multiplyBy2()
+ {
+ n *= 2;
+ }
+
+ Number multipliedBy2() const
+ {
+ return n * 2;
+ }
+
+ bool isEven() const
+ {
+ return (n & 1) == 0;
+ }
+
+ int toInt() const
+ {
+ return n;
+ }
+
+ QString toString() const
+ {
+ return QString::number(n);
+ }
+
+ Number squared() const
+ {
+ return Number(n * n);
+ }
+
+ bool operator==(const Number &other) const
+ {
+ return n == other.n;
+ }
+};
+
+bool keepEvenNumbers(const Number &x)
+{
+ return (x.toInt() & 1) == 0;
+}
+
+class KeepEvenNumbers
+{
+public:
+ bool operator()(const Number &x)
+ {
+ return (x.toInt() & 1) == 0;
+ }
+};
+
+void intSumReduce(int &sum, int x)
+{
+ sum += x;
+}
+
+class IntSumReduce
+{
+public:
+ void operator()(int &sum, int x)
+ {
+ sum += x;
+ }
+};
+
+class IntSumReduceMoveOnly
+{
+public:
+ IntSumReduceMoveOnly() = default;
+ IntSumReduceMoveOnly(IntSumReduceMoveOnly &&) = default;
+ IntSumReduceMoveOnly &operator=(IntSumReduceMoveOnly &&other) = default;
+
+ IntSumReduceMoveOnly(const IntSumReduceMoveOnly &) = delete;
+ IntSumReduceMoveOnly &operator=(const IntSumReduceMoveOnly &) = delete;
+
+ void operator()(int &sum, int x) { sum += x; }
+};
+
+void numberSumReduce(int &sum, const Number &x)
+{
+ sum += x.toInt();
+}
+
+class NumberSumReduce
+{
+public:
+ void operator()(int &sum, const Number &x)
+ {
+ sum += x.toInt();
+ }
+};
+
+template<typename T>
+class MoveOnlyVector
+{
+public:
+ using value_type = T;
+
+ // rule of six
+ MoveOnlyVector() = default;
+ ~MoveOnlyVector() = default;
+ MoveOnlyVector(MoveOnlyVector<T> &&other) = default;
+ MoveOnlyVector &operator=(MoveOnlyVector<T> &&other) = default;
+
+ MoveOnlyVector(const MoveOnlyVector<T> &) = delete;
+ MoveOnlyVector &operator=(const MoveOnlyVector<T> &) = delete;
+
+ // convenience for creation
+ explicit MoveOnlyVector(const std::vector<T> &v) : data(v) { }
+ void push_back(T &&el) { data.push_back(el); }
+ void push_back(const T &el) { data.push_back(el); }
+
+ // minimal interface to be usable as a Sequence in QtConcurrent
+ typedef typename std::vector<T>::const_iterator const_iterator;
+ typedef typename std::vector<T>::iterator iterator;
+ const_iterator cbegin() const { return data.cbegin(); }
+ const_iterator cend() const { return data.cend(); }
+ iterator begin() { return data.begin(); }
+ iterator end() { return data.end(); }
+ const_iterator begin() const { return data.cbegin(); }
+ const_iterator end() const { return data.cend(); }
+ bool operator==(const MoveOnlyVector<T> &other) const { return data == other.data; }
+
+private:
+ std::vector<T> data;
+};
+
+struct NonTemplateSequence : public QList<int>
+{
+ NonTemplateSequence() = default;
+
+ NonTemplateSequence(std::initializer_list<int> args) : QList(args) { }
+};
+
+#endif