summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2012-06-04 22:31:26 +0200
committerLars Knoll <lars.knoll@qt.io>2019-12-07 14:18:19 +0100
commitf6a151024b03158bcf46dc86e346d4227f8ca9d4 (patch)
tree898bbc0be052034801a5269bdd291de09766bd95 /src/corelib/tools
parent8fb45ae5b8b8ad276aeb9bc9e40f351f47523087 (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.cpp57
-rw-r--r--src/corelib/tools/qarraydata.h42
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) \