summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp')
-rw-r--r--tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp153
1 files changed, 153 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
index f676307730..bb76caed3e 100644
--- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
+++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
@@ -82,6 +82,8 @@ private slots:
void freeSpace();
void dataPointerAllocate_data();
void dataPointerAllocate();
+ void selfEmplaceBackwards();
+ void selfEmplaceForward();
#ifndef QT_NO_EXCEPTIONS
void exceptionSafetyPrimitives_constructor();
void exceptionSafetyPrimitives_destructor();
@@ -2128,6 +2130,157 @@ void tst_QArrayData::dataPointerAllocate()
}
}
+struct MyQStringWrapper : public QString
+{
+ bool movedTo = false;
+ bool movedFrom = false;
+ MyQStringWrapper() = default;
+ MyQStringWrapper(QChar c) : QString(c) { }
+ MyQStringWrapper(MyQStringWrapper &&other) : QString(std::move(static_cast<QString>(other)))
+ {
+ movedTo = true;
+ movedFrom = other.movedFrom;
+ other.movedFrom = true;
+ }
+ MyQStringWrapper &operator=(MyQStringWrapper &&other)
+ {
+ QString::operator=(std::move(static_cast<QString>(other)));
+ movedTo = true;
+ movedFrom = other.movedFrom;
+ other.movedFrom = true;
+ return *this;
+ }
+ MyQStringWrapper(const MyQStringWrapper &) = default;
+ MyQStringWrapper &operator=(const MyQStringWrapper &) = default;
+ ~MyQStringWrapper() = default;
+};
+
+struct MyMovableQString : public MyQStringWrapper
+{
+ MyMovableQString() = default;
+ MyMovableQString(QChar c) : MyQStringWrapper(c) { }
+
+private:
+ friend bool operator==(const MyMovableQString &a, QChar c)
+ {
+ return static_cast<QString>(a) == QString(c);
+ }
+
+ friend bool operator==(const MyMovableQString &a, const MyMovableQString &b)
+ {
+ return static_cast<QString>(a) == static_cast<QString>(b);
+ }
+};
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(MyMovableQString, Q_RELOCATABLE_TYPE);
+QT_END_NAMESPACE
+static_assert(QTypeInfo<MyMovableQString>::isComplex);
+static_assert(QTypeInfo<MyMovableQString>::isRelocatable);
+
+struct MyComplexQString : public MyQStringWrapper
+{
+ MyComplexQString() = default;
+ MyComplexQString(QChar c) : MyQStringWrapper(c) { }
+
+private:
+ friend bool operator==(const MyComplexQString &a, QChar c)
+ {
+ return static_cast<QString>(a) == QString(c);
+ }
+
+ friend bool operator==(const MyComplexQString &a, const MyComplexQString &b)
+ {
+ return static_cast<QString>(a) == static_cast<QString>(b);
+ }
+};
+static_assert(QTypeInfo<MyComplexQString>::isComplex);
+static_assert(!QTypeInfo<MyComplexQString>::isRelocatable);
+
+void tst_QArrayData::selfEmplaceBackwards()
+{
+ const auto createDataPointer = [](qsizetype capacity, int spaceAtEnd, auto dummy) {
+ using Type = std::decay_t<decltype(dummy)>;
+ Q_UNUSED(dummy);
+ auto [header, ptr] = QTypedArrayData<Type>::allocate(capacity, QArrayData::Grow);
+ // do custom adjustments to make sure there's free space at end
+ ptr += header->alloc - spaceAtEnd;
+ return QArrayDataPointer(header, ptr);
+ };
+
+ const auto testSelfEmplace = [&](auto dummy, int spaceAtEnd, auto initValues) {
+ auto adp = createDataPointer(100, spaceAtEnd, dummy);
+ for (auto v : initValues) {
+ adp->emplaceBack(v);
+ }
+ QVERIFY(!adp.freeSpaceAtEnd());
+ QVERIFY(adp.freeSpaceAtBegin());
+
+ adp->emplace(adp.end(), adp.data()[0]);
+ for (qsizetype i = 0; i < adp.size - 1; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i]);
+ }
+ QCOMPARE(adp.data()[adp.size - 1], initValues[0]);
+
+ adp->emplace(adp.end(), std::move(adp.data()[0]));
+ for (qsizetype i = 1; i < adp.size - 2; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i]);
+ }
+ QCOMPARE(adp.data()[adp.size - 2], initValues[0]);
+ QCOMPARE(adp.data()[0].movedFrom, true);
+ QCOMPARE(adp.data()[adp.size - 1], initValues[0]);
+ QCOMPARE(adp.data()[adp.size - 1].movedTo, true);
+ };
+
+ QList<QChar> movableObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyMovableQString(), 4, movableObjs);
+ QList<QChar> complexObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyComplexQString(), 4, complexObjs);
+}
+
+void tst_QArrayData::selfEmplaceForward()
+{
+ const auto createDataPointer = [](qsizetype capacity, int spaceAtBegin, auto dummy) {
+ using Type = std::decay_t<decltype(dummy)>;
+ Q_UNUSED(dummy);
+ auto [header, ptr] = QTypedArrayData<Type>::allocate(capacity, QArrayData::Grow);
+ // do custom adjustments to make sure there's free space at end
+ ptr += spaceAtBegin;
+ return QArrayDataPointer(header, ptr);
+ };
+
+ const auto testSelfEmplace = [&](auto dummy, int spaceAtBegin, auto initValues) {
+ auto adp = createDataPointer(100, spaceAtBegin, dummy);
+ auto reversedInitValues = initValues;
+ std::reverse(reversedInitValues.begin(), reversedInitValues.end());
+ for (auto v : reversedInitValues) {
+ adp->emplaceFront(v);
+ }
+ QVERIFY(!adp.freeSpaceAtBegin());
+ QVERIFY(adp.freeSpaceAtEnd());
+
+ adp->emplace(adp.begin(), adp.data()[adp.size - 1]);
+ for (qsizetype i = 1; i < adp.size; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i - 1]);
+ }
+ QCOMPARE(adp.data()[0], initValues[spaceAtBegin - 1]);
+
+ adp->emplace(adp.begin(), std::move(adp.data()[adp.size - 1]));
+ for (qsizetype i = 2; i < adp.size; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i - 2]);
+ }
+ QCOMPARE(adp.data()[1], initValues[spaceAtBegin - 1]);
+ QCOMPARE(adp.data()[adp.size - 1].movedFrom, true);
+ QCOMPARE(adp.data()[0], initValues[spaceAtBegin - 1]);
+ QCOMPARE(adp.data()[0].movedTo, true);
+ };
+
+ QList<QChar> movableObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyMovableQString(), 4, movableObjs);
+ QList<QChar> complexObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyComplexQString(), 4, complexObjs);
+}
+
#ifndef QT_NO_EXCEPTIONS
struct ThrowingTypeWatcher
{