summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qlist.h33
-rw-r--r--src/corelib/tools/qlist.qdoc31
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp195
3 files changed, 259 insertions, 0 deletions
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 0078f87cce..443789b411 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -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)
@@ -580,6 +586,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)
{
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
index 8d1280a2ea..339c089bb8 100644
--- a/src/corelib/tools/qlist.qdoc
+++ b/src/corelib/tools/qlist.qdoc
@@ -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
diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
index 71884a2927..c5ba53ad57 100644
--- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp
+++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
@@ -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;