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
|
void finish() override
|
||||||
{
|
{
|
||||||
reducer.finish(reduce, reducedResult);
|
reducer.finish(reduce, reducedResult);
|
||||||
sequence = reducedResult;
|
sequence = std::move(reducedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool shouldThrottleThread() override
|
inline bool shouldThrottleThread() override
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Generated from concurrent.pro.
|
# Generated from concurrent.pro.
|
||||||
|
|
||||||
add_subdirectory(qtconcurrentfilter)
|
add_subdirectory(qtconcurrentfilter)
|
||||||
|
add_subdirectory(qtconcurrentfiltermapgenerated)
|
||||||
add_subdirectory(qtconcurrentiteratekernel)
|
add_subdirectory(qtconcurrentiteratekernel)
|
||||||
add_subdirectory(qtconcurrentmap)
|
add_subdirectory(qtconcurrentmap)
|
||||||
add_subdirectory(qtconcurrentmedian)
|
add_subdirectory(qtconcurrentmedian)
|
||||||
|
@ -2,6 +2,7 @@ TEMPLATE=subdirs
|
|||||||
SUBDIRS=\
|
SUBDIRS=\
|
||||||
qtconcurrentfilter \
|
qtconcurrentfilter \
|
||||||
qtconcurrentiteratekernel \
|
qtconcurrentiteratekernel \
|
||||||
|
qtconcurrentfiltermapgenerated \
|
||||||
qtconcurrentmap \
|
qtconcurrentmap \
|
||||||
qtconcurrentmedian \
|
qtconcurrentmedian \
|
||||||
qtconcurrentrun \
|
qtconcurrentrun \
|
||||||
|
@ -265,13 +265,13 @@ void tst_QtConcurrentFilter::filtered()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only types sequences
|
// 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 }));
|
QCOMPARE(future.results(), QList<int>({ 2, 4 }));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// does not work yet
|
// does not work yet
|
||||||
auto result = QtConcurrent::blockingFiltered(
|
auto result = QtConcurrent::blockingFiltered(
|
||||||
MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers);
|
MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||||
QCOMPARE(result, std::vector<int>({ 2, 4 }));
|
QCOMPARE(result, std::vector<int>({ 2, 4 }));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -341,15 +341,15 @@ void tst_QtConcurrentFilter::filteredThreadPool()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move-only sequences
|
// move-only sequences
|
||||||
auto future = QtConcurrent::filtered(
|
auto future = QtConcurrent::filtered(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||||
&pool, MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers);
|
keepEvenIntegers);
|
||||||
QCOMPARE(future.results(), QList<int>({ 2, 4 }));
|
QCOMPARE(future.results(), QList<int>({ 2, 4 }));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// does not work yet
|
// does not work yet
|
||||||
auto result =
|
auto result =
|
||||||
QtConcurrent::blockingFiltered(
|
QtConcurrent::blockingFiltered(
|
||||||
&pool, MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers);
|
&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers);
|
||||||
QCOMPARE(result, std::vector<int>({ 2, 4 }));
|
QCOMPARE(result, std::vector<int>({ 2, 4 }));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -550,11 +550,11 @@ void tst_QtConcurrentFilter::filteredReduced()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// move only sequences
|
||||||
auto future = QtConcurrent::filteredReduced(MoveOnlyVector({ 1, 2, 3, 4 }),
|
auto future = QtConcurrent::filteredReduced(MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||||
keepEvenIntegers, intSumReduce);
|
keepEvenIntegers, intSumReduce);
|
||||||
QCOMPARE(future.result(), intSum);
|
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);
|
keepEvenIntegers, intSumReduce);
|
||||||
QCOMPARE(result, intSum);
|
QCOMPARE(result, intSum);
|
||||||
}
|
}
|
||||||
@ -649,12 +649,12 @@ void tst_QtConcurrentFilter::filteredReducedThreadPool()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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);
|
keepOddIntegers, intSumReduce);
|
||||||
QCOMPARE(future.result(), intSum);
|
QCOMPARE(future.result(), intSum);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingFilteredReduced(&pool, MoveOnlyVector({ 1, 2, 3, 4 }),
|
auto result = QtConcurrent::blockingFilteredReduced(
|
||||||
keepOddIntegers, intSumReduce);
|
&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepOddIntegers, intSumReduce);
|
||||||
QCOMPARE(result, intSum);
|
QCOMPARE(result, intSum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -923,12 +923,12 @@ void tst_QtConcurrentFilter::filteredReducedInitialValue()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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);
|
keepEvenIntegers, intSumReduce, intInitial);
|
||||||
QCOMPARE(future.result(), intSum);
|
QCOMPARE(future.result(), intSum);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingFilteredReduced(
|
auto result = QtConcurrent::blockingFilteredReduced(
|
||||||
MoveOnlyVector({ 1, 2, 3, 4 }), keepEvenIntegers, intSumReduce, intInitial);
|
MoveOnlyVector<int>({ 1, 2, 3, 4 }), keepEvenIntegers, intSumReduce, intInitial);
|
||||||
QCOMPARE(result, intSum);
|
QCOMPARE(result, intSum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1034,12 +1034,13 @@ void tst_QtConcurrentFilter::filteredReducedInitialValueThreadPool()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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);
|
keepOddIntegers, intSumReduce, intInitial);
|
||||||
QCOMPARE(future.result(), intSum);
|
QCOMPARE(future.result(), intSum);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingFilteredReduced(
|
auto result =
|
||||||
&pool, MoveOnlyVector({ 1, 2, 3, 4 }), keepOddIntegers, intSumReduce, intInitial);
|
QtConcurrent::blockingFilteredReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3, 4 }),
|
||||||
|
keepOddIntegers, intSumReduce, intInitial);
|
||||||
QCOMPARE(result, intSum);
|
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
|
// functors take arguments by reference, modifying the move-only sequence in place
|
||||||
{
|
{
|
||||||
MoveOnlyVector moveOnlyVector({ 1, 2, 3 });
|
MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 });
|
||||||
|
|
||||||
// functor
|
// functor
|
||||||
QtConcurrent::map(moveOnlyVector, MultiplyBy2InPlace()).waitForFinished();
|
QtConcurrent::map(moveOnlyVector, MultiplyBy2InPlace()).waitForFinished();
|
||||||
QCOMPARE(moveOnlyVector, MoveOnlyVector({ 2, 4, 6 }));
|
QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -291,14 +291,14 @@ void tst_QtConcurrentMap::blockingMap()
|
|||||||
|
|
||||||
// functors take arguments by reference, modifying the move-only sequence in place
|
// functors take arguments by reference, modifying the move-only sequence in place
|
||||||
{
|
{
|
||||||
MoveOnlyVector moveOnlyVector({ 1, 2, 3 });
|
MoveOnlyVector<int> moveOnlyVector({ 1, 2, 3 });
|
||||||
|
|
||||||
// functor
|
// functor
|
||||||
QtConcurrent::blockingMap(moveOnlyVector, MultiplyBy2InPlace());
|
QtConcurrent::blockingMap(moveOnlyVector, MultiplyBy2InPlace());
|
||||||
QCOMPARE(moveOnlyVector, MoveOnlyVector({ 2, 4, 6 }));
|
QCOMPARE(moveOnlyVector, MoveOnlyVector<int>({ 2, 4, 6 }));
|
||||||
QtConcurrent::blockingMap(moveOnlyVector.begin(), moveOnlyVector.end(),
|
QtConcurrent::blockingMap(moveOnlyVector.begin(), moveOnlyVector.end(),
|
||||||
MultiplyBy2InPlace());
|
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
|
// functors don't take arguments by reference, making these no-ops
|
||||||
@ -574,11 +574,11 @@ void tst_QtConcurrentMap::mapped()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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 }));
|
QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingMapped<std::vector<int>>(MoveOnlyVector({ 1, 2, 3 }),
|
auto result = QtConcurrent::blockingMapped<std::vector<int>>(
|
||||||
multiplyBy2);
|
MoveOnlyVector<int>({ 1, 2, 3 }), multiplyBy2);
|
||||||
QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
|
QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -677,11 +677,11 @@ void tst_QtConcurrentMap::mappedThreadPool()
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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 }));
|
QCOMPARE(future.results(), QList<int>({ 2, 4, 6 }));
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingMapped<std::vector<int>>(
|
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 }));
|
QCOMPARE(result, std::vector<int>({ 2, 4, 6 }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -870,11 +870,11 @@ void tst_QtConcurrentMap::mappedReduced()
|
|||||||
{
|
{
|
||||||
// move only sequences
|
// move only sequences
|
||||||
auto future =
|
auto future =
|
||||||
QtConcurrent::mappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare, intSumReduce);
|
QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare, intSumReduce);
|
||||||
QCOMPARE(future.result(), sumOfSquares);
|
QCOMPARE(future.result(), sumOfSquares);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare,
|
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||||
intSumReduce);
|
intSquare, intSumReduce);
|
||||||
QCOMPARE(result, sumOfSquares);
|
QCOMPARE(result, sumOfSquares);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -979,11 +979,11 @@ void tst_QtConcurrentMap::mappedReducedThreadPool()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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);
|
intSumReduce);
|
||||||
QCOMPARE(future.result(), sumOfCubes);
|
QCOMPARE(future.result(), sumOfCubes);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }),
|
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||||
intCube, intSumReduce);
|
intCube, intSumReduce);
|
||||||
QCOMPARE(result, sumOfCubes);
|
QCOMPARE(result, sumOfCubes);
|
||||||
}
|
}
|
||||||
@ -1216,12 +1216,12 @@ void tst_QtConcurrentMap::mappedReducedInitialValue()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// move only sequences
|
||||||
auto future = QtConcurrent::mappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare,
|
auto future = QtConcurrent::mappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }), intSquare,
|
||||||
intSumReduce, intInitial);
|
intSumReduce, intInitial);
|
||||||
QCOMPARE(future.result(), sumOfSquares);
|
QCOMPARE(future.result(), sumOfSquares);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector({ 1, 2, 3 }), intSquare,
|
auto result = QtConcurrent::blockingMappedReduced(MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||||
intSumReduce, intInitial);
|
intSquare, intSumReduce, intInitial);
|
||||||
QCOMPARE(result, sumOfSquares);
|
QCOMPARE(result, sumOfSquares);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1324,11 +1324,11 @@ void tst_QtConcurrentMap::mappedReducedInitialValueThreadPool()
|
|||||||
|
|
||||||
{
|
{
|
||||||
// move only sequences
|
// 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);
|
intSumReduce, intInitial);
|
||||||
QCOMPARE(future.result(), sumOfCubes);
|
QCOMPARE(future.result(), sumOfCubes);
|
||||||
|
|
||||||
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector({ 1, 2, 3 }),
|
auto result = QtConcurrent::blockingMappedReduced(&pool, MoveOnlyVector<int>({ 1, 2, 3 }),
|
||||||
intCube, intSumReduce, intInitial);
|
intCube, intSumReduce, intInitial);
|
||||||
QCOMPARE(result, sumOfCubes);
|
QCOMPARE(result, sumOfCubes);
|
||||||
}
|
}
|
||||||
|
@ -161,34 +161,39 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class MoveOnlyVector
|
class MoveOnlyVector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using value_type = int;
|
using value_type = T;
|
||||||
|
|
||||||
// rule of six
|
// rule of six
|
||||||
MoveOnlyVector() = default;
|
MoveOnlyVector() = default;
|
||||||
~MoveOnlyVector() = default;
|
~MoveOnlyVector() = default;
|
||||||
MoveOnlyVector(MoveOnlyVector &&other) = default;
|
MoveOnlyVector(MoveOnlyVector<T> &&other) = default;
|
||||||
MoveOnlyVector &operator=(MoveOnlyVector &&other) = default;
|
MoveOnlyVector &operator=(MoveOnlyVector<T> &&other) = default;
|
||||||
|
|
||||||
MoveOnlyVector(const MoveOnlyVector &) = delete;
|
MoveOnlyVector(const MoveOnlyVector<T> &) = delete;
|
||||||
MoveOnlyVector &operator=(const MoveOnlyVector &) = delete;
|
MoveOnlyVector &operator=(const MoveOnlyVector<T> &) = delete;
|
||||||
|
|
||||||
// convenience for creation
|
// 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
|
// minimal interface to be usable as a Sequence in QtConcurrent
|
||||||
typedef std::vector<int>::const_iterator const_iterator;
|
typedef typename std::vector<T>::const_iterator const_iterator;
|
||||||
typedef std::vector<int>::iterator iterator;
|
typedef typename std::vector<T>::iterator iterator;
|
||||||
const_iterator cbegin() const { return data.cbegin(); }
|
const_iterator cbegin() const { return data.cbegin(); }
|
||||||
const_iterator cend() const { return data.cend(); }
|
const_iterator cend() const { return data.cend(); }
|
||||||
iterator begin() { return data.begin(); }
|
iterator begin() { return data.begin(); }
|
||||||
iterator end() { return data.end(); }
|
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:
|
private:
|
||||||
std::vector<int> data;
|
std::vector<T> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user