summaryrefslogtreecommitdiffstats
path: root/tests/auto/concurrent/qtconcurrentfiltermapgenerated
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/concurrent/qtconcurrentfiltermapgenerated')
-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
14 files changed, 1697 insertions, 0 deletions
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)
+};