QList: Add a append(QList &&) overload

We already had append(const QList &) and now there's an overload
taking an rvalue reference.

Change-Id: Id2fbc6c57badebebeee7b80d15bb333270fa4e19
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Mårten Nordheim 2020-05-20 13:59:48 +02:00
parent 0c53f8ba98
commit 5d7be66fd7
3 changed files with 259 additions and 0 deletions

View File

@ -239,6 +239,7 @@ public:
void append(const_iterator i1, const_iterator i2);
void append(rvalue_ref t) { emplaceBack(std::move(t)); }
void append(const QList<T> &l) { append(l.constBegin(), l.constEnd()); }
void append(QList<T> &&l);
void prepend(rvalue_ref t);
void prepend(const T &t);
@ -434,14 +435,19 @@ public:
// comfort
QList<T> &operator+=(const QList<T> &l) { append(l.cbegin(), l.cend()); return *this; }
QList<T> &operator+=(QList<T> &&l) { append(std::move(l)); return *this; }
inline QList<T> operator+(const QList<T> &l) const
{ QList n = *this; n += l; return n; }
inline QList<T> operator+(QList<T> &&l) const
{ QList n = *this; n += std::move(l); return n; }
inline QList<T> &operator+=(const T &t)
{ append(t); return *this; }
inline QList<T> &operator<< (const T &t)
{ append(t); return *this; }
inline QList<T> &operator<<(const QList<T> &l)
{ *this += l; return *this; }
inline QList<T> &operator<<(QList<T> &&l)
{ *this += std::move(l); return *this; }
inline QList<T> &operator+=(rvalue_ref t)
{ append(std::move(t)); return *this; }
inline QList<T> &operator<<(rvalue_ref t)
@ -579,6 +585,33 @@ inline void QList<T>::append(const_iterator i1, const_iterator i2)
}
}
template <typename T>
inline void QList<T>::append(QList<T> &&other)
{
if (other.isEmpty())
return;
if (other.d->needsDetach() || !std::is_nothrow_move_constructible_v<T>)
return append(other);
const size_t newSize = size() + other.size();
if (d->needsDetach() || newSize > d->allocatedCapacity()) {
DataPointer detached(Data::allocate(d->detachCapacity(newSize),
d->detachFlags() | Data::GrowsForward));
if (!d->needsDetach())
detached->moveAppend(begin(), end());
else
detached->copyAppend(cbegin(), cend());
detached->moveAppend(other.begin(), other.end());
d.swap(detached);
} else {
// we're detached and we can just move data around
d->moveAppend(other.begin(), other.end());
}
}
template <typename T>
inline typename QList<T>::iterator
QList<T>::insert(qsizetype i, qsizetype n, parameter_type t)

View File

@ -670,6 +670,15 @@
\sa operator<<(), operator+=()
*/
/*! \fn template <typename T> void QList<T>::append(QList<T> &&value)
\overload
\since 6.0
Moves the items of the \a value list to the end of this list.
\sa operator<<(), operator+=()
*/
/*!
\fn template <typename T> void QList<T>::prepend(const T &value)
@ -1290,6 +1299,14 @@
\sa operator+(), append()
*/
/*! \fn template <typename T> QList<T> &QList<T>::operator+=(QList<T> &&other)
\since 6.0
\overload
\sa operator+(), append()
*/
/*! \fn template <typename T> void QList<T>::operator+=(const T &value)
\overload
@ -1315,6 +1332,14 @@
\sa operator+=()
*/
/*! \fn template <typename T> QList<T> QList<T>::operator+(QList<T> &&other) const
\since 6.0
\overload
\sa operator+=()
*/
/*! \fn template <typename T> QList<T> &QList<T>::operator<<(const T &value)
Appends \a value to the list and returns a reference to this list.
@ -1336,6 +1361,12 @@
Appends \a other to the list and returns a reference to the list.
*/
/*! \fn template <typename T> QList<T> &QList<T>::operator<<(QList<T> &&other)
\since 6.0
\overload
*/
/*! \typedef QList::iterator
The QList::iterator typedef provides an STL-style non-const

View File

@ -216,6 +216,7 @@ private slots:
void appendMovable() const;
void appendCustom() const;
void appendRvalue() const;
void appendList() const;
void at() const;
void capacityInt() const;
void capacityMovable() const;
@ -695,6 +696,200 @@ void tst_QList::appendRvalue() const
QCOMPARE(v.back(), QString("world"));
}
struct ConstructionCounted
{
ConstructionCounted(int i) : i(i) { }
ConstructionCounted(ConstructionCounted &&other) noexcept
: i(other.i), copies(other.copies), moves(other.moves + 1)
{
// set to some easily noticeable values
other.i = -64;
other.copies = -64;
other.moves = -64;
}
ConstructionCounted &operator=(ConstructionCounted &&other) noexcept
{
i = other.i;
copies = other.copies;
moves = other.moves + 1;
// set to some easily noticeable values
other.i = -64;
other.copies = -64;
other.moves = -64;
return *this;
}
ConstructionCounted(const ConstructionCounted &other) noexcept
: i(other.i), copies(other.copies + 1), moves(other.moves)
{
}
ConstructionCounted &operator=(const ConstructionCounted &other) noexcept
{
i = other.i;
copies = other.copies + 1;
moves = other.moves;
return *this;
}
~ConstructionCounted() = default;
friend bool operator==(const ConstructionCounted &lhs, const ConstructionCounted &rhs)
{
return lhs.i == rhs.i;
}
QString toString() { return QString::number(i); }
int i;
int copies = 0;
int moves = 0;
};
QT_BEGIN_NAMESPACE
namespace QTest {
char *toString(const ConstructionCounted &cc)
{
char *str = new char[5];
qsnprintf(str, 4, "%d", cc.i);
return str;
}
}
QT_END_NAMESPACE
void tst_QList::appendList() const
{
// By const-ref
{
QList<int> v1 = { 1, 2, 3, 4 };
QList<int> v2 = { 5, 6, 7, 8 };
v1.append(v2);
QCOMPARE(v2.size(), 4);
QCOMPARE(v1.size(), 8);
QList<int> expected = { 1, 2, 3, 4, 5, 6, 7, 8 };
QCOMPARE(v1, expected);
QList<int> doubleExpected = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
// append self to self
v1.append(v1);
QCOMPARE(v1.size(), 16);
QCOMPARE(v1, doubleExpected);
v1.resize(8);
// append to self, but was shared
QList v1_2(v1);
v1.append(v1);
QCOMPARE(v1_2.size(), 8);
QCOMPARE(v1_2, expected);
QCOMPARE(v1.size(), 16);
QCOMPARE(v1, doubleExpected);
v1.resize(8);
// append empty
QList<int> v3;
v1.append(v3);
// append to empty
QList<int> v4;
v4.append(v1);
QCOMPARE(v4, expected);
v1 = { 1, 2, 3, 4 };
// Using operators
// <<
QList<int> v5;
v5 << v1 << v2;
QCOMPARE(v5, expected);
// +=
QList<int> v6;
v6 += v1;
v6 += v2;
QCOMPARE(v6, expected);
// +
QCOMPARE(v1 + v2, expected);
}
// By move
{
QList<ConstructionCounted> v1 = { 1, 2, 3, 4 };
// Sanity check
QCOMPARE(v1.at(3).moves, 0);
QCOMPARE(v1.at(3).copies, 1); // because of initializer list
QList<ConstructionCounted> v2 = { 5, 6, 7, 8 };
v1.append(std::move(v2));
QCOMPARE(v1.size(), 8);
QList<ConstructionCounted> expected = { 1, 2, 3, 4, 5, 6, 7, 8 };
QCOMPARE(v1, expected);
QCOMPARE(v1.at(0).copies, 1);
QCOMPARE(v1.at(0).moves, 1);
QCOMPARE(v1.at(4).copies, 1); // was v2.at(0)
QCOMPARE(v1.at(4).moves, 1);
// append move from empty
QList<ConstructionCounted> v3;
v1.append(std::move(v3));
QCOMPARE(v1.size(), 8);
QCOMPARE(v1, expected);
for (qsizetype i = 0; i < v1.size(); ++i) {
const auto &counter = v1.at(i);
QCOMPARE(counter.copies, 1);
QCOMPARE(counter.moves, 1);
}
// append move to empty
QList<ConstructionCounted> v4;
v4.reserve(64);
v4.append(std::move(v1));
QCOMPARE(v4.size(), 8);
QCOMPARE(v4, expected);
for (qsizetype i = 0; i < v4.size(); ++i) {
const auto &counter = v4.at(i);
QCOMPARE(counter.copies, 1);
QCOMPARE(counter.moves, 2);
}
QVERIFY(v4.capacity() >= 64);
v1.swap(v4); // swap back...
// append move from shared
QList<ConstructionCounted> v5 = { 1, 2, 3, 4 };
QList<ConstructionCounted> v5_2(v5);
v1.append(std::move(v5_2));
QCOMPARE(v1.size(), 12);
QList<ConstructionCounted> expectedTwelve = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4 };
QCOMPARE(v1, expectedTwelve);
QCOMPARE(v5.size(), 4);
QList<ConstructionCounted> expectedFour = { 1, 2, 3, 4 };
QCOMPARE(v5, expectedFour);
QCOMPARE(v5.at(0).copies, 1); // from constructing with std::initializer_list
QCOMPARE(v5.at(0).moves, 0);
// Using operators
// <<
QList<ConstructionCounted> v6;
v6 << (QList<ConstructionCounted>() << 1 << 2);
v6 << (QList<ConstructionCounted>() << 3 << 4);
QCOMPARE(v6, expectedFour);
QCOMPARE(v6.at(0).copies, 2);
QCOMPARE(v6.at(0).moves, 1);
// +=
QList<ConstructionCounted> v7;
v7 += (QList<ConstructionCounted>() << 1 << 2);
v7 += (QList<ConstructionCounted>() << 3 << 4);
QCOMPARE(v7, expectedFour);
// +
QList<ConstructionCounted> v8;
QCOMPARE(v8 + (QList<ConstructionCounted>() << 1 << 2 << 3 << 4), expectedFour);
v8 = { 1, 2 };
QCOMPARE(v8 + (QList<ConstructionCounted>() << 3 << 4), expectedFour);
}
}
void tst_QList::at() const
{
QList<QString> myvec;