Non-associative containers: add range constructors
Something nice we'd like to detect for array-backed containers is if the iterator passed is a Contiguous one; if the type is also trivially copyable / Q_PRIMITIVE_TYPE, we could memcpy() the whole range. However, there's no trait in the Standard to detect contiguous iterators (the best approximation would be detecting if the iterator is actually a pointer). Also, it's probably not smart to do the work now for QVector since QVector needs refactoring anyhow, and this work will be lost. QString and QByteArray are left in another commit. [ChangeLog][QtCore][QVector] Added range constructor. [ChangeLog][QtCore][QVarLengthArray] Added range constructor. [ChangeLog][QtCore][QList] Added range constructor. [ChangeLog][QtCore][QStringList] Added range constructor. [ChangeLog][QtCore][QLinkedList] Added range constructor. [ChangeLog][QtCore][QSet] Added range constructor. Change-Id: I220edb796053c9c4d31a6dbdc7efc5fc0f6678f9 Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
This commit is contained in:
parent
f363540580
commit
2e1763d83a
93
src/corelib/tools/qcontainertools_impl.h
Normal file
93
src/corelib/tools/qcontainertools_impl.h
Normal file
@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
|
||||
** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#if 0
|
||||
#pragma qt_sync_skip_header_check
|
||||
#pragma qt_sync_stop_processing
|
||||
#endif
|
||||
|
||||
#ifndef QCONTAINERTOOLS_IMPL_H
|
||||
#define QCONTAINERTOOLS_IMPL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <iterator>
|
||||
|
||||
#ifndef Q_QDOC
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtPrivate
|
||||
{
|
||||
template <typename Iterator>
|
||||
using IfIsInputIterator = typename std::enable_if<
|
||||
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>::value,
|
||||
bool>::type;
|
||||
|
||||
template <typename Iterator>
|
||||
using IfIsForwardIterator = typename std::enable_if<
|
||||
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::forward_iterator_tag>::value,
|
||||
bool>::type;
|
||||
|
||||
template <typename Iterator>
|
||||
using IfIsNotForwardIterator = typename std::enable_if<
|
||||
!std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::forward_iterator_tag>::value,
|
||||
bool>::type;
|
||||
|
||||
template <typename Container,
|
||||
typename InputIterator,
|
||||
IfIsNotForwardIterator<InputIterator> = true>
|
||||
void reserveIfForwardIterator(Container *, InputIterator, InputIterator)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Container,
|
||||
typename ForwardIterator,
|
||||
IfIsForwardIterator<ForwardIterator> = true>
|
||||
void reserveIfForwardIterator(Container *c, ForwardIterator f, ForwardIterator l)
|
||||
{
|
||||
c->reserve(static_cast<typename Container::size_type>(std::distance(f, l)));
|
||||
}
|
||||
} // namespace QtPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // Q_QDOC
|
||||
|
||||
#endif // QCONTAINERTOOLS_IMPL_H
|
@ -153,6 +153,14 @@ const QLinkedListData QLinkedListData::shared_null = {
|
||||
initializer lists.
|
||||
*/
|
||||
|
||||
/*! \fn template <class T> template<typename InputIterator> QLinkedList<T>::QLinkedList(InputIterator first, InputIterator last)
|
||||
\since 5.14
|
||||
|
||||
Constructs a list with the contents in the iterator range [\a first, \a last).
|
||||
|
||||
The value type of \c InputIterator must be convertible to \c T.
|
||||
*/
|
||||
|
||||
/*! \fn template <class T> QLinkedList<T>::~QLinkedList()
|
||||
|
||||
Destroys the list. References to the values in the list, and all
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
#include <QtCore/qiterator.h>
|
||||
#include <QtCore/qrefcount.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
@ -84,11 +85,14 @@ public:
|
||||
inline QLinkedList(const QLinkedList<T> &l) : d(l.d) { d->ref.ref(); if (!d->sharable) detach(); }
|
||||
#if defined(Q_COMPILER_INITIALIZER_LISTS)
|
||||
inline QLinkedList(std::initializer_list<T> list)
|
||||
: d(const_cast<QLinkedListData *>(&QLinkedListData::shared_null))
|
||||
{
|
||||
std::copy(list.begin(), list.end(), std::back_inserter(*this));
|
||||
}
|
||||
: QLinkedList(list.begin(), list.end()) {}
|
||||
#endif
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
|
||||
inline QLinkedList(InputIterator first, InputIterator last)
|
||||
: QLinkedList()
|
||||
{
|
||||
std::copy(first, last, std::back_inserter(*this));
|
||||
}
|
||||
~QLinkedList();
|
||||
QLinkedList<T> &operator=(const QLinkedList<T> &);
|
||||
#ifdef Q_COMPILER_RVALUE_REFS
|
||||
|
@ -545,6 +545,14 @@ void **QListData::erase(void **xi)
|
||||
\since 5.2
|
||||
*/
|
||||
|
||||
/*! \fn template <class T> template<typename InputIterator> QList<T>::QList(InputIterator first, InputIterator last)
|
||||
\since 5.14
|
||||
|
||||
Constructs a QList with the contents in the iterator range [\a first, \a last).
|
||||
|
||||
The value type of \c InputIterator must be convertible to \c T.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <class T> QList<T> QList<T>::mid(int pos, int length) const
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <QtCore/qarraydata.h>
|
||||
#include <QtCore/qhashfunctions.h>
|
||||
#include <QtCore/qvector.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
@ -169,9 +170,11 @@ public:
|
||||
inline void swap(QList<T> &other) noexcept { qSwap(d, other.d); }
|
||||
#ifdef Q_COMPILER_INITIALIZER_LISTS
|
||||
inline QList(std::initializer_list<T> args)
|
||||
: d(const_cast<QListData::Data *>(&QListData::shared_null))
|
||||
{ reserve(int(args.size())); std::copy(args.begin(), args.end(), std::back_inserter(*this)); }
|
||||
: QList(args.begin(), args.end()) {}
|
||||
#endif
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
|
||||
QList(InputIterator first, InputIterator last);
|
||||
|
||||
bool operator==(const QList<T> &l) const;
|
||||
inline bool operator!=(const QList<T> &l) const { return !(*this == l); }
|
||||
|
||||
@ -842,6 +845,15 @@ Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
|
||||
dealloc(d);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator>>
|
||||
QList<T>::QList(InputIterator first, InputIterator last)
|
||||
: QList()
|
||||
{
|
||||
QtPrivate::reserveIfForwardIterator(this, first, last);
|
||||
std::copy(first, last, std::back_inserter(*this));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Q_OUTOFLINE_TEMPLATE bool QList<T>::operator==(const QList<T> &l) const
|
||||
{
|
||||
|
@ -41,6 +41,8 @@
|
||||
#define QSET_H
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
|
||||
#ifdef Q_COMPILER_INITIALIZER_LISTS
|
||||
#include <initializer_list>
|
||||
#endif
|
||||
@ -59,12 +61,16 @@ public:
|
||||
inline QSet() noexcept {}
|
||||
#ifdef Q_COMPILER_INITIALIZER_LISTS
|
||||
inline QSet(std::initializer_list<T> list)
|
||||
{
|
||||
reserve(int(list.size()));
|
||||
for (typename std::initializer_list<T>::const_iterator it = list.begin(); it != list.end(); ++it)
|
||||
insert(*it);
|
||||
}
|
||||
: QSet(list.begin(), list.end()) {}
|
||||
#endif
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
|
||||
inline QSet(InputIterator first, InputIterator last)
|
||||
{
|
||||
QtPrivate::reserveIfForwardIterator(this, first, last);
|
||||
for (; first != last; ++first)
|
||||
insert(*first);
|
||||
}
|
||||
|
||||
// compiler-generated copy/move ctor/assignment operators are fine!
|
||||
// compiler-generated destructor is fine!
|
||||
|
||||
|
@ -113,6 +113,17 @@
|
||||
compiled in C++11 mode.
|
||||
*/
|
||||
|
||||
/*! \fn template <class T> template<typename InputIterator> QSet<T>::QSet(InputIterator first, InputIterator last)
|
||||
\since 5.14
|
||||
|
||||
Constructs a set with the contents in the iterator range [\a first, \a last).
|
||||
|
||||
The value type of \c InputIterator must be convertible to \c T.
|
||||
|
||||
\note If the range [\a first, \a last) contains duplicate elements,
|
||||
the first one is retained.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <class T> void QSet<T>::swap(QSet<T> &other)
|
||||
|
||||
|
@ -847,5 +847,12 @@ int QtPrivate::QStringList_removeDuplicates(QStringList *that)
|
||||
lists.
|
||||
*/
|
||||
|
||||
/*! \fn template<typename InputIterator> QStringList::QStringList(InputIterator first, InputIterator last)
|
||||
\since 5.14
|
||||
|
||||
Constructs a QStringList with the contents in the iterator range [\a first, \a last).
|
||||
|
||||
The value type of \c InputIterator must be convertible to \c QString.
|
||||
*/
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -44,6 +44,7 @@
|
||||
#define QSTRINGLIST_H
|
||||
|
||||
#include <QtCore/qalgorithms.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
#include <QtCore/qregexp.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qstringmatcher.h>
|
||||
@ -109,6 +110,9 @@ public:
|
||||
#ifdef Q_COMPILER_INITIALIZER_LISTS
|
||||
inline QStringList(std::initializer_list<QString> args) : QList<QString>(args) { }
|
||||
#endif
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
|
||||
inline QStringList(InputIterator first, InputIterator last)
|
||||
: QList<QString>(first, last) { }
|
||||
|
||||
QStringList &operator=(const QList<QString> &other)
|
||||
{ QList<QString>::operator=(other); return *this; }
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <QtCore/qcontainerfwd.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qalgorithms.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
@ -71,13 +72,19 @@ public:
|
||||
|
||||
#ifdef Q_COMPILER_INITIALIZER_LISTS
|
||||
QVarLengthArray(std::initializer_list<T> args)
|
||||
: a(Prealloc), s(0), ptr(reinterpret_cast<T *>(array))
|
||||
: QVarLengthArray(args.begin(), args.end())
|
||||
{
|
||||
if (args.size())
|
||||
append(args.begin(), int(args.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
|
||||
inline QVarLengthArray(InputIterator first, InputIterator last)
|
||||
: QVarLengthArray()
|
||||
{
|
||||
QtPrivate::reserveIfForwardIterator(this, first, last);
|
||||
std::copy(first, last, std::back_inserter(*this));
|
||||
}
|
||||
|
||||
inline ~QVarLengthArray() {
|
||||
if (QTypeInfo<T>::isComplex) {
|
||||
T *i = ptr + s;
|
||||
|
@ -110,6 +110,14 @@
|
||||
lists.
|
||||
*/
|
||||
|
||||
/*! \fn template<class T, int Prealloc> template<typename InputIterator> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
|
||||
\since 5.14
|
||||
|
||||
Constructs an array with the contents in the iterator range [\a first, \a last).
|
||||
|
||||
The value type of \c InputIterator must be convertible to \c T.
|
||||
*/
|
||||
|
||||
|
||||
/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::~QVarLengthArray()
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <QtCore/qrefcount.h>
|
||||
#include <QtCore/qarraydata.h>
|
||||
#include <QtCore/qhashfunctions.h>
|
||||
#include <QtCore/qcontainertools_impl.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
@ -81,6 +82,9 @@ public:
|
||||
inline QVector(std::initializer_list<T> args);
|
||||
QVector<T> &operator=(std::initializer_list<T> args);
|
||||
#endif
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
|
||||
inline QVector(InputIterator first, InputIterator last);
|
||||
|
||||
bool operator==(const QVector<T> &v) const;
|
||||
inline bool operator!=(const QVector<T> &v) const { return !(*this == v); }
|
||||
|
||||
@ -557,6 +561,15 @@ QT_WARNING_POP
|
||||
# endif // Q_CC_MSVC
|
||||
#endif // Q_COMPILER_INITIALIZER_LISTS
|
||||
|
||||
template <typename T>
|
||||
template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator>>
|
||||
QVector<T>::QVector(InputIterator first, InputIterator last)
|
||||
: QVector()
|
||||
{
|
||||
QtPrivate::reserveIfForwardIterator(this, first, last);
|
||||
std::copy(first, last, std::back_inserter(*this));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void QVector<T>::freeData(Data *x)
|
||||
{
|
||||
|
@ -243,6 +243,13 @@
|
||||
lists.
|
||||
*/
|
||||
|
||||
/*! \fn template <typename T> template<typename InputIterator> QVector<T>::QVector(InputIterator first, InputIterator last)
|
||||
\since 5.14
|
||||
|
||||
Constructs a vector with the contents in the iterator range [\a first, \a last).
|
||||
|
||||
The value type of \c InputIterator must be convertible to \c T.
|
||||
*/
|
||||
|
||||
/*! \fn template <typename T> QVector<T>::~QVector()
|
||||
|
||||
|
@ -18,6 +18,7 @@ HEADERS += \
|
||||
tools/qcollator.h \
|
||||
tools/qcollator_p.h \
|
||||
tools/qcontainerfwd.h \
|
||||
tools/qcontainertools_impl.h \
|
||||
tools/qcryptographichash.h \
|
||||
tools/qdatetime.h \
|
||||
tools/qdatetime_p.h \
|
||||
|
@ -34,13 +34,375 @@
|
||||
#include "qstring.h"
|
||||
#include "qvarlengtharray.h"
|
||||
#include "qvector.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector> // for reference
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
// MSVC has these containers from the Standard Library, but it lacks
|
||||
// a __has_include mechanism (that we need to use for other stdlibs).
|
||||
// For the sake of increasing our test coverage, work around the issue.
|
||||
|
||||
#ifdef Q_CC_MSVC
|
||||
#define COMPILER_HAS_STDLIB_INCLUDE(x) 1
|
||||
#else
|
||||
#define COMPILER_HAS_STDLIB_INCLUDE(x) QT_HAS_INCLUDE(x)
|
||||
#endif
|
||||
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
|
||||
#include <forward_list>
|
||||
#endif
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
struct Movable
|
||||
{
|
||||
explicit Movable(int i = 0) Q_DECL_NOTHROW
|
||||
: i(i)
|
||||
{
|
||||
++instanceCount;
|
||||
}
|
||||
|
||||
Movable(const Movable &m)
|
||||
: i(m.i)
|
||||
{
|
||||
++instanceCount;
|
||||
}
|
||||
|
||||
~Movable()
|
||||
{
|
||||
--instanceCount;
|
||||
}
|
||||
|
||||
int i;
|
||||
static int instanceCount;
|
||||
};
|
||||
|
||||
int Movable::instanceCount = 0;
|
||||
bool operator==(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i == rhs.i; }
|
||||
bool operator!=(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i != rhs.i; }
|
||||
bool operator<(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i < rhs.i; }
|
||||
|
||||
uint qHash(Movable m, uint seed = 0) Q_DECL_NOTHROW { return qHash(m.i, seed); }
|
||||
QDebug &operator<<(QDebug &d, Movable m)
|
||||
{
|
||||
const QDebugStateSaver saver(d);
|
||||
return d.nospace() << "Movable(" << m.i << ")";
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
|
||||
QT_END_NAMESPACE
|
||||
|
||||
struct Complex
|
||||
{
|
||||
explicit Complex(int i = 0) Q_DECL_NOTHROW
|
||||
: i(i)
|
||||
{
|
||||
++instanceCount;
|
||||
}
|
||||
|
||||
Complex(const Complex &c)
|
||||
: i(c.i)
|
||||
{
|
||||
++instanceCount;
|
||||
}
|
||||
|
||||
~Complex()
|
||||
{
|
||||
--instanceCount;
|
||||
}
|
||||
|
||||
int i;
|
||||
static int instanceCount;
|
||||
};
|
||||
|
||||
int Complex::instanceCount = 0;
|
||||
bool operator==(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i == rhs.i; }
|
||||
bool operator!=(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i != rhs.i; }
|
||||
bool operator<(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i < rhs.i; }
|
||||
|
||||
uint qHash(Complex c, uint seed = 0) Q_DECL_NOTHROW { return qHash(c.i, seed); }
|
||||
QDebug &operator<<(QDebug &d, Complex c)
|
||||
{
|
||||
const QDebugStateSaver saver(d);
|
||||
return d.nospace() << "Complex(" << c.i << ")";
|
||||
}
|
||||
|
||||
|
||||
struct DuplicateStrategyTestType
|
||||
{
|
||||
explicit DuplicateStrategyTestType(int i = 0) Q_DECL_NOTHROW
|
||||
: i(i),
|
||||
j(++counter)
|
||||
{
|
||||
}
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
static int counter;
|
||||
};
|
||||
|
||||
int DuplicateStrategyTestType::counter = 0;
|
||||
|
||||
// only look at the i member, not j. j allows us to identify which instance
|
||||
// gets inserted in containers that don't allow for duplicates
|
||||
bool operator==(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.i == rhs.i;
|
||||
}
|
||||
|
||||
bool operator!=(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.i != rhs.i;
|
||||
}
|
||||
|
||||
bool operator<(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.i < rhs.i;
|
||||
}
|
||||
|
||||
uint qHash(DuplicateStrategyTestType c, uint seed = 0) Q_DECL_NOTHROW
|
||||
{
|
||||
return qHash(c.i, seed);
|
||||
}
|
||||
|
||||
bool reallyEqual(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.i == rhs.i && lhs.j == rhs.j;
|
||||
}
|
||||
|
||||
QDebug &operator<<(QDebug &d, DuplicateStrategyTestType c)
|
||||
{
|
||||
const QDebugStateSaver saver(d);
|
||||
return d.nospace() << "DuplicateStrategyTestType(" << c.i << "," << c.j << ")";
|
||||
}
|
||||
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<Movable>
|
||||
{
|
||||
std::size_t operator()(Movable m) const Q_DECL_NOTHROW
|
||||
{
|
||||
return hash<int>()(m.i);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<Complex>
|
||||
{
|
||||
std::size_t operator()(Complex m) const Q_DECL_NOTHROW
|
||||
{
|
||||
return hash<int>()(m.i);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<DuplicateStrategyTestType>
|
||||
{
|
||||
std::size_t operator()(DuplicateStrategyTestType m) const Q_DECL_NOTHROW
|
||||
{
|
||||
return hash<int>()(m.i);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// work around the fact that QVarLengthArray has a non-type
|
||||
// template parameter, and that breaks non_associative_container_duplicates_strategy
|
||||
template<typename T>
|
||||
class VarLengthArray : public QVarLengthArray<T>
|
||||
{
|
||||
public:
|
||||
#ifdef Q_COMPILER_INHERITING_CONSTRUCTORS
|
||||
using QVarLengthArray<T>::QVarLengthArray;
|
||||
#else
|
||||
template<typename InputIterator>
|
||||
VarLengthArray(InputIterator first, InputIterator last)
|
||||
: QVarLengthArray<T>(first, last)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef Q_COMPILER_INITIALIZER_LISTS
|
||||
VarLengthArray(std::initializer_list<T> args)
|
||||
: QVarLengthArray<T>(args)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
class tst_ContainerApiSymmetry : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
int m_movableInstanceCount;
|
||||
int m_complexInstanceCount;
|
||||
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
template <typename Container>
|
||||
void ranged_ctor_non_associative_impl() const;
|
||||
|
||||
template<template<typename ... T> class Container>
|
||||
void non_associative_container_duplicates_strategy() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
// non associative
|
||||
void ranged_ctor_std_vector_int() { ranged_ctor_non_associative_impl<std::vector<int>>(); }
|
||||
void ranged_ctor_std_vector_char() { ranged_ctor_non_associative_impl<std::vector<char>>(); }
|
||||
void ranged_ctor_std_vector_QChar() { ranged_ctor_non_associative_impl<std::vector<QChar>>(); }
|
||||
void ranged_ctor_std_vector_Movable() { ranged_ctor_non_associative_impl<std::vector<Movable>>(); }
|
||||
void ranged_ctor_std_vector_Complex() { ranged_ctor_non_associative_impl<std::vector<Complex>>(); }
|
||||
void ranged_ctor_std_vector_duplicates_strategy() { non_associative_container_duplicates_strategy<std::vector>(); }
|
||||
|
||||
void ranged_ctor_QVector_int() { ranged_ctor_non_associative_impl<QVector<int>>(); }
|
||||
void ranged_ctor_QVector_char() { ranged_ctor_non_associative_impl<QVector<char>>(); }
|
||||
void ranged_ctor_QVector_QChar() { ranged_ctor_non_associative_impl<QVector<QChar>>(); }
|
||||
void ranged_ctor_QVector_Movable() { ranged_ctor_non_associative_impl<QVector<Movable>>(); }
|
||||
void ranged_ctor_QVector_Complex() { ranged_ctor_non_associative_impl<QVector<Complex>>(); }
|
||||
void ranged_ctor_QVector_duplicates_strategy() { non_associative_container_duplicates_strategy<QVector>(); }
|
||||
|
||||
void ranged_ctor_QVarLengthArray_int() { ranged_ctor_non_associative_impl<QVarLengthArray<int>>(); }
|
||||
void ranged_ctor_QVarLengthArray_Movable() { ranged_ctor_non_associative_impl<QVarLengthArray<Movable>>(); }
|
||||
void ranged_ctor_QVarLengthArray_Complex() { ranged_ctor_non_associative_impl<QVarLengthArray<Complex>>(); }
|
||||
void ranged_ctor_QVarLengthArray_duplicates_strategy() { non_associative_container_duplicates_strategy<VarLengthArray>(); } // note the VarLengthArray passed
|
||||
|
||||
void ranged_ctor_QList_int() { ranged_ctor_non_associative_impl<QList<int>>(); }
|
||||
void ranged_ctor_QList_Movable() { ranged_ctor_non_associative_impl<QList<Movable>>(); }
|
||||
void ranged_ctor_QList_Complex() { ranged_ctor_non_associative_impl<QList<Complex>>(); }
|
||||
void ranged_ctor_QList_duplicates_strategy() { non_associative_container_duplicates_strategy<QList>(); }
|
||||
|
||||
void ranged_ctor_std_list_int() { ranged_ctor_non_associative_impl<std::list<int>>(); }
|
||||
void ranged_ctor_std_list_Movable() { ranged_ctor_non_associative_impl<std::list<Movable>>(); }
|
||||
void ranged_ctor_std_list_Complex() { ranged_ctor_non_associative_impl<std::list<Complex>>(); }
|
||||
void ranged_ctor_std_list_duplicates_strategy() { non_associative_container_duplicates_strategy<std::list>(); }
|
||||
|
||||
void ranged_ctor_std_forward_list_int() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
|
||||
ranged_ctor_non_associative_impl<std::forward_list<int>>();
|
||||
#else
|
||||
QSKIP("<forward_list> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_forward_list_Movable() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
|
||||
ranged_ctor_non_associative_impl<std::forward_list<Movable>>();
|
||||
#else
|
||||
QSKIP("<forward_list> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_forward_list_Complex() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
|
||||
ranged_ctor_non_associative_impl<std::forward_list<Complex>>();
|
||||
#else
|
||||
QSKIP("<forward_list> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_forward_list_duplicates_strategy() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
|
||||
non_associative_container_duplicates_strategy<std::forward_list>();
|
||||
#else
|
||||
QSKIP("<forward_list> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_QLinkedList_int() { ranged_ctor_non_associative_impl<QLinkedList<int>>(); }
|
||||
void ranged_ctor_QLinkedList_Movable() { ranged_ctor_non_associative_impl<QLinkedList<Movable>>(); }
|
||||
void ranged_ctor_QLinkedList_Complex() { ranged_ctor_non_associative_impl<QLinkedList<Complex>>(); }
|
||||
void ranged_ctor_QLinkedList_duplicates_strategy() { non_associative_container_duplicates_strategy<QLinkedList>(); }
|
||||
|
||||
void ranged_ctor_std_set_int() { ranged_ctor_non_associative_impl<std::set<int>>(); }
|
||||
void ranged_ctor_std_set_Movable() { ranged_ctor_non_associative_impl<std::set<Movable>>(); }
|
||||
void ranged_ctor_std_set_Complex() { ranged_ctor_non_associative_impl<std::set<Complex>>(); }
|
||||
void ranged_ctor_std_set_duplicates_strategy() { non_associative_container_duplicates_strategy<std::set>(); }
|
||||
|
||||
void ranged_ctor_std_multiset_int() { ranged_ctor_non_associative_impl<std::multiset<int>>(); }
|
||||
void ranged_ctor_std_multiset_Movable() { ranged_ctor_non_associative_impl<std::multiset<Movable>>(); }
|
||||
void ranged_ctor_std_multiset_Complex() { ranged_ctor_non_associative_impl<std::multiset<Complex>>(); }
|
||||
void ranged_ctor_std_multiset_duplicates_strategy() { non_associative_container_duplicates_strategy<std::multiset>(); }
|
||||
|
||||
void ranged_ctor_std_unordered_set_int() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
ranged_ctor_non_associative_impl<std::unordered_set<int>>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_unordered_set_Movable() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
ranged_ctor_non_associative_impl<std::unordered_set<Movable>>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_unordered_set_Complex() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
ranged_ctor_non_associative_impl<std::unordered_set<Complex>>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_unordered_set_duplicates_strategy() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
non_associative_container_duplicates_strategy<std::unordered_set>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ranged_ctor_std_unordered_multiset_int() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
ranged_ctor_non_associative_impl<std::unordered_multiset<int>>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_unordered_multiset_Movable() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
ranged_ctor_non_associative_impl<std::unordered_multiset<Movable>>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_unordered_multiset_Complex() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
ranged_ctor_non_associative_impl<std::unordered_multiset<Complex>>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_std_unordered_multiset_duplicates_strategy() {
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
non_associative_container_duplicates_strategy<std::unordered_multiset>();
|
||||
#else
|
||||
QSKIP("<unordered_set> is needed for this test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ranged_ctor_QSet_int() { ranged_ctor_non_associative_impl<QSet<int>>(); }
|
||||
void ranged_ctor_QSet_Movable() { ranged_ctor_non_associative_impl<QSet<Movable>>(); }
|
||||
void ranged_ctor_QSet_Complex() { ranged_ctor_non_associative_impl<QSet<Complex>>(); }
|
||||
void ranged_ctor_QSet_duplicates_strategy() { non_associative_container_duplicates_strategy<QSet>(); }
|
||||
|
||||
private:
|
||||
template <typename Container>
|
||||
void front_back_impl() const;
|
||||
@ -58,6 +420,237 @@ private Q_SLOTS:
|
||||
void front_back_QByteArray() { front_back_impl<QByteArray>(); }
|
||||
};
|
||||
|
||||
void tst_ContainerApiSymmetry::init()
|
||||
{
|
||||
m_movableInstanceCount = Movable::instanceCount;
|
||||
m_complexInstanceCount = Complex::instanceCount;
|
||||
}
|
||||
|
||||
void tst_ContainerApiSymmetry::cleanup()
|
||||
{
|
||||
// very simple leak check
|
||||
QCOMPARE(Movable::instanceCount, m_movableInstanceCount);
|
||||
QCOMPARE(Complex::instanceCount, m_complexInstanceCount);
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
Container createContainerReference()
|
||||
{
|
||||
using V = typename Container::value_type;
|
||||
|
||||
return {V(0), V(1), V(2), V(0)};
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void tst_ContainerApiSymmetry::ranged_ctor_non_associative_impl() const
|
||||
{
|
||||
using V = typename Container::value_type;
|
||||
|
||||
// the double V(0) is deliberate
|
||||
const auto reference = createContainerReference<Container>();
|
||||
|
||||
// plain array
|
||||
const V values1[] = { V(0), V(1), V(2), V(0) };
|
||||
|
||||
const Container c1(values1, values1 + sizeof(values1)/sizeof(values1[0]));
|
||||
|
||||
// from QList
|
||||
QList<V> l2;
|
||||
l2 << V(0) << V(1) << V(2) << V(0);
|
||||
|
||||
const Container c2a(l2.begin(), l2.end());
|
||||
const Container c2b(l2.cbegin(), l2.cend());
|
||||
|
||||
// from std::list
|
||||
std::list<V> l3;
|
||||
l3.push_back(V(0));
|
||||
l3.push_back(V(1));
|
||||
l3.push_back(V(2));
|
||||
l3.push_back(V(0));
|
||||
const Container c3a(l3.begin(), l3.end());
|
||||
|
||||
// from const std::list
|
||||
const std::list<V> l3c = l3;
|
||||
const Container c3b(l3c.begin(), l3c.end());
|
||||
|
||||
// from itself
|
||||
const Container c4(reference.begin(), reference.end());
|
||||
|
||||
QCOMPARE(c1, reference);
|
||||
QCOMPARE(c2a, reference);
|
||||
QCOMPARE(c2b, reference);
|
||||
QCOMPARE(c3a, reference);
|
||||
QCOMPARE(c3b, reference);
|
||||
QCOMPARE(c4, reference);
|
||||
}
|
||||
|
||||
|
||||
// type traits for detecting whether a non-associative container
|
||||
// accepts duplicated values, and if it doesn't, whether construction/insertion
|
||||
// prefer the new values (overwriting) or the old values (rejecting)
|
||||
|
||||
struct ContainerAcceptsDuplicateValues {};
|
||||
struct ContainerOverwritesDuplicateValues {};
|
||||
struct ContainerRejectsDuplicateValues {};
|
||||
|
||||
template<typename Container>
|
||||
struct ContainerDuplicatedValuesStrategy {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::vector<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<QVector<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<QVarLengthArray<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<VarLengthArray<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<QList<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::list<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::forward_list<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
#endif
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<QLinkedList<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
// assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::set<T...>> : ContainerRejectsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::multiset<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
|
||||
#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
|
||||
// assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::unordered_set<T...>> : ContainerRejectsDuplicateValues {};
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<std::unordered_multiset<T...>> : ContainerAcceptsDuplicateValues {};
|
||||
#endif
|
||||
|
||||
template<typename ... T>
|
||||
struct ContainerDuplicatedValuesStrategy<QSet<T...>> : ContainerRejectsDuplicateValues {};
|
||||
|
||||
#if defined(Q_COMPILER_INITIALIZER_LISTS)
|
||||
template<typename Container>
|
||||
void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerAcceptsDuplicateValues)
|
||||
{
|
||||
// do a deep check for equality, not ordering
|
||||
QVERIFY(std::distance(reference.begin(), reference.end()) == std::distance(c.begin(), c.end()));
|
||||
QVERIFY(std::is_permutation(reference.begin(), reference.end(), c.begin(), &reallyEqual));
|
||||
}
|
||||
|
||||
enum class IterationOnReference
|
||||
{
|
||||
ForwardIteration,
|
||||
ReverseIteration
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
void non_associative_container_check_duplicates_impl_no_duplicates(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, IterationOnReference ior)
|
||||
{
|
||||
std::vector<DuplicateStrategyTestType> valuesAlreadySeen;
|
||||
|
||||
// iterate on reference forward or backwards, depending on ior. this will give
|
||||
// us the expected semantics when checking for duplicated values into c
|
||||
auto it = [&reference, ior]() {
|
||||
switch (ior) {
|
||||
case IterationOnReference::ForwardIteration: return reference.begin();
|
||||
case IterationOnReference::ReverseIteration: return reference.end() - 1;
|
||||
};
|
||||
return std::initializer_list<DuplicateStrategyTestType>::const_iterator();
|
||||
}();
|
||||
|
||||
const auto &end = [&reference, ior]() {
|
||||
switch (ior) {
|
||||
case IterationOnReference::ForwardIteration: return reference.end();
|
||||
case IterationOnReference::ReverseIteration: return reference.begin() - 1;
|
||||
};
|
||||
return std::initializer_list<DuplicateStrategyTestType>::const_iterator();
|
||||
}();
|
||||
|
||||
while (it != end) {
|
||||
const auto &value = *it;
|
||||
|
||||
// check that there is indeed the same value in the container (using operator==)
|
||||
const auto &valueInContainerIterator = std::find(c.begin(), c.end(), value);
|
||||
QVERIFY(valueInContainerIterator != c.end());
|
||||
QVERIFY(value == *valueInContainerIterator);
|
||||
|
||||
// if the value is a duplicate, we don't expect to find it in the container
|
||||
// (when doing a deep comparison). otherwise it should be there
|
||||
|
||||
const auto &valuesAlreadySeenIterator = std::find(valuesAlreadySeen.cbegin(), valuesAlreadySeen.cend(), value);
|
||||
const bool valueIsDuplicated = (valuesAlreadySeenIterator != valuesAlreadySeen.cend());
|
||||
|
||||
const auto &reallyEqualCheck = [&value](const DuplicateStrategyTestType &v) { return reallyEqual(value, v); };
|
||||
QCOMPARE(std::find_if(c.begin(), c.end(), reallyEqualCheck) == c.end(), valueIsDuplicated);
|
||||
|
||||
valuesAlreadySeen.push_back(value);
|
||||
|
||||
switch (ior) {
|
||||
case IterationOnReference::ForwardIteration:
|
||||
++it;
|
||||
break;
|
||||
case IterationOnReference::ReverseIteration:
|
||||
--it;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerRejectsDuplicateValues)
|
||||
{
|
||||
non_associative_container_check_duplicates_impl_no_duplicates(reference, c, IterationOnReference::ForwardIteration);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
void non_associative_container_check_duplicates_impl(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c, ContainerOverwritesDuplicateValues)
|
||||
{
|
||||
non_associative_container_check_duplicates_impl_no_duplicates(reference, c, IterationOnReference::ReverseIteration);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
void non_associative_container_check_duplicates(const std::initializer_list<DuplicateStrategyTestType> &reference, const Container &c)
|
||||
{
|
||||
non_associative_container_check_duplicates_impl(reference, c, ContainerDuplicatedValuesStrategy<Container>());
|
||||
}
|
||||
|
||||
template<template<class ... T> class Container>
|
||||
void tst_ContainerApiSymmetry::non_associative_container_duplicates_strategy() const
|
||||
{
|
||||
// first and last are "duplicates" -- they compare equal for operator==,
|
||||
// but they differ when using reallyEqual
|
||||
const std::initializer_list<DuplicateStrategyTestType> reference{ DuplicateStrategyTestType{0},
|
||||
DuplicateStrategyTestType{1},
|
||||
DuplicateStrategyTestType{2},
|
||||
DuplicateStrategyTestType{0} };
|
||||
Container<DuplicateStrategyTestType> c1{reference};
|
||||
non_associative_container_check_duplicates(reference, c1);
|
||||
|
||||
Container<DuplicateStrategyTestType> c2{reference.begin(), reference.end()};
|
||||
non_associative_container_check_duplicates(reference, c2);
|
||||
}
|
||||
#else
|
||||
template<template<class ... T> class Container>
|
||||
void tst_ContainerApiSymmetry::non_associative_container_duplicates_strategy() const
|
||||
{
|
||||
QSKIP("Test requires a better compiler");
|
||||
}
|
||||
#endif // Q_COMPILER_INITIALIZER_LISTS
|
||||
|
||||
template <typename Container>
|
||||
Container make(int size)
|
||||
{
|
||||
|
@ -30,13 +30,17 @@
|
||||
#include <qregexp.h>
|
||||
#include <qregularexpression.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
class tst_QStringList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void constructors();
|
||||
void sort();
|
||||
void filter();
|
||||
void replaceInStrings();
|
||||
@ -66,6 +70,39 @@ private slots:
|
||||
|
||||
extern const char email[];
|
||||
|
||||
void tst_QStringList::constructors()
|
||||
{
|
||||
{
|
||||
QStringList list;
|
||||
QVERIFY(list.isEmpty());
|
||||
QCOMPARE(list.size(), 0);
|
||||
QVERIFY(list == QStringList());
|
||||
}
|
||||
{
|
||||
QString str = "abc";
|
||||
QStringList list(str);
|
||||
QVERIFY(!list.isEmpty());
|
||||
QCOMPARE(list.size(), 1);
|
||||
QCOMPARE(list.at(0), str);
|
||||
}
|
||||
{
|
||||
QStringList list{ "a", "b", "c" };
|
||||
QVERIFY(!list.isEmpty());
|
||||
QCOMPARE(list.size(), 3);
|
||||
QCOMPARE(list.at(0), "a");
|
||||
QCOMPARE(list.at(1), "b");
|
||||
QCOMPARE(list.at(2), "c");
|
||||
}
|
||||
{
|
||||
const QVector<QString> reference{ "a", "b", "c" };
|
||||
QCOMPARE(reference.size(), 3);
|
||||
|
||||
QStringList list(reference.cbegin(), reference.cend());
|
||||
QCOMPARE(list.size(), reference.size());
|
||||
QVERIFY(std::equal(list.cbegin(), list.cend(), reference.cbegin()));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStringList::indexOf_regExp()
|
||||
{
|
||||
QStringList list;
|
||||
|
Loading…
x
Reference in New Issue
Block a user