diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2012-06-04 22:31:26 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2019-12-07 14:18:19 +0100 |
commit | f6a151024b03158bcf46dc86e346d4227f8ca9d4 (patch) | |
tree | 898bbc0be052034801a5269bdd291de09766bd95 /src/corelib/tools | |
parent | 8fb45ae5b8b8ad276aeb9bc9e40f351f47523087 (diff) |
Introduce flags to indicate the QArrayData type
These flags allow us to determine what type of data QArrayData is
carrying. There are currently only two supported types:
- raw data type: constructed via fromRawData or static data
- allocated data type: regular data done via heap allocation
The QArrayData object is usually allocated on the heap, unless its own
reference count is -1 (indicating static const QArrayData). Such
object should have a type of RawDataType, since we can't call free().
Add GrowsBackward for completeness as well as the StaticDataFlags
default for static data.
Change-Id: Icc915a468a2acf2eae91a94e82451f852d382c92
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/corelib/tools')
-rw-r--r-- | src/corelib/tools/qarraydata.cpp | 57 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.h | 42 |
2 files changed, 63 insertions, 36 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index ce6f138497..bc48619349 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -153,17 +153,17 @@ QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers") const QArrayData QArrayData::shared_null[2] = { - { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared null + { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, 0, 0, sizeof(QArrayData) }, // shared null /* zero initialized terminator */}; -static const QArrayData qt_array[3] = { - { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, sizeof(QArrayData) }, // shared empty - { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, sizeof(QArrayData) }, // unsharable empty +static const QArrayData emptyNotNullShared[2] = { + { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, 0, 0, sizeof(QArrayData) }, // shared empty /* zero initialized terminator */}; QT_WARNING_POP -static const QArrayData &qt_array_empty = qt_array[0]; +static const QArrayData &qt_array_empty = emptyNotNullShared[0]; + static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize, uint options) { @@ -179,6 +179,17 @@ static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, siz } } +static QArrayData *allocateData(size_t allocSize, uint options) +{ + QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); + if (header) { + header->ref.atomic.storeRelaxed(1); + header->flags = options; + header->size = 0; + } + return header; +} + static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options) { header = static_cast<QArrayData *>(::realloc(header, allocSize)); @@ -194,38 +205,43 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, Q_ASSERT(alignment >= alignof(QArrayData) && !(alignment & (alignment - 1))); - // Don't allocate empty headers - if (!(options & RawData) && !capacity) + if (capacity == 0) + // optimization for empty headers return const_cast<QArrayData *>(&qt_array_empty); size_t headerSize = sizeof(QArrayData); - // Allocate extra (alignment - alignof(QArrayData)) padding bytes so we - // can properly align the data array. This assumes malloc is able to - // provide appropriate alignment for the header -- as it should! - // Padding is skipped when allocating a header for RawData. - if (!(options & RawData)) - headerSize += (alignment - alignof(QArrayData)); + if (alignment > alignof(QArrayData)) { + // Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we + // can properly align the data array. This assumes malloc is able to + // provide appropriate alignment for the header -- as it should! + headerSize += alignment - alignof(QArrayData); + } if (headerSize > size_t(MaxAllocSize)) return nullptr; size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); - QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); + options |= ArrayOption(AllocatedDataType); + QArrayData *header = allocateData(allocSize, options); if (header) { quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1); - - header->ref.atomic.storeRelaxed(1); - header->size = 0; - header->alloc = capacity; - header->flags = options; header->offset = data - quintptr(header); + header->alloc = capacity; } return header; } +QArrayData *QArrayData::prepareRawData(ArrayOptions options) Q_DECL_NOTHROW +{ + QArrayData *header = allocateData(sizeof(QArrayData), (options & ~DataTypeBits) | RawDataType); + if (header) + header->alloc = 0; + return header; +} + QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity, ArrayOptions options) noexcept { @@ -233,9 +249,10 @@ QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, Q_ASSERT(data->isMutable()); Q_ASSERT(!data->ref.isShared()); + options |= ArrayOption(AllocatedDataType); size_t headerSize = sizeof(QArrayData); size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); - QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options)); + QArrayData *header = reallocateData(data, allocSize, options); if (header) header->alloc = capacity; return header; diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index feee557131..babccc6017 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -48,6 +48,24 @@ QT_BEGIN_NAMESPACE struct Q_CORE_EXPORT QArrayData { + enum ArrayOption { + RawDataType = 0x0001, //!< this class is really a QArrayData + AllocatedDataType = 0x0002, //!< this class is really a QArrayAllocatedData + DataTypeBits = 0x000f, + + CapacityReserved = 0x0010, //!< the capacity was reserved by the user, try to keep it + GrowsForward = 0x0020, //!< allocate with eyes towards growing through append() + GrowsBackwards = 0x0040, //!< allocate with eyes towards growing through prepend() + + /// this option is used by the Q_ARRAY_LITERAL and similar macros + StaticDataFlags = RawDataType, + /// this option is used by the allocate() function + DefaultAllocationFlags = 0, + /// this option is used by the prepareRawData() function + DefaultRawFlags = 0 + }; + Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) + QtPrivate::RefCount ref; uint flags; int size; @@ -84,20 +102,9 @@ struct Q_CORE_EXPORT QArrayData // follow COW principles. bool isMutable() const { - return alloc != 0; + return flags & AllocatedDataType; } - enum ArrayOption { - CapacityReserved = 0x1, - RawData = 0x4, - GrowsForward = 0x8, - - DefaultAllocationFlags = 0, - DefaultRawFlags = 0 - }; - - Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) - size_t detachCapacity(size_t newSize) const { if (flags & CapacityReserved && newSize < constAllocatedCapacity()) @@ -107,7 +114,7 @@ struct Q_CORE_EXPORT QArrayData ArrayOptions detachFlags() const { - ArrayOptions result; + ArrayOptions result = DefaultAllocationFlags; if (flags & CapacityReserved) result |= CapacityReserved; return result; @@ -115,7 +122,7 @@ struct Q_CORE_EXPORT QArrayData ArrayOptions cloneFlags() const { - ArrayOptions result; + ArrayOptions result = DefaultAllocationFlags; if (flags & CapacityReserved) result |= CapacityReserved; return result; @@ -129,6 +136,8 @@ struct Q_CORE_EXPORT QArrayData size_t capacity, ArrayOptions options = DefaultAllocationFlags) noexcept; Q_REQUIRED_RESULT static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize, size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept; + Q_REQUIRED_RESULT static QArrayData *prepareRawData(ArrayOptions options = ArrayOptions(RawDataType)) + Q_DECL_NOTHROW; static void deallocate(QArrayData *data, size_t objectSize, size_t alignment) noexcept; @@ -269,7 +278,7 @@ struct QTypedArrayData ArrayOptions options = DefaultRawFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - QTypedArrayData *result = allocate(0, options | RawData); + QTypedArrayData *result = static_cast<QTypedArrayData *>(prepareRawData(options)); if (result) { Q_ASSERT(!result->ref.isShared()); // No shared empty, please! @@ -302,6 +311,7 @@ struct QTypedArrayData template <class T, size_t N> struct QStaticArrayData { + // static arrays are of type RawDataType QArrayData header; T data[N]; }; @@ -314,7 +324,7 @@ struct QArrayDataPointerRef }; #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ - { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::DefaultAllocationFlags, size, 0, offset } \ + { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, size, 0, offset } \ /**/ #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) \ |