From f1e48d48fd58b28b1dc18652af3fc74da5e112fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Tue, 22 Nov 2011 17:28:14 +0100 Subject: Add AllocateOptions to QArrayData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This approach is better for future ABI evolution than using individual bool parameters. QArrayData now also offers to calculate allocate options for typical detach and clone operations: the CapacityReserved flag is preserved, while cloning resets the Unsharable state. Change-Id: I256e135adcf27a52a5c7d6130069c35c8b946bc3 Reviewed-by: João Abecasis --- src/corelib/tools/qarraydata.cpp | 8 ++--- src/corelib/tools/qarraydata.h | 37 ++++++++++++++++--- src/corelib/tools/qarraydatapointer.h | 12 ++++--- tests/auto/corelib/tools/qarraydata/simplevector.h | 12 ++++--- .../corelib/tools/qarraydata/tst_qarraydata.cpp | 42 +++++++++++++--------- 5 files changed, 78 insertions(+), 33 deletions(-) diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 150f23cc12..efed984aef 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -49,7 +49,7 @@ static const QArrayData qt_array_empty = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0 static const QArrayData qt_array_unsharable_empty = { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, 0 }; QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, - size_t capacity, bool reserve, bool sharable) + size_t capacity, AllocateOptions options) { // Alignment is a power of two Q_ASSERT(alignment >= Q_ALIGNOF(QArrayData) @@ -57,7 +57,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, // Don't allocate empty headers if (!capacity) - return sharable + return !(options & Unsharable) ? const_cast(&qt_array_empty) : const_cast(&qt_array_unsharable_empty); @@ -73,10 +73,10 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1); - header->ref.atomic.store(sharable ? 1 : 0); + header->ref.atomic.store(bool(!(options & Unsharable))); header->size = 0; header->alloc = capacity; - header->capacityReserved = reserve; + header->capacityReserved = bool(options & CapacityReserved); header->offset = data - quintptr(header); } diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 2486bebafa..8eb543ee51 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -73,14 +73,43 @@ struct Q_CORE_EXPORT QArrayData return reinterpret_cast(this) + offset; } + enum AllocateOption { + CapacityReserved = 0x1, + Unsharable = 0x2, + + Default = 0 + }; + + Q_DECLARE_FLAGS(AllocateOptions, AllocateOption) + + AllocateOptions detachFlags() const + { + AllocateOptions result; + if (!ref.isSharable()) + result |= Unsharable; + if (capacityReserved) + result |= CapacityReserved; + return result; + } + + AllocateOptions cloneFlags() const + { + AllocateOptions result; + if (capacityReserved) + result |= CapacityReserved; + return result; + } + static QArrayData *allocate(size_t objectSize, size_t alignment, - size_t capacity, bool reserve, bool sharable) Q_REQUIRED_RESULT; + size_t capacity, AllocateOptions options = Default) Q_REQUIRED_RESULT; static void deallocate(QArrayData *data, size_t objectSize, size_t alignment); static const QArrayData shared_null; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocateOptions) + template struct QTypedArrayData : QArrayData @@ -98,11 +127,11 @@ struct QTypedArrayData class AlignmentDummy { QArrayData header; T data; }; - static QTypedArrayData *allocate(size_t capacity, bool reserve = false, - bool sharable = true) Q_REQUIRED_RESULT + static QTypedArrayData *allocate(size_t capacity, + AllocateOptions options = Default) Q_REQUIRED_RESULT { return static_cast(QArrayData::allocate(sizeof(T), - Q_ALIGNOF(AlignmentDummy), capacity, reserve, sharable)); + Q_ALIGNOF(AlignmentDummy), capacity, options)); } static void deallocate(QArrayData *data) diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index c03e2ef849..1dc02daa63 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -66,7 +66,7 @@ public: QArrayDataPointer(const QArrayDataPointer &other) : d(other.d->ref.ref() ? other.d - : other.clone()) + : other.clone(other.d->cloneFlags())) { } @@ -115,7 +115,9 @@ public: void setSharable(bool sharable) { if (d->alloc == 0 && d->size == 0) { - d = Data::allocate(0, false, sharable); + d = Data::allocate(0, sharable + ? QArrayData::Default + : QArrayData::Unsharable); return; } @@ -137,7 +139,7 @@ public: bool detach() { if (d->ref.isShared()) { - Data *copy = clone(); + Data *copy = clone(d->detachFlags()); QArrayDataPointer old(d); d = copy; return true; @@ -147,10 +149,10 @@ public: } private: - Data *clone() const Q_REQUIRED_RESULT + Data *clone(QArrayData::AllocateOptions options) const Q_REQUIRED_RESULT { QArrayDataPointer copy(Data::allocate(d->alloc ? d->alloc : d->size, - d->capacityReserved)); + options)); if (d->size) copy->copyAppend(d->begin(), d->end()); diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index 9ab28a9ddd..4f02df1c40 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -140,7 +140,8 @@ public: || (n && !d->capacityReserved && (d->ref != 1 || (d->capacityReserved = 1, false)))) { - SimpleVector detached(Data::allocate(n, true)); + SimpleVector detached(Data::allocate(n, + d->detachFlags() | Data::CapacityReserved)); detached.d->copyAppend(constBegin(), constEnd()); detached.swap(*this); } @@ -160,7 +161,8 @@ public: if (d->ref != 1 || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( - qMax(capacity(), size() + (last - first)), d->capacityReserved)); + qMax(capacity(), size() + (last - first)), + d->detachFlags())); detached.d->copyAppend(first, last); detached.d->copyAppend(begin, begin + d->size); @@ -180,7 +182,8 @@ public: if (d->ref != 1 || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( - qMax(capacity(), size() + (last - first)), d->capacityReserved)); + qMax(capacity(), size() + (last - first)), + d->detachFlags())); if (d->size) { const T *const begin = constBegin(); @@ -219,7 +222,8 @@ public: if (d->ref != 1 || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( - qMax(capacity(), size() + (last - first)), d->capacityReserved)); + qMax(capacity(), size() + (last - first)), + d->detachFlags())); if (position) detached.d->copyAppend(begin, where); diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 47d5e2a32b..2df4131f4a 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -153,7 +153,7 @@ void tst_QArrayData::referenceCounting() void tst_QArrayData::sharedNullEmpty() { QArrayData *null = const_cast(&QArrayData::shared_null); - QArrayData *empty = QArrayData::allocate(1, Q_ALIGNOF(QArrayData), 0, false, true); + QArrayData *empty = QArrayData::allocate(1, Q_ALIGNOF(QArrayData), 0); QVERIFY(null->ref.isStatic()); QVERIFY(null->ref.isSharable()); @@ -473,11 +473,13 @@ struct Deallocator }; Q_DECLARE_METATYPE(const QArrayData *) +Q_DECLARE_METATYPE(QArrayData::AllocateOptions) void tst_QArrayData::allocate_data() { QTest::addColumn("objectSize"); QTest::addColumn("alignment"); + QTest::addColumn("allocateOptions"); QTest::addColumn("isCapacityReserved"); QTest::addColumn("isSharable"); QTest::addColumn("commonEmpty"); @@ -492,22 +494,25 @@ void tst_QArrayData::allocate_data() { "void *", sizeof(void *), Q_ALIGNOF(void *) } }; - QArrayData *shared_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0, false, true); - QArrayData *unsharable_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0, false, false); + QArrayData *shared_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0); + QArrayData *unsharable_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0, QArrayData::Unsharable); QVERIFY(shared_empty); QVERIFY(unsharable_empty); struct { char const *description; + QArrayData::AllocateOptions allocateOptions; bool isCapacityReserved; bool isSharable; const QArrayData *commonEmpty; } options[] = { - { "Default", false, true, shared_empty }, - { "Reserved", true, true, shared_empty }, - { "Reserved | Unsharable", true, false, unsharable_empty }, - { "Unsharable", false, false, unsharable_empty }, + { "Default", QArrayData::Default, false, true, shared_empty }, + { "Reserved", QArrayData::CapacityReserved, true, true, shared_empty }, + { "Reserved | Unsharable", + QArrayData::CapacityReserved | QArrayData::Unsharable, true, false, + unsharable_empty }, + { "Unsharable", QArrayData::Unsharable, false, false, unsharable_empty }, }; for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i) @@ -517,14 +522,15 @@ void tst_QArrayData::allocate_data() + QLatin1String(": ") + QLatin1String(options[j].description))) << types[i].objectSize << types[i].alignment - << options[j].isCapacityReserved << options[j].isSharable - << options[j].commonEmpty; + << options[j].allocateOptions << options[j].isCapacityReserved + << options[j].isSharable << options[j].commonEmpty; } void tst_QArrayData::allocate() { QFETCH(size_t, objectSize); QFETCH(size_t, alignment); + QFETCH(QArrayData::AllocateOptions, allocateOptions); QFETCH(bool, isCapacityReserved); QFETCH(bool, isSharable); QFETCH(const QArrayData *, commonEmpty); @@ -535,14 +541,14 @@ void tst_QArrayData::allocate() // Shared Empty QCOMPARE(QArrayData::allocate(objectSize, minAlignment, 0, - isCapacityReserved, isSharable), commonEmpty); + QArrayData::AllocateOptions(allocateOptions)), 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, isSharable); + capacity, QArrayData::AllocateOptions(allocateOptions)); keeper.headers.append(data); QCOMPARE(data->size, 0); @@ -584,7 +590,7 @@ void tst_QArrayData::alignment() for (int i = 0; i < 100; ++i) { QArrayData *data = QArrayData::allocate(sizeof(Unaligned), - minAlignment, 8, false, true); + minAlignment, 8, QArrayData::Default); keeper.headers.append(data); QVERIFY(data); @@ -952,10 +958,14 @@ void tst_QArrayData::setSharable_data() { 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)); + QArrayDataPointer emptyReserved(QTypedArrayData::allocate(5, + QArrayData::CapacityReserved)); + QArrayDataPointer nonEmpty(QTypedArrayData::allocate(10, + QArrayData::Default)); + QArrayDataPointer nonEmptyReserved(QTypedArrayData::allocate(15, + QArrayData::CapacityReserved)); + QArrayDataPointer staticArray( + static_cast *>(&staticArrayData.header)); nonEmpty->copyAppend(5, 1); nonEmptyReserved->copyAppend(7, 2); -- cgit v1.2.3