summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools/qlist/tst_qlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/tools/qlist/tst_qlist.cpp')
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp267
1 files changed, 240 insertions, 27 deletions
diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
index fef30647e3..35d69e8433 100644
--- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp
+++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
@@ -1,15 +1,15 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QTest>
#include <QAtomicInt>
#include <QThread>
#include <QSemaphore>
-#include <QScopedValueRollback>
+#include <QAtomicScopedValueRollback>
#include <qlist.h>
-#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
+#ifdef QT_COMPILER_HAS_LWG3346
# if __has_include(<concepts>)
# include <concepts>
# if defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L
@@ -231,6 +231,16 @@ private slots:
void appendCustom() const { append<Custom>(); }
void appendRvalue() const;
void appendList() const;
+ void assignEmpty() const;
+ void assignInt() const { assign<int>(); }
+ void assignMovable() const { assign<Movable>(); }
+ void assignCustom() const { assign<Custom>(); }
+ void assignUsesPrependBuffer_int_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_int() const { assignUsesPrependBuffer<int>(); }
+ void assignUsesPrependBuffer_Movable_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_Movable() const { assignUsesPrependBuffer<Movable>(); }
+ void assignUsesPrependBuffer_Custom_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_Custom() const { assignUsesPrependBuffer<Custom>(); }
void at() const;
void capacityInt() const { capacity<int>(); }
void capacityMovable() const { capacity<Movable>(); }
@@ -312,6 +322,7 @@ private slots:
void resizeToZero() const;
void resizeToTheSameSize_data();
void resizeToTheSameSize() const;
+ void resizeForOverwrite() const;
void iterators() const;
void constIterators() const;
void reverseIterators() const;
@@ -396,6 +407,9 @@ private:
template<typename T> void testAssignment() const;
template<typename T> void add() const;
template<typename T> void append() const;
+ template<typename T> void assign() const;
+ void assignUsesPrependBuffer_data() const;
+ template<typename T> void assignUsesPrependBuffer() const;
template<typename T> void assignFromInitializerList() const;
template<typename T> void capacity() const;
template<typename T> void clear() const;
@@ -548,25 +562,22 @@ void tst_QList::constructors_reserveAndInitialize() const
{
// default-initialise items
- QList<int> myInt(5, 42);
+ const QList<int> myInt(5, 42);
QVERIFY(myInt.capacity() == 5);
- foreach (int meaningoflife, myInt) {
+ for (int meaningoflife : myInt)
QCOMPARE(meaningoflife, 42);
- }
- QList<QString> myString(5, QString::fromLatin1("c++"));
+ const QList<QString> myString(5, QString::fromLatin1("c++"));
QVERIFY(myString.capacity() == 5);
// make sure all items are initialised ok
- foreach (QString meaningoflife, myString) {
+ for (const QString &meaningoflife : myString)
QCOMPARE(meaningoflife, QString::fromLatin1("c++"));
- }
- QList<Custom> myCustom(5, Custom('n'));
+ const QList<Custom> myCustom(5, Custom('n'));
QVERIFY(myCustom.capacity() == 5);
// make sure all items are initialised ok
- foreach (Custom meaningoflife, myCustom) {
+ for (Custom meaningoflife : myCustom)
QCOMPARE(meaningoflife.i, 'n');
- }
}
template<typename T>
@@ -750,6 +761,162 @@ void tst_QList::append() const
}
}
+void tst_QList::assignEmpty() const
+{
+ // Test that the realloc branch in assign(it, it) doesn't crash.
+ using T = int;
+ QList<T> list;
+ QList<T> ref1 = list;
+ QVERIFY(list.d.needsDetach());
+ list.assign(list.begin(), list.begin());
+
+#if !defined Q_OS_QNX // QNX has problems with the empty istream_iterator
+ auto empty = std::istream_iterator<T>{};
+ list.squeeze();
+ QCOMPARE_EQ(list.capacity(), 0);
+ ref1 = list;
+ QVERIFY(list.d.needsDetach());
+ list.assign(empty, empty);
+#endif
+}
+
+template <typename T>
+void tst_QList::assign() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+ {
+ QList<T> myvec;
+ myvec.assign(2, T_FOO);
+ QVERIFY(myvec.isDetached());
+ QCOMPARE(myvec, QList<T>() << T_FOO << T_FOO);
+
+ QList<T> myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ myvec.assign(3, T_BAR);
+ QCOMPARE(myvec, QList<T>() << T_BAR << T_BAR << T_BAR);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(myvecCopy.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
+ }
+ {
+ QList<T> myvec;
+ myvec.assign(4, T_FOO);
+ QVERIFY(myvec.isDetached());
+ QCOMPARE(myvec, QList<T>() << T_FOO << T_FOO << T_FOO << T_FOO);
+
+ QList<T> myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ myvecCopy.assign(myvec.begin(), myvec.begin() + 2);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(myvecCopy.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
+ QCOMPARE(myvecCopy, QList<T>() << T_FOO << T_FOO);
+ }
+}
+
+inline namespace Scenarios {
+Q_NAMESPACE
+enum ListState {
+ UnsharedList,
+ SharedList,
+};
+Q_ENUM_NS(ListState)
+enum RelationWithPrependBuffer {
+ FitsIntoFreeSpaceAtBegin,
+ FitsFreeSpaceAtBeginExactly,
+ ExceedsFreeSpaceAtBegin,
+ FitsFreeSpaceAtBeginPlusSizeExactly,
+ FullCapacity,
+};
+Q_ENUM_NS(RelationWithPrependBuffer)
+} // namespace Scenarios
+
+void tst_QList::assignUsesPrependBuffer_data() const
+{
+ QTest::addColumn<ListState>("listState");
+ QTest::addColumn<RelationWithPrependBuffer>("relationWithPrependBuffer");
+
+ const auto sme = QMetaEnum::fromType<ListState>();
+ const auto rme = QMetaEnum::fromType<RelationWithPrependBuffer>();
+
+ for (int i = 0, s = sme.value(i); s != -1; s = sme.value(++i)) {
+ for (int j = 0, r = rme.value(j); r != -1; r = rme.value(++j)) {
+ QTest::addRow("%s-%s", sme.key(i), rme.key(j))
+ << ListState(s) << RelationWithPrependBuffer(r);
+ }
+ }
+}
+
+template <typename T>
+void tst_QList::assignUsesPrependBuffer() const
+{
+ QFETCH(const ListState, listState);
+ QFETCH(const RelationWithPrependBuffer, relationWithPrependBuffer);
+
+ const auto capBegin = [](const QList<T> &l) {
+ return l.begin() - l.d.freeSpaceAtBegin();
+ };
+ const auto capEnd = [](const QList<T> &l) {
+ return l.end() + l.d.freeSpaceAtEnd();
+ };
+
+ TST_QLIST_CHECK_LEAKS(T)
+ {
+ // Test the prepend optimization.
+ QList<T> withFreeSpaceAtBegin(16, T_FOO);
+ // try at most 100 times to create freeSpaceAtBegin():
+ for (int i = 0; i < 100 && withFreeSpaceAtBegin.d.freeSpaceAtBegin() < 2; ++i)
+ withFreeSpaceAtBegin.prepend(T_FOO);
+ QCOMPARE_GT(withFreeSpaceAtBegin.d.freeSpaceAtBegin(), 1);
+
+ auto c = [&] {
+ switch (listState) {
+ case UnsharedList: return std::move(withFreeSpaceAtBegin);
+ case SharedList: return withFreeSpaceAtBegin;
+ }
+ Q_UNREACHABLE_RETURN(withFreeSpaceAtBegin);
+ }();
+
+ const auto n = [&] () -> qsizetype {
+ switch (relationWithPrependBuffer) {
+ case FitsIntoFreeSpaceAtBegin:
+ return qsizetype(1);
+ case FitsFreeSpaceAtBeginExactly:
+ return c.d.freeSpaceAtBegin();
+ case ExceedsFreeSpaceAtBegin:
+ return c.d.freeSpaceAtBegin() + 1;
+ case FitsFreeSpaceAtBeginPlusSizeExactly:
+ return c.d.freeSpaceAtBegin() + c.size();
+ case FullCapacity:
+ return c.capacity();
+ };
+ Q_UNREACHABLE_RETURN(0);
+ }();
+
+ const auto oldCapBegin = capBegin(c);
+ const auto oldCapEnd = capEnd(c);
+
+ const std::vector v(n, T_BAR);
+ c.assign(v.begin(), v.end());
+ QCOMPARE_EQ(c.d.freeSpaceAtBegin(), 0); // we used the prepend-buffer
+ if (listState != SharedList) {
+ // check that we didn't reallocate
+ QCOMPARE_EQ(capBegin(c), oldCapBegin);
+ QCOMPARE_EQ(capEnd(c), oldCapEnd);
+ }
+ }
+}
+
void tst_QList::appendRvalue() const
{
QList<QString> v;
@@ -941,6 +1108,7 @@ void tst_QList::appendList() const
// Using operators
// <<
QList<ConstructionCounted> v6;
+ v6.reserve(4);
v6 << (QList<ConstructionCounted>() << 1 << 2);
v6 << (QList<ConstructionCounted>() << 3 << 4);
QCOMPARE(v6, expectedFour);
@@ -1078,20 +1246,20 @@ void tst_QList::count() const
{
// zero size
QList<T> myvec;
- QVERIFY(myvec.count() == 0);
+ QVERIFY(myvec.size() == 0);
QVERIFY(!myvec.isDetached());
// grow
myvec.append(SimpleValue<T>::at(0));
- QVERIFY(myvec.count() == 1);
+ QVERIFY(myvec.size() == 1);
myvec.append(SimpleValue<T>::at(1));
- QVERIFY(myvec.count() == 2);
+ QVERIFY(myvec.size() == 2);
// shrink
myvec.remove(0);
- QVERIFY(myvec.count() == 1);
+ QVERIFY(myvec.size() == 1);
myvec.remove(0);
- QVERIFY(myvec.count() == 0);
+ QVERIFY(myvec.size() == 0);
}
// count of items
@@ -1905,11 +2073,11 @@ void tst_QList::move() const
list << T_FOO << T_BAR << T_BAZ;
// move an item
- list.move(0, list.count() - 1);
+ list.move(0, list.size() - 1);
QCOMPARE(list, QList<T>() << T_BAR << T_BAZ << T_FOO);
// move it back
- list.move(list.count() - 1, 0);
+ list.move(list.size() - 1, 0);
QCOMPARE(list, QList<T>() << T_FOO << T_BAR << T_BAZ);
// move an item in the middle
@@ -2364,6 +2532,51 @@ void tst_QList::resizeToTheSameSize() const
QCOMPARE(y.size(), x.size());
}
+void tst_QList::resizeForOverwrite() const
+{
+ constexpr int BUILD_COUNT = 42;
+ {
+ // Smoke test
+ QList<int> l(BUILD_COUNT, Qt::Uninitialized);
+ l.resizeForOverwrite(l.size() + BUILD_COUNT);
+ }
+
+ {
+ const int beforeCounter = Movable::counter.loadRelaxed();
+ QList<Movable> l(BUILD_COUNT, Qt::Uninitialized);
+ const int after1Counter = Movable::counter.loadRelaxed();
+ QCOMPARE(after1Counter, beforeCounter + BUILD_COUNT);
+
+ l.resizeForOverwrite(l.size() + BUILD_COUNT);
+ const int after2Counter = Movable::counter.loadRelaxed();
+ QCOMPARE(after2Counter, after1Counter + BUILD_COUNT);
+ }
+
+ struct QtInitializationSupport {
+ bool wasInitialized;
+ QtInitializationSupport() : wasInitialized(true) {}
+ explicit QtInitializationSupport(Qt::Initialization) : wasInitialized(false) {}
+ };
+
+ {
+ QList<QtInitializationSupport> l(BUILD_COUNT);
+ for (const auto &elem : l)
+ QVERIFY(elem.wasInitialized);
+ l.resize(l.size() + BUILD_COUNT);
+ for (const auto &elem : l)
+ QVERIFY(elem.wasInitialized);
+ }
+
+ {
+ QList<QtInitializationSupport> l(BUILD_COUNT, Qt::Uninitialized);
+ for (const auto &elem : l)
+ QVERIFY(!elem.wasInitialized);
+ l.resizeForOverwrite(l.size() + BUILD_COUNT);
+ for (const auto &elem : l)
+ QVERIFY(!elem.wasInitialized);
+ }
+}
+
void tst_QList::iterators() const
{
QList<int> v;
@@ -2673,24 +2886,24 @@ void tst_QList::size() const
// zero size
QList<T> myvec;
QVERIFY(myvec.size() == 0);
- QCOMPARE(myvec.length(), myvec.size());
+ QCOMPARE(myvec.size(), myvec.size());
QVERIFY(!myvec.isDetached());
// grow
myvec.append(SimpleValue<T>::at(0));
QVERIFY(myvec.size() == 1);
- QCOMPARE(myvec.length(), myvec.size());
+ QCOMPARE(myvec.size(), myvec.size());
myvec.append(SimpleValue<T>::at(1));
QVERIFY(myvec.size() == 2);
- QCOMPARE(myvec.length(), myvec.size());
+ QCOMPARE(myvec.size(), myvec.size());
// shrink
myvec.remove(0);
QVERIFY(myvec.size() == 1);
- QCOMPARE(myvec.length(), myvec.size());
+ QCOMPARE(myvec.size(), myvec.size());
myvec.remove(0);
QVERIFY(myvec.size() == 0);
- QCOMPARE(myvec.length(), myvec.size());
+ QCOMPARE(myvec.size(), myvec.size());
}
// ::squeeze() is tested in ::capacity().
@@ -3181,7 +3394,7 @@ void tst_QList::emplaceReturnsIterator()
void tst_QList::emplaceFront() const
{
- QScopedValueRollback<QAtomicInt> rollback(Movable::counter, 0);
+ QAtomicScopedValueRollback rollback(Movable::counter, 0);
QList<Movable> vec;
vec.emplaceFront('b');
@@ -3206,7 +3419,7 @@ void tst_QList::emplaceFrontReturnsRef() const
void tst_QList::emplaceBack()
{
- QScopedValueRollback<QAtomicInt> rollback(Movable::counter, 0);
+ QAtomicScopedValueRollback rollback(Movable::counter, 0);
QList<Movable> vec;
@@ -3613,7 +3826,7 @@ void tst_QList::stability_append() const
std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
QList<T> src(1, SimpleValue<T>::at(0));
v.append(src.begin(), src.end());
- QVERIFY(v.size() < v.capacity());
+ QCOMPARE_LE(v.size(), v.capacity());
for (int i = 0; i < v.capacity() - v.size(); ++i) {
auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());