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.cpp137
1 files changed, 130 insertions, 7 deletions
diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
index 0172927042..c27147dfdb 100644
--- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
+++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
@@ -38,6 +38,7 @@
#include <algorithm>
#include <vector>
#include <stdexcept>
+#include <functional>
// A wrapper for a test function. Calls a function, if it fails, reports failure
#define RUN_TEST_FUNC(test, ...) \
@@ -78,6 +79,10 @@ private slots:
void grow();
void freeSpace_data();
void freeSpace();
+ void dataPointerAllocate_data() { arrayOps_data(); }
+ void dataPointerAllocate();
+ void dataPointerAllocateAlignedWithReallocate_data();
+ void dataPointerAllocateAlignedWithReallocate();
#ifndef QT_NO_EXCEPTIONS
void exceptionSafetyPrimitives_constructor();
void exceptionSafetyPrimitives_destructor();
@@ -473,7 +478,8 @@ void tst_QArrayData::allocate_data()
} options[] = {
{ "Default", QArrayData::DefaultAllocationFlags, false },
{ "Reserved", QArrayData::CapacityReserved, true },
- { "Grow", QArrayData::GrowsForward, false }
+ { "Grow", QArrayData::GrowsForward, false },
+ { "GrowBack", QArrayData::GrowsBackwards, false }
};
for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i)
@@ -507,7 +513,7 @@ void tst_QArrayData::allocate()
keeper.headers.append(data);
- if (allocateOptions & QArrayData::GrowsForward)
+ if (allocateOptions & (QArrayData::GrowsForward | QArrayData::GrowsBackwards))
QVERIFY(data->allocatedCapacity() > capacity);
else
QCOMPARE(data->allocatedCapacity(), capacity);
@@ -549,7 +555,7 @@ void tst_QArrayData::reallocate()
keeper.headers.clear();
keeper.headers.append(data);
- if (allocateOptions & QArrayData::GrowsForward)
+ if (allocateOptions & (QArrayData::GrowsForward | QArrayData::GrowsBackwards))
QVERIFY(data->allocatedCapacity() > newCapacity);
else
QCOMPARE(data->allocatedCapacity(), newCapacity);
@@ -1128,6 +1134,7 @@ void tst_QArrayData::arrayOpsExtra()
const auto setupDataPointers = [&allocationOptions] (size_t capacity, size_t initialSize = 0) {
const qsizetype alloc = qsizetype(capacity);
+ // QTBUG-84320: change to growing function once supported
QArrayDataPointer<int> i(QTypedArrayData<int>::allocate(alloc, allocationOptions));
QArrayDataPointer<QString> s(QTypedArrayData<QString>::allocate(alloc, allocationOptions));
QArrayDataPointer<CountedObject> o(QTypedArrayData<CountedObject>::allocate(alloc, allocationOptions));
@@ -1839,14 +1846,14 @@ void tst_QArrayData::freeSpace()
{
QFETCH(QArrayData::ArrayOptions, allocationOptions);
QFETCH(size_t, n);
- const auto testFreeSpace = [] (auto dummy, auto options, size_t n) {
+ const auto testFreeSpace = [] (auto dummy, auto options, qsizetype n) {
using Type = std::decay_t<decltype(dummy)>;
- using Data = QTypedArrayData<Type>;
using DataPointer = QArrayDataPointer<Type>;
Q_UNUSED(dummy);
- DataPointer ptr(Data::allocate(n, options));
+ const qsizetype capacity = n + 1;
+ auto ptr = DataPointer::allocateGrow(DataPointer(), capacity, n, options);
const auto alloc = qsizetype(ptr.constAllocatedCapacity());
- QVERIFY(size_t(alloc) >= n);
+ QVERIFY(alloc >= capacity);
QCOMPARE(ptr.freeSpaceAtBegin() + ptr.freeSpaceAtEnd(), alloc);
};
RUN_TEST_FUNC(testFreeSpace, char(0), allocationOptions, n);
@@ -1856,6 +1863,122 @@ void tst_QArrayData::freeSpace()
RUN_TEST_FUNC(testFreeSpace, CountedObject(), allocationOptions, n);
}
+void tst_QArrayData::dataPointerAllocate()
+{
+ QFETCH(QArrayData::ArrayOptions, allocationOptions);
+ const auto createDataPointer = [] (qsizetype capacity, auto initValue) {
+ using Type = std::decay_t<decltype(initValue)>;
+ Q_UNUSED(initValue);
+ return QArrayDataPointer<Type>(QTypedArrayData<Type>::allocate(capacity));
+ };
+
+ const auto testRealloc = [&] (qsizetype capacity, qsizetype newSize, auto initValue) {
+ using Type = std::decay_t<decltype(initValue)>;
+ using DataPointer = QArrayDataPointer<Type>;
+
+ auto oldDataPointer = createDataPointer(capacity, initValue);
+ oldDataPointer->insert(oldDataPointer.begin(), 1, initValue); // trigger prepend
+ QVERIFY(!oldDataPointer.needsDetach());
+
+ auto newDataPointer = DataPointer::allocateGrow(
+ oldDataPointer, oldDataPointer->detachCapacity(newSize), newSize, allocationOptions);
+ const auto newAlloc = newDataPointer.constAllocatedCapacity();
+ const auto freeAtBegin = newDataPointer.freeSpaceAtBegin();
+ const auto freeAtEnd = newDataPointer.freeSpaceAtEnd();
+
+ QVERIFY(newAlloc > oldDataPointer.constAllocatedCapacity());
+ QCOMPARE(size_t(freeAtBegin + freeAtEnd), newAlloc);
+ // when not detached, the behavior is the same as of ::realloc
+ if (allocationOptions & (QArrayData::GrowsForward | QArrayData::GrowsBackwards))
+ QCOMPARE(freeAtBegin, oldDataPointer.freeSpaceAtBegin());
+ else
+ QCOMPARE(freeAtBegin, 0);
+ };
+
+ for (size_t n : {10, 512, 1000}) {
+ RUN_TEST_FUNC(testRealloc, n, n + 1, int(0));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, char('a'));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, char16_t(u'a'));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, QString("hello, world!"));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, CountedObject());
+ }
+
+ const auto testDetachRealloc = [&] (qsizetype capacity, qsizetype newSize, auto initValue) {
+ using Type = std::decay_t<decltype(initValue)>;
+ using DataPointer = QArrayDataPointer<Type>;
+
+ auto oldDataPointer = createDataPointer(capacity, initValue);
+ oldDataPointer->insert(oldDataPointer.begin(), 1, initValue); // trigger prepend
+ auto oldDataPointerCopy = oldDataPointer; // force detach later
+ QVERIFY(oldDataPointer.needsDetach());
+
+ auto newDataPointer = DataPointer::allocateGrow(
+ oldDataPointer, oldDataPointer->detachCapacity(newSize), newSize, allocationOptions);
+ const auto newAlloc = newDataPointer.constAllocatedCapacity();
+ const auto freeAtBegin = newDataPointer.freeSpaceAtBegin();
+ const auto freeAtEnd = newDataPointer.freeSpaceAtEnd();
+
+ QVERIFY(newAlloc > oldDataPointer.constAllocatedCapacity());
+ QCOMPARE(size_t(freeAtBegin + freeAtEnd), newAlloc);
+ if (allocationOptions & QArrayData::GrowsBackwards) {
+ QCOMPARE(size_t(freeAtBegin), (newAlloc - newSize) / 2);
+ } else {
+ QCOMPARE(freeAtBegin, 0);
+ }
+ };
+
+ for (size_t n : {10, 512, 1000}) {
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, int(0));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, char('a'));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, char16_t(u'a'));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, QString("hello, world!"));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, CountedObject());
+ }
+}
+
+void tst_QArrayData::dataPointerAllocateAlignedWithReallocate_data()
+{
+ QTest::addColumn<QArrayData::ArrayOptions>("initFlags");
+ QTest::addColumn<QArrayData::ArrayOptions>("newFlags");
+
+ QTest::newRow("default-flags") << QArrayData::ArrayOptions(QArrayData::DefaultAllocationFlags)
+ << QArrayData::ArrayOptions(QArrayData::DefaultAllocationFlags);
+ QTest::newRow("no-grows-backwards") << QArrayData::ArrayOptions(QArrayData::GrowsForward)
+ << QArrayData::ArrayOptions(QArrayData::GrowsForward);
+ QTest::newRow("grows-backwards") << QArrayData::ArrayOptions(QArrayData::GrowsBackwards)
+ << QArrayData::ArrayOptions(QArrayData::GrowsBackwards);
+ QTest::newRow("removed-grows-backwards") << QArrayData::ArrayOptions(QArrayData::GrowsBackwards)
+ << QArrayData::ArrayOptions(QArrayData::GrowsForward);
+ QTest::newRow("removed-growth") << QArrayData::ArrayOptions(QArrayData::GrowsBackwards)
+ << QArrayData::ArrayOptions(QArrayData::DefaultAllocationFlags);
+}
+
+void tst_QArrayData::dataPointerAllocateAlignedWithReallocate()
+{
+ QFETCH(QArrayData::ArrayOptions, initFlags);
+ QFETCH(QArrayData::ArrayOptions, newFlags);
+
+ // Note: using the same type to ensure alignment and padding are the same.
+ // otherwise, we may get differences in the allocated size
+ auto a = QArrayDataPointer<int>::allocateGrow(QArrayDataPointer<int>(), 50, 0, initFlags);
+ auto b = QArrayDataPointer<int>::allocateGrow(QArrayDataPointer<int>(), 50, 0, initFlags);
+
+ if (initFlags & QArrayData::GrowsBackwards) {
+ QVERIFY(a.freeSpaceAtBegin() > 0);
+ } else {
+ QVERIFY(a.freeSpaceAtBegin() == 0);
+ }
+ QCOMPARE(a.freeSpaceAtBegin(), b.freeSpaceAtBegin());
+
+ a->reallocate(100, newFlags);
+ b = QArrayDataPointer<int>::allocateGrow(b, 100, b.size, newFlags);
+
+ // It is enough to test that the behavior of reallocate is the same as the
+ // behavior of allocate w.r.t. pointer adjustment in case of
+ // GrowsBackwards. Actual values are not that interesting
+ QCOMPARE(a.freeSpaceAtBegin(), b.freeSpaceAtBegin());
+}
+
#ifndef QT_NO_EXCEPTIONS
struct ThrowingTypeWatcher
{