Automatically generate unit tests for QtConcurrent
There are many different ways to to call map and filter functions in QtConcurrent. This patch adds a python script to generate all possible combinations. Change-Id: I61ed1758601e219c5852e8cc939c5feebb23d2f6 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
parent
3553f8119b
commit
223e409efb
@ -133,7 +133,7 @@ public:
|
||||
void finish() override
|
||||
{
|
||||
reducer.finish(reduce, reducedResult);
|
||||
sequence = reducedResult;
|
||||
sequence = std::move(reducedResult);
|
||||
}
|
||||
|
||||
inline bool shouldThrottleThread() override
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Generated from concurrent.pro.
|
||||
|
||||
add_subdirectory(qtconcurrentfilter)
|
||||
add_subdirectory(qtconcurrentfiltermapgenerated)
|
||||
add_subdirectory(qtconcurrentiteratekernel)
|
||||
add_subdirectory(qtconcurrentmap)
|
||||
add_subdirectory(qtconcurrentmedian)
|
||||
|
@ -2,6 +2,7 @@ TEMPLATE=subdirs
|
||||
SUBDIRS=\
|
||||
qtconcurrentfilter \
|
||||
qtconcurrentiteratekernel \
|
||||
qtconcurrentfiltermapgenerated \
|
||||
qtconcurrentmap \
|
||||
qtconcurrentmedian \
|
||||
qtconcurrentrun \
|
||||
|
@ -265,13 +265,13 @@ void tst_QtConcurrentFilter::filtered()
|
||||
|
||||
{
|
||||
// move only types sequences
|
||||
auto future = QtConcurrent::filtered(MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||
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({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||
MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||
QCOMPARE(result, std::vector<int>({ 2, 4 }));
|
||||
#endif
|
||||
}
|
||||
@ -341,15 +341,15 @@ void tst_QtConcurrentFilter::filteredThreadPool()
|
||||
|
||||
{
|
||||
// move-only sequences
|
||||
auto future = QtConcurrent::filtered(
|
||||
&pool, MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||
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({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||
&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||
QCOMPARE(result, std::vector<int>({ 2, 4 }));
|
||||
#endif
|
||||
}
|
||||
@ -550,11 +550,11 @@ void tst_QtConcurrentFilter::filteredReduced()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::filteredReduced(MoveOnlyVector({ 1, 2, 3, 4 }),
|
||||
auto future = QtConcurrent::filteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||
keepEvenIntegers, intSumReduce);
|
||||
QCOMPARE(future.result(), intSum);
|
||||
|
||||
auto result = QtConcurrent::blockingFilteredReduced(MoveOnlyVector({ 1, 2, 3, 4 }),
|
||||
auto result = QtConcurrent::blockingFilteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||
keepEvenIntegers, intSumReduce);
|
||||
QCOMPARE(result, intSum);
|
||||
}
|
||||
@ -649,12 +649,12 @@ void tst_QtConcurrentFilter::filteredReducedThreadPool()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::filteredReduced(&pool, MoveOnlyVector({ 1, 2, 3, 4 }),
|
||||
auto future = QtConcurrent::filteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||
keepOddIntegers, intSumReduce);
|
||||
QCOMPARE(future.result(), intSum);
|
||||
|
||||
auto result = QtConcurrent::blockingFilteredReduced(&pool, MoveOnlyVector({ 1, 2, 3, 4 }),
|
||||
keepOddIntegers, intSumReduce);
|
||||
auto result = QtConcurrent::blockingFilteredReduced(
|
||||
&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepOddIntegers, intSumReduce);
|
||||
QCOMPARE(result, intSum);
|
||||
}
|
||||
}
|
||||
@ -923,12 +923,12 @@ void tst_QtConcurrentFilter::filteredReducedInitialValue()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::filteredReduced(MoveOnlyVector({ 1, 2, 3, 4 }),
|
||||
auto future = QtConcurrent::filteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||
keepEvenIntegers, intSumReduce, intInitial);
|
||||
QCOMPARE(future.result(), intSum);
|
||||
|
||||
auto result = QtConcurrent::blockingFilteredReduced(
|
||||
MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers, intSumReduce, intInitial);
|
||||
MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers, intSumReduce, intInitial);
|
||||
QCOMPARE(result, intSum);
|
||||
}
|
||||
}
|
||||
@ -1034,12 +1034,13 @@ void tst_QtConcurrentFilter::filteredReducedInitialValueThreadPool()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::filteredReduced(&pool, MoveOnlyVector({ 1, 2, 3, 4 }),
|
||||
auto future = QtConcurrent::filteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||
keepOddIntegers, intSumReduce, intInitial);
|
||||
QCOMPARE(future.result(), intSum);
|
||||
|
||||
auto result = QtConcurrent::blockingFilteredReduced(
|
||||
&pool, MoveOnlyVector({ 1, 2, 3, 4 }), keepOddIntegers, intSumReduce, intInitial);
|
||||
auto result =
|
||||
QtConcurrent::blockingFilteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||
keepOddIntegers, intSumReduce, intInitial);
|
||||
QCOMPARE(result, intSum);
|
||||
}
|
||||
}
|
||||
|
1
tests/auto/concurrent/qtconcurrentfiltermapgenerated/.gitignore
vendored
Normal file
1
tests/auto/concurrent/qtconcurrentfiltermapgenerated/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
tst_qtconcurrentfiltermapgenerated
|
@ -0,0 +1,12 @@
|
||||
#####################################################################
|
||||
## tst_qtconcurrentfiltermapgenerated Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qtconcurrentfiltermapgenerated
|
||||
SOURCES
|
||||
tst_qtconcurrentfiltermapgenerated.cpp
|
||||
tst_qtconcurrentfiltermapgenerated.h
|
||||
tst_qtconcurrent_selected_tests.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Concurrent
|
||||
)
|
@ -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.
|
@ -0,0 +1,293 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#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)
|
||||
{
|
||||
if (!movedFrom)
|
||||
return el.isOdd();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
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
|
@ -0,0 +1,163 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
|
||||
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)
|
||||
+ ";"
|
||||
)
|
@ -0,0 +1,71 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
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")
|
@ -0,0 +1,181 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
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_()
|
@ -0,0 +1,391 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
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)
|
@ -0,0 +1,58 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
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)
|
@ -0,0 +1,56 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
|
||||
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)
|
@ -0,0 +1,220 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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$
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
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
|
@ -0,0 +1,5 @@
|
||||
CONFIG += testcase
|
||||
TARGET = tst_qtconcurrentfiltermapgenerated
|
||||
QT = core testlib concurrent
|
||||
SOURCES = tst_qtconcurrentfiltermapgenerated.cpp tst_qtconcurrent_selected_tests.cpp
|
||||
HEADERS = tst_qtconcurrentfiltermapgenerated.h
|
@ -0,0 +1,296 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#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);*/
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include <qtconcurrentfilter.h>
|
||||
#include <qtconcurrentmap.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QList>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#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)
|
@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include <qtconcurrentfilter.h>
|
||||
#include <qtconcurrentmap.h>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#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();
|
||||
// START_GENERATED_SLOTS (see generate_tests.py)
|
||||
void test1();
|
||||
// END_GENERATED_SLOTS (see generate_tests.py)
|
||||
};
|
@ -194,11 +194,11 @@ void tst_QtConcurrentMap::map()
|
||||
|
||||
// functors take arguments by reference, modifying the move-only sequence in place
|
||||
{
|
||||
MoveOnlyVector moveOnlyVector({ 1, 2, 3 });
|
||||
MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 });
|
||||
|
||||
// functor
|
||||
QtConcurrent::map(moveOnlyVector, MultiplyBy2InPlace()).waitForFinished();
|
||||
QCOMPARE(moveOnlyVector, MoveOnlyVector({ 2, 4, 6 }));
|
||||
QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 }));
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -291,14 +291,14 @@ void tst_QtConcurrentMap::blockingMap()
|
||||
|
||||
// functors take arguments by reference, modifying the move-only sequence in place
|
||||
{
|
||||
MoveOnlyVector moveOnlyVector({ 1, 2, 3 });
|
||||
MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 });
|
||||
|
||||
// functor
|
||||
QtConcurrent::blockingMap(moveOnlyVector, MultiplyBy2InPlace());
|
||||
QCOMPARE(moveOnlyVector, MoveOnlyVector({ 2, 4, 6 }));
|
||||
QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 }));
|
||||
QtConcurrent::blockingMap(moveOnlyVector.begin(), moveOnlyVector.end(),
|
||||
MultiplyBy2InPlace());
|
||||
QCOMPARE(moveOnlyVector, MoveOnlyVector({ 4, 8, 12 }));
|
||||
QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 4, 8, 12 }));
|
||||
}
|
||||
|
||||
// functors don't take arguments by reference, making these no-ops
|
||||
@ -574,11 +574,11 @@ void tst_QtConcurrentMap::mapped()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::mapped(MoveOnlyVector({ 1, 2, 3 }), multiplyBy2);
|
||||
auto future = QtConcurrent::mapped(MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
|
||||
QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
|
||||
|
||||
auto result = QtConcurrent::blockingMapped<std::vector<int>>(MoveOnlyVector({ 1, 2, 3 }),
|
||||
multiplyBy2);
|
||||
auto result = QtConcurrent::blockingMapped<std::vector<int>>(
|
||||
MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
|
||||
QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
|
||||
}
|
||||
}
|
||||
@ -677,11 +677,11 @@ void tst_QtConcurrentMap::mappedThreadPool()
|
||||
}
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::mapped(&pool, MoveOnlyVector({ 1, 2, 3 }), multiplyBy2);
|
||||
auto future = QtConcurrent::mapped(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
|
||||
QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
|
||||
|
||||
auto result = QtConcurrent::blockingMapped<std::vector<int>>(
|
||||
&pool, MoveOnlyVector({ 1, 2, 3 }), multiplyBy2);
|
||||
&pool, MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
|
||||
QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
|
||||
}
|
||||
}
|
||||
@ -870,11 +870,11 @@ void tst_QtConcurrentMap::mappedReduced()
|
||||
{
|
||||
// move only sequences
|
||||
auto future =
|
||||
QtConcurrent::mappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare, intSumReduce);
|
||||
QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare, intSumReduce);
|
||||
QCOMPARE(future.result(), sumOfSquares);
|
||||
|
||||
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare,
|
||||
intSumReduce);
|
||||
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||
intSquare, intSumReduce);
|
||||
QCOMPARE(result, sumOfSquares);
|
||||
}
|
||||
}
|
||||
@ -979,11 +979,11 @@ void tst_QtConcurrentMap::mappedReducedThreadPool()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }), intCube,
|
||||
auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube,
|
||||
intSumReduce);
|
||||
QCOMPARE(future.result(), sumOfCubes);
|
||||
|
||||
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }),
|
||||
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||
intCube, intSumReduce);
|
||||
QCOMPARE(result, sumOfCubes);
|
||||
}
|
||||
@ -1216,12 +1216,12 @@ void tst_QtConcurrentMap::mappedReducedInitialValue()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::mappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare,
|
||||
auto future = QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare,
|
||||
intSumReduce, intInitial);
|
||||
QCOMPARE(future.result(), sumOfSquares);
|
||||
|
||||
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare,
|
||||
intSumReduce, intInitial);
|
||||
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||
intSquare, intSumReduce, intInitial);
|
||||
QCOMPARE(result, sumOfSquares);
|
||||
}
|
||||
}
|
||||
@ -1324,11 +1324,11 @@ void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool()
|
||||
|
||||
{
|
||||
// move only sequences
|
||||
auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }), intCube,
|
||||
auto future = QtConcurrent::mappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }), intCube,
|
||||
intSumReduce, intInitial);
|
||||
QCOMPARE(future.result(), sumOfCubes);
|
||||
|
||||
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }),
|
||||
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||
intCube, intSumReduce, intInitial);
|
||||
QCOMPARE(result, sumOfCubes);
|
||||
}
|
||||
|
@ -161,34 +161,39 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MoveOnlyVector
|
||||
{
|
||||
public:
|
||||
using value_type = int;
|
||||
using value_type = T;
|
||||
|
||||
// rule of six
|
||||
MoveOnlyVector() = default;
|
||||
~MoveOnlyVector() = default;
|
||||
MoveOnlyVector(MoveOnlyVector &&other) = default;
|
||||
MoveOnlyVector &operator=(MoveOnlyVector &&other) = default;
|
||||
MoveOnlyVector(MoveOnlyVector<T> &&other) = default;
|
||||
MoveOnlyVector &operator=(MoveOnlyVector<T> &&other) = default;
|
||||
|
||||
MoveOnlyVector(const MoveOnlyVector &) = delete;
|
||||
MoveOnlyVector &operator=(const MoveOnlyVector &) = delete;
|
||||
MoveOnlyVector(const MoveOnlyVector<T> &) = delete;
|
||||
MoveOnlyVector &operator=(const MoveOnlyVector<T> &) = delete;
|
||||
|
||||
// convenience for creation
|
||||
explicit MoveOnlyVector(const std::vector<int> &v) : data(v) { }
|
||||
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 std::vector<int>::const_iterator const_iterator;
|
||||
typedef std::vector<int>::iterator iterator;
|
||||
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(); }
|
||||
bool operator==(const MoveOnlyVector &other) const { return data == other.data; }
|
||||
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<int> data;
|
||||
std::vector<T> data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user