diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2012-06-11 21:26:23 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2019-12-08 10:29:17 +0100 |
commit | 812a611dc05e5facd036856625ccb9274fdcb117 (patch) | |
tree | 06151f35165e3b2ae614d21be65e4555e19f45e7 /src | |
parent | 62c673ccc6f81cee09a25f5acceec2768cea4672 (diff) |
Stop using the reference counter to store data state
Instead of using the reference count to store whether the data is
sharable and whether the header is immutable, move the settings to the
flags member. This allows us to save one comparison per deref() or
needsDetach(). It also allows for the possibility of mutable data
pointed to by a static header.
Change-Id: Ie678a2ff2bb9bce73497cb6138b431c465b0f3bb
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/text/qstring.cpp | 2 | ||||
-rw-r--r-- | src/corelib/text/qstringliteral.h | 2 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.cpp | 13 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.h | 27 | ||||
-rw-r--r-- | src/corelib/tools/qarraydataops.h | 4 | ||||
-rw-r--r-- | src/corelib/tools/qvector.h | 2 |
6 files changed, 29 insertions, 21 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 3e9deba29a..4d3f2016ac 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -2677,7 +2677,7 @@ QString &QString::append(const QString &str) QString &QString::append(const QChar *str, int len) { if (str && len > 0) { - if (d->isShared() || uint(d->size + len) + 1u > d->allocatedCapacity()) + if (d->needsDetach() || uint(d->size + len) + 1u > d->allocatedCapacity()) reallocData(uint(d->size + len) + 1u, true); memcpy(d->data() + d->size, str, len * sizeof(QChar)); d->size += len; diff --git a/src/corelib/text/qstringliteral.h b/src/corelib/text/qstringliteral.h index 7b4d2d04f5..a0d4ddc30b 100644 --- a/src/corelib/text/qstringliteral.h +++ b/src/corelib/text/qstringliteral.h @@ -75,7 +75,7 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2, /**/ #define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ - { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, size, 0, offset } \ + { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, size, 0, offset } \ /**/ #define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \ diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index fdd441c7de..aa7fac15ef 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -153,11 +153,11 @@ QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers") const QArrayData QArrayData::shared_null[2] = { - { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, 0, 0, sizeof(QArrayData) }, // shared null + { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0, 0, sizeof(QArrayData) }, // shared null /* zero initialized terminator */}; static const QArrayData emptyNotNullShared[2] = { - { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, 0, 0, sizeof(QArrayData) }, // shared empty + { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0, 0, sizeof(QArrayData) }, // shared empty /* zero initialized terminator */}; QT_WARNING_POP @@ -183,7 +183,7 @@ static QArrayData *allocateData(size_t allocSize, uint options) { QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); if (header) { - header->ref_.atomic.storeRelaxed(1); + header->ref_.storeRelaxed(1); header->flags = options; header->size = 0; } @@ -222,7 +222,8 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, return nullptr; size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); - options |= AllocatedDataType | Mutable; + options |= AllocatedDataType | MutableData; + options &= ~ImmutableHeader; QArrayData *header = allocateData(allocSize, options); if (header) { quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) @@ -249,10 +250,10 @@ QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, Q_ASSERT(data->isMutable()); Q_ASSERT(!data->isShared()); - options |= ArrayOption(AllocatedDataType); size_t headerSize = sizeof(QArrayData); size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); - options |= AllocatedDataType | Mutable; + options |= AllocatedDataType | MutableData; + options &= ~ImmutableHeader; QArrayData *header = reallocateData(data, allocSize, options); if (header) header->alloc = capacity; diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 183cf9f002..56d61340f0 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -56,18 +56,19 @@ struct Q_CORE_EXPORT QArrayData 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() - Mutable = 0x0080, //!< the data can be changed; doesn't say anything about the header + MutableData = 0x0080, //!< the data can be changed; doesn't say anything about the header + ImmutableHeader = 0x0100, //!< the header is static, it can't be changed /// this option is used by the Q_ARRAY_LITERAL and similar macros - StaticDataFlags = RawDataType, + StaticDataFlags = RawDataType | ImmutableHeader, /// this option is used by the allocate() function - DefaultAllocationFlags = 0, + DefaultAllocationFlags = MutableData, /// this option is used by the prepareRawData() function DefaultRawFlags = 0 }; Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) - QtPrivate::RefCount ref_; + QBasicAtomicInt ref_; uint flags; int size; uint alloc; @@ -84,13 +85,19 @@ struct Q_CORE_EXPORT QArrayData return alloc; } + /// Returns true if sharing took place bool ref() { - return ref_.ref(); + if (!isStatic()) + ref_.ref(); + return true; } + /// Returns false if deallocation is necessary bool deref() { + if (isStatic()) + return true; return ref_.deref(); } @@ -113,17 +120,17 @@ struct Q_CORE_EXPORT QArrayData // follow COW principles. bool isMutable() const { - return flags & Mutable; + return flags & MutableData; } bool isStatic() const { - return ref_.isStatic(); + return flags & ImmutableHeader; } bool isShared() const { - return ref_.isShared(); + return ref_.loadRelaxed() != 1; } // Returns true if a detach is necessary before modifying the data @@ -131,7 +138,7 @@ struct Q_CORE_EXPORT QArrayData // detaching is necessary, you should be in a non-const function already bool needsDetach() { - // ### optimize me -- this currently requires 3 conditionals! + // requires two conditionals return !isMutable() || isShared(); } @@ -354,7 +361,7 @@ struct QArrayDataPointerRef }; #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ - { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, size, 0, offset } \ + { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, size, 0, offset } \ /**/ #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) \ diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 777f0d839f..11494a5f6f 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -106,7 +106,7 @@ struct QPodArrayOps void destroyAll() // Call from destructors, ONLY! { Q_ASSERT(this->isMutable()); - Q_ASSERT(this->ref_.atomic.loadRelaxed() == 0); + Q_ASSERT(this->ref_.loadRelaxed() == 0); // As this is to be called only from destructor, it doesn't need to be // exception safe; size not updated. @@ -204,7 +204,7 @@ struct QGenericArrayOps // As this is to be called only from destructor, it doesn't need to be // exception safe; size not updated. - Q_ASSERT(this->ref_.atomic.loadRelaxed() == 0); + Q_ASSERT(this->ref_.loadRelaxed() == 0); const T *const b = this->begin(); const T *i = this->end(); diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index d9512ee90e..bf422e72d4 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -701,7 +701,7 @@ void QVector<T>::removeLast() Q_ASSERT(!isEmpty()); Q_ASSERT(d->allocatedCapacity()); - if (d->isShared()) + if (d->needsDetach()) detach(); --d->size; if (QTypeInfo<T>::isComplex) |