From 3d61c5ca8f00b489435d5bea776b4a4c97c39793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 24 Nov 2011 17:15:11 +0100 Subject: Add setSharable support in QArrayData stack Making use of the same feature added in RefCount. To keep with the intention of avoiding the allocation of "empty" array headers, this introduces an unsharable_empty, which allows users to maintain the "unsharable bit" on empty containers, without imposing any actual allocations. (Before anyone asks, there is no point to a zero-sized capacity-reserved container so no other combinations are needed for now.) Change-Id: Icaa40ac3100ad954fdc20dee0c991861136a5b19 Reviewed-by: Bradley T. Hughes --- .../corelib/tools/qarraydata/tst_qarraydata.cpp | 152 ++++++++++++++++++++- 1 file changed, 146 insertions(+), 6 deletions(-) (limited to 'tests/auto/corelib') diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index e9a3218331..e8edab20e4 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -79,6 +79,8 @@ private slots: void typedData(); void gccBug43247(); void arrayOps(); + void setSharable_data(); + void setSharable(); }; template const T &const_(const T &t) { return t; } @@ -477,6 +479,7 @@ void tst_QArrayData::allocate_data() QTest::addColumn("objectSize"); QTest::addColumn("alignment"); QTest::addColumn("isCapacityReserved"); + QTest::addColumn("isSharable"); QTest::addColumn("commonEmpty"); struct { @@ -492,10 +495,13 @@ void tst_QArrayData::allocate_data() struct { char const *description; bool isCapacityReserved; + bool isSharable; const QArrayData *commonEmpty; } options[] = { - { "Default", false, &QArrayData::shared_empty }, - { "Reserved", true, &QArrayData::shared_empty }, + { "Default", false, true, &QArrayData::shared_empty }, + { "Reserved", true, true, &QArrayData::shared_empty }, + { "Reserved | Unsharable", true, false, &QArrayData::unsharable_empty }, + { "Unsharable", false, false, &QArrayData::unsharable_empty }, }; for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i) @@ -505,7 +511,8 @@ void tst_QArrayData::allocate_data() + QLatin1String(": ") + QLatin1String(options[j].description))) << types[i].objectSize << types[i].alignment - << options[j].isCapacityReserved << options[j].commonEmpty; + << options[j].isCapacityReserved << options[j].isSharable + << options[j].commonEmpty; } void tst_QArrayData::allocate() @@ -513,6 +520,7 @@ void tst_QArrayData::allocate() QFETCH(size_t, objectSize); QFETCH(size_t, alignment); QFETCH(bool, isCapacityReserved); + QFETCH(bool, isSharable); QFETCH(const QArrayData *, commonEmpty); // Minimum alignment that can be requested is that of QArrayData. @@ -521,19 +529,20 @@ void tst_QArrayData::allocate() // Shared Empty QCOMPARE(QArrayData::allocate(objectSize, minAlignment, 0, - isCapacityReserved), commonEmpty); + isCapacityReserved, isSharable), commonEmpty); Deallocator keeper(objectSize, minAlignment); keeper.headers.reserve(1024); for (int capacity = 1; capacity <= 1024; capacity <<= 1) { QArrayData *data = QArrayData::allocate(objectSize, minAlignment, - capacity, isCapacityReserved); + capacity, isCapacityReserved, isSharable); keeper.headers.append(data); QCOMPARE(data->size, 0); QVERIFY(data->alloc >= uint(capacity)); QCOMPARE(data->capacityReserved, uint(isCapacityReserved)); + QCOMPARE(data->ref.isSharable(), isSharable); // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. @@ -569,7 +578,7 @@ void tst_QArrayData::alignment() for (int i = 0; i < 100; ++i) { QArrayData *data = QArrayData::allocate(sizeof(Unaligned), - minAlignment, 8, false); + minAlignment, 8, false, true); keeper.headers.append(data); QVERIFY(data); @@ -903,5 +912,136 @@ void tst_QArrayData::arrayOps() } } +Q_DECLARE_METATYPE(QArrayDataPointer) + +static inline bool arrayIsFilledWith(const QArrayDataPointer &array, + int fillValue, size_t size) +{ + const int *iter = array->begin(); + const int *const end = array->end(); + + for (size_t i = 0; i < size; ++i, ++iter) + if (*iter != fillValue) + return false; + + if (iter != end) + return false; + + return true; +} + +void tst_QArrayData::setSharable_data() +{ + QTest::addColumn >("array"); + QTest::addColumn("size"); + QTest::addColumn("capacity"); + QTest::addColumn("isCapacityReserved"); + QTest::addColumn("fillValue"); + + QArrayDataPointer null; + QArrayDataPointer empty; empty.clear(); + + static QStaticArrayData staticArrayData = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), + { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 } + }; + + QArrayDataPointer emptyReserved(QTypedArrayData::allocate(5, true, true)); + QArrayDataPointer nonEmpty(QTypedArrayData::allocate(10, false, true)); + QArrayDataPointer nonEmptyReserved(QTypedArrayData::allocate(15, true, true)); + QArrayDataPointer staticArray(static_cast *>(&staticArrayData.header)); + + nonEmpty->copyAppend(5, 1); + nonEmptyReserved->copyAppend(7, 2); + + QTest::newRow("shared-null") << null << size_t(0) << size_t(0) << false << 0; + QTest::newRow("shared-empty") << empty << size_t(0) << size_t(0) << false << 0; + // unsharable-empty implicitly tested in shared-empty + QTest::newRow("empty-reserved") << emptyReserved << size_t(0) << size_t(5) << true << 0; + QTest::newRow("non-empty") << nonEmpty << size_t(5) << size_t(10) << false << 1; + QTest::newRow("non-empty-reserved") << nonEmptyReserved << size_t(7) << size_t(15) << true << 2; + QTest::newRow("static-array") << staticArray << size_t(10) << size_t(0) << false << 3; +} + +void tst_QArrayData::setSharable() +{ + QFETCH(QArrayDataPointer, array); + QFETCH(size_t, size); + QFETCH(size_t, capacity); + QFETCH(bool, isCapacityReserved); + QFETCH(int, fillValue); + + QVERIFY(array->ref.isShared()); // QTest has a copy + QVERIFY(array->ref.isSharable()); + + QCOMPARE(size_t(array->size), size); + QCOMPARE(size_t(array->alloc), capacity); + QCOMPARE(bool(array->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + // shared-null becomes shared-empty, may otherwise detach + array.setSharable(true); + + QVERIFY(array->ref.isSharable()); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + { + QArrayDataPointer copy(array); + QVERIFY(array->ref.isShared()); + QVERIFY(array->ref.isSharable()); + QCOMPARE(copy.data(), array.data()); + } + + // Unshare, must detach + array.setSharable(false); + + // Immutability (alloc == 0) is lost on detach + if (capacity == 0 && size != 0) + capacity = size; + + QVERIFY(!array->ref.isShared()); + QVERIFY(!array->ref.isSharable()); + + QCOMPARE(size_t(array->size), size); + QCOMPARE(size_t(array->alloc), capacity); + QCOMPARE(bool(array->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + { + QArrayDataPointer copy(array); + QVERIFY(!array->ref.isShared()); + QVERIFY(!array->ref.isSharable()); + + // Null/empty is always shared + QCOMPARE(copy->ref.isShared(), !(size || isCapacityReserved)); + QVERIFY(copy->ref.isSharable()); + + QCOMPARE(size_t(copy->size), size); + QCOMPARE(size_t(copy->alloc), capacity); + QCOMPARE(bool(copy->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(copy, fillValue, size)); + } + + // Make sharable, again + array.setSharable(true); + + QCOMPARE(array->ref.isShared(), !(size || isCapacityReserved)); + QVERIFY(array->ref.isSharable()); + + QCOMPARE(size_t(array->size), size); + QCOMPARE(size_t(array->alloc), capacity); + QCOMPARE(bool(array->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + { + QArrayDataPointer copy(array); + QVERIFY(array->ref.isShared()); + QCOMPARE(copy.data(), array.data()); + } + + QCOMPARE(array->ref.isShared(), !(size || isCapacityReserved)); + QVERIFY(array->ref.isSharable()); +} + QTEST_APPLESS_MAIN(tst_QArrayData) #include "tst_qarraydata.moc" -- cgit v1.2.3