Commit b81d7887 authored by Tobias Hunger's avatar Tobias Hunger

Utils: Support more containers with Utils::transform

Support std::vector and similar classes as input and output.

Change-Id: I1d202d54c18e868ce0e71e4c2b6288565710baa8
Reviewed-by: Eike Ziller's avatarEike Ziller <eike.ziller@qt.io>
parent b712b1bc
......@@ -275,88 +275,145 @@ inserter(QSet<X> &container)
// Result type of transform operation
template<template<typename> class Container, template<typename> class InputContainer, typename IT, typename Function>
template<template<typename, typename...> class Container, typename IT, typename Function>
using ResultContainer = Container<std::decay_t<std::result_of_t<Function(IT)>>>;
template<typename C, typename SC, typename F>
void transform_impl(const SC &container, C &result, F function)
{
result.reserve(container.size());
std::transform(std::begin(container), std::end(container), inserter(result), function);
}
} // anonymous
// --------------------------------------------------------------------
// Different containers for input and output:
// --------------------------------------------------------------------
// different container types for input and output, e.g. transforming a QList into a QSet
template<template<typename> class C, // result container type
template<typename> class SC, // input container type
// function:
template<template<typename, typename...> class C, // result container type
template<typename, typename...> class SC, // input container type
typename F, // function type
typename T, // input value type
typename F> // function type
typename... SCArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const SC<T> &container, F function)
decltype(auto) transform(const SC<T, SCArgs...> &container, F function)
{
ResultContainer<C, SC, T, F> result;
result.reserve(container.size());
std::transform(container.begin(), container.end(),
inserter(result),
function);
ResultContainer<C, T, F> result;
transform_impl(container, result, function);
return result;
}
// different container types for input and output, e.g. transforming a QList into a QSet
// for member function pointers
template<template<typename> class C, // result container type
template<typename> class SC, // input container type
// member function:
template<template<typename, typename...> class C, // result container type
template<typename, typename...> class SC, // input container type
typename T, // input value type
typename R,
typename S>
typename S,
typename... SCArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const SC<T> &container, R (S::*p)() const)
decltype(auto) transform(const SC<T, SCArgs...> &container, R (S::*p)() const)
{
return transform<C, SC, T>(container, std::mem_fn(p));
ResultContainer<C, T, decltype(std::mem_fn(p))> result;
transform_impl(container, result, std::mem_fn(p));
return result;
}
// same container type for input and output, e.g. transforming a QList<QString> into QList<int>
// or QStringList -> QList<>
template<template<typename> class C, // container
// members:
template<template<typename, typename...> class C, // result container
template<typename, typename...> class SC, // input container
typename T, // container value type
typename F>
typename R,
typename S,
typename... SCArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const C<T> &container, F function)
decltype(auto) transform(const SC<T, SCArgs...> &container, R S::*p)
{
return transform<C, C, T>(container, function);
ResultContainer<C, T, decltype(std::mem_fn(p))> result;
transform_impl(container, result, std::mem_fn(p));
return result;
}
// same container type for member function pointer
template<template<typename> class C, // container
typename T, // container value type
// different container types for input and output, e.g. transforming a QList into a QSet
// function:
template<template<typename, typename...> class C, // container type
typename F, // function type
typename T, // input value type
typename... CArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const C<T, CArgs...> &container, F function)
{
ResultContainer<C, T, F> result;
transform_impl(container, result, function);
return result;
}
// member function:
template<template<typename, typename...> class C, // container type
typename T, // input value type
typename R,
typename S>
typename S,
typename... CArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const C<T> &container, R (S::*p)() const)
decltype(auto) transform(const C<T, CArgs...> &container, R (S::*p)() const)
{
return transform<C, C, T>(container, std::mem_fn(p));
ResultContainer<C, T, decltype(std::mem_fn(p))> result;
transform_impl(container, result, std::mem_fn(p));
return result;
}
// same container type for members
template<template<typename> class C, // container
// members:
template<template<typename, typename...> class C, // container
typename T, // container value type
typename R,
typename S>
typename S,
typename... CArgs> // Arguments to SC
Q_REQUIRED_RESULT
decltype(auto) transform(const C<T> &container, R S::*member)
decltype(auto) transform(const C<T, CArgs...> &container, R S::*p)
{
return transform<C, C, T>(container, std::mem_fn(member));
ResultContainer<C, T, decltype(std::mem_fn(p))> result;
transform_impl(container, result, std::mem_fn(p));
return result;
}
// QStringList different containers
template<template<typename> class C, // result container type
typename F>
// Specialization for QStringList:
template<template<typename, typename...> class C = QList, // result container
typename F> // Arguments to C
Q_REQUIRED_RESULT
decltype(auto) transform(const QStringList &container, F function)
{
return transform<C, QList, QString>(container, function);
ResultContainer<C, QString, F> result;
transform_impl(static_cast<QList<QString>>(container), result, function);
return result;
}
// QStringList -> QList
template<typename F>
// member function:
template<template<typename, typename...> class C = QList, // result container type
typename R,
typename S>
Q_REQUIRED_RESULT
decltype(auto) transform(const QStringList &container, F function)
decltype(auto) transform(const QStringList &container, R (S::*p)() const)
{
return Utils::transform<QList, QList, QString>(container, function);
ResultContainer<C, QString, decltype(std::mem_fn(p))> result;
transform_impl(container, result, std::mem_fn(p));
return result;
}
// members:
template<template<typename, typename...> class C = QList, // result container
typename R,
typename S>
Q_REQUIRED_RESULT
decltype(auto) transform(const QStringList &container, R S::*p)
{
ResultContainer<C, QString, decltype(std::mem_fn(p))> result;
transform_impl(container, result, std::mem_fn(p));
return result;
}
//////////////////
......
......@@ -26,6 +26,7 @@
#include <QtTest>
#include <array>
#include <deque>
#include <memory>
#include <valarray>
......@@ -162,6 +163,78 @@ void tst_Algorithm::transform()
const QList<int> trans = Utils::transform(list, &Struct::member);
QCOMPARE(trans, QList<int>({4, 3, 2, 1, 2}));
}
{
// QList -> std::vector
const QList<int> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform<std::vector>(v, [](int i) { return i + 1; });
QCOMPARE(trans, std::vector<int>({2, 3, 4, 5}));
}
{
// QList -> std::vector
const QList<Struct> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform<std::vector>(v, &Struct::getMember);
QCOMPARE(trans, std::vector<int>({1, 2, 3, 4}));
}
{
// QList -> std::vector
const QList<Struct> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform<std::vector>(v, &Struct::member);
QCOMPARE(trans, std::vector<int>({1, 2, 3, 4}));
}
{
// std::vector -> QList
const std::vector<int> v({1, 2, 3, 4});
const QList<int> trans = Utils::transform<QList>(v, [](int i) { return i + 1; });
QCOMPARE(trans, QList<int>({2, 3, 4, 5}));
}
{
// std::vector -> QList
const std::vector<Struct> v({1, 2, 3, 4});
const QList<int> trans = Utils::transform<QList>(v, &Struct::getMember);
QCOMPARE(trans, QList<int>({1, 2, 3, 4}));
}
{
// std::vector -> QList
const std::vector<Struct> v({1, 2, 3, 4});
const QList<int> trans = Utils::transform<QList>(v, &Struct::member);
QCOMPARE(trans, QList<int>({1, 2, 3, 4}));
}
{
// std::deque -> std::vector
const std::deque<int> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform<std::vector>(v, [](int i) { return i + 1; });
QCOMPARE(trans, std::vector<int>({2, 3, 4, 5}));
}
{
// std::deque -> std::vector
const std::deque<Struct> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform<std::vector>(v, &Struct::getMember);
QCOMPARE(trans, std::vector<int>({1, 2, 3, 4}));
}
{
// std::deque -> std::vector
const std::deque<Struct> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform<std::vector>(v, &Struct::member);
QCOMPARE(trans, std::vector<int>({1, 2, 3, 4}));
}
{
// std::vector -> std::vector
const std::vector<int> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform(v, [](int i) { return i + 1; });
QCOMPARE(trans, std::vector<int>({2, 3, 4, 5}));
}
{
// std::vector -> std::vector
const std::vector<Struct> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform(v, &Struct::getMember);
QCOMPARE(trans, std::vector<int>({1, 2, 3, 4}));
}
{
// std::vector -> std::vector
const std::vector<Struct> v({1, 2, 3, 4});
const std::vector<int> trans = Utils::transform(v, &Struct::member);
QCOMPARE(trans, std::vector<int>({1, 2, 3, 4}));
}
}
void tst_Algorithm::sort()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment