diff options
-rw-r--r-- | src/corelib/text/qbytearray.cpp | 24 | ||||
-rw-r--r-- | src/corelib/text/qbytearray.h | 8 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 18 | ||||
-rw-r--r-- | src/corelib/text/qstring.h | 10 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.cpp | 3 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.h | 12 | ||||
-rw-r--r-- | src/corelib/tools/qarraydatapointer.h | 7 | ||||
-rw-r--r-- | src/corelib/tools/qvector.h | 3 | ||||
-rw-r--r-- | tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp | 2 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/simplevector.h | 10 |
10 files changed, 54 insertions, 43 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index d7fcfce90c..da91a93700 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -63,7 +63,7 @@ #include <string.h> #include <stdlib.h> -#define IS_RAW_DATA(d) (!(d)->isMutable()) +#define IS_RAW_DATA(d) ((d)->flags & QArrayData::RawDataType) QT_BEGIN_NAMESPACE @@ -1208,7 +1208,7 @@ QByteArray &QByteArray::operator=(const char *str) } else { const int len = int(strlen(str)); const int fullLen = len + 1; - if (d->ref.isShared() || fullLen > int(d->allocatedCapacity()) + if (d->needsDetach() || fullLen > int(d->allocatedCapacity()) || (len < d->size && fullLen < int(d->allocatedCapacity() >> 1))) reallocData(fullLen, d->detachFlags()); x = d; @@ -1755,7 +1755,7 @@ void QByteArray::resize(int size) if (size < 0) size = 0; - if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) { + if (!d->ref.isShared() && !d->isMutable() && size < d->size) { d->size = size; return; } @@ -1775,9 +1775,9 @@ void QByteArray::resize(int size) x->data()[size] = '\0'; d = x; } else { - if (d->ref.isShared() || size > capacity()) + if (d->needsDetach() || size > capacity()) reallocData(uint(size) + 1u, d->detachFlags() | Data::GrowsForward); - if (d->allocatedCapacity()) { + if (d->isMutable()) { d->size = size; d->data()[size] = '\0'; } @@ -1805,7 +1805,7 @@ QByteArray &QByteArray::fill(char ch, int size) void QByteArray::reallocData(uint alloc, Data::ArrayOptions options) { - if (d->ref.isShared() || IS_RAW_DATA(d)) { + if (d->needsDetach()) { Data *x = Data::allocate(alloc, options); Q_CHECK_PTR(x); x->size = qMin(int(alloc) - 1, d->size); @@ -1900,7 +1900,7 @@ QByteArray &QByteArray::prepend(const char *str) QByteArray &QByteArray::prepend(const char *str, int len) { if (str) { - if (d->ref.isShared() || d->size + len > capacity()) + if (d->needsDetach() || d->size + len > capacity()) reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::GrowsForward); memmove(d->data()+len, d->data(), d->size); memcpy(d->data(), str, len); @@ -1926,7 +1926,7 @@ QByteArray &QByteArray::prepend(const char *str, int len) QByteArray &QByteArray::prepend(char ch) { - if (d->ref.isShared() || d->size + 1 > capacity()) + if (d->needsDetach() || d->size + 1 > capacity()) reallocData(uint(d->size) + 2u, d->detachFlags() | Data::GrowsForward); memmove(d->data()+1, d->data(), d->size); d->data()[0] = ch; @@ -1964,7 +1964,7 @@ QByteArray &QByteArray::append(const QByteArray &ba) if (d->size == 0 && d->ref.isStatic() && !IS_RAW_DATA(ba.d)) { *this = ba; } else if (ba.d->size != 0) { - if (d->ref.isShared() || d->size + ba.d->size > capacity()) + if (d->needsDetach() || d->size + ba.d->size > capacity()) reallocData(uint(d->size + ba.d->size) + 1u, d->detachFlags() | Data::GrowsForward); memcpy(d->data() + d->size, ba.d->data(), ba.d->size); d->size += ba.d->size; @@ -1996,7 +1996,7 @@ QByteArray& QByteArray::append(const char *str) { if (str) { const int len = int(strlen(str)); - if (d->ref.isShared() || d->size + len > capacity()) + if (d->needsDetach() || d->size + len > capacity()) reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::GrowsForward); memcpy(d->data() + d->size, str, len + 1); // include null terminator d->size += len; @@ -2021,7 +2021,7 @@ QByteArray &QByteArray::append(const char *str, int len) if (len < 0) len = qstrlen(str); if (str && len) { - if (d->ref.isShared() || d->size + len > capacity()) + if (d->needsDetach() || d->size + len > capacity()) reallocData(uint(d->size + len) + 1u, d->detachFlags() | Data::GrowsForward); memcpy(d->data() + d->size, str, len); // include null terminator d->size += len; @@ -2049,7 +2049,7 @@ QByteArray &QByteArray::append(const char *str, int len) QByteArray& QByteArray::append(char ch) { - if (d->ref.isShared() || d->size + 1 > capacity()) + if (d->needsDetach() || d->size + 1 > capacity()) reallocData(uint(d->size) + 2u, d->detachFlags() | Data::GrowsForward); d->data()[d->size++] = ch; d->data()[d->size] = '\0'; diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index 611cacc646..597bc8bcb3 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -495,7 +495,7 @@ inline const char *QByteArray::data() const inline const char *QByteArray::constData() const { return d->data(); } inline void QByteArray::detach() -{ if (d->ref.isShared() || !d->isMutable()) reallocData(uint(d->size) + 1u, d->detachFlags()); } +{ if (d->needsDetach()) reallocData(uint(d->size) + 1u, d->detachFlags()); } inline bool QByteArray::isDetached() const { return !d->ref.isShared(); } inline QByteArray::QByteArray(const QByteArray &a) noexcept : d(a.d) @@ -506,7 +506,7 @@ inline int QByteArray::capacity() const inline void QByteArray::reserve(int asize) { - if (d->ref.isShared() || asize > capacity()) { + if (d->needsDetach() || asize > capacity()) { reallocData(qMax(uint(size()), uint(asize)) + 1u, d->detachFlags() | Data::CapacityReserved); } else { d->flags |= Data::CapacityReserved; @@ -515,7 +515,9 @@ inline void QByteArray::reserve(int asize) inline void QByteArray::squeeze() { - if (d->ref.isShared() || d->size < capacity()) { + if ((d->flags & Data::CapacityReserved) == 0) + return; + if (d->needsDetach() || d->size < capacity()) { reallocData(uint(d->size) + 1u, d->detachFlags() & ~Data::CapacityReserved); } else { d->flags &= ~Data::CapacityReserved; diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index d0f141e079..ab08d497bd 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -100,7 +100,7 @@ #define ULLONG_MAX quint64_C(18446744073709551615) #endif -#define IS_RAW_DATA(d) (!(d)->isMutable()) +#define IS_RAW_DATA(d) ((d)->flags & QArrayData::RawDataType) QT_BEGIN_NAMESPACE @@ -2265,14 +2265,14 @@ void QString::resize(int size) if (size < 0) size = 0; - if (IS_RAW_DATA(d) && !d->ref.isShared() && size < d->size) { + if (!d->ref.isShared() && !d->isMutable() && size < d->size) { d->size = size; return; } - if (d->ref.isShared() || uint(size) + 1u > d->allocatedCapacity()) + if (d->needsDetach() || size > capacity()) reallocData(uint(size) + 1u, true); - if (d->flags & Data::AllocatedDataType) { + if (d->isMutable()) { d->size = size; d->data()[size] = '\0'; } @@ -2353,7 +2353,7 @@ void QString::reallocData(uint alloc, bool grow) if (grow) allocOptions |= QArrayData::GrowsForward; - if (d->ref.isShared() || IS_RAW_DATA(d)) { + if (d->needsDetach()) { Data *x = Data::allocate(alloc, allocOptions); Q_CHECK_PTR(x); x->size = qMin(int(alloc) - 1, d->size); @@ -2658,7 +2658,7 @@ QString &QString::append(const QString &str) if (d == Data::sharedNull()) { operator=(str); } else { - if (d->ref.isShared() || d->size + str.d->size > capacity()) + if (d->needsDetach() || d->size + str.d->size > capacity()) reallocData(uint(d->size + str.d->size) + 1u, true); memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); d->size += str.d->size; @@ -2696,7 +2696,7 @@ QString &QString::append(QLatin1String str) const char *s = str.latin1(); if (s) { int len = str.size(); - if (d->ref.isShared() || d->size + len > capacity()) + if (d->needsDetach() || d->size + len > capacity()) reallocData(uint(d->size + len) + 1u, true); ushort *i = d->data() + d->size; qt_from_latin1(i, s, uint(len)); @@ -2743,7 +2743,7 @@ QString &QString::append(QLatin1String str) */ QString &QString::append(QChar ch) { - if (d->ref.isShared() || d->size + 1 > capacity()) + if (d->needsDetach() || d->size + 1 > capacity()) reallocData(uint(d->size) + 2u, true); d->data()[d->size++] = ch.unicode(); d->data()[d->size] = '\0'; @@ -6457,7 +6457,7 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1, const ushort *QString::utf16() const { - if (IS_RAW_DATA(d)) { + if (!d->isMutable()) { // ensure '\0'-termination for ::fromRawData strings const_cast<QString*>(this)->reallocData(uint(d->size) + 1u); } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 03d83eeab9..fd674284fe 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -542,7 +542,7 @@ public: inline QString &prepend(QLatin1String s) { return insert(0, s); } inline QString &operator+=(QChar c) { - if (d->ref.isShared() || d->size + 1 > capacity()) + if (d->needsDetach() || d->size + 1 > capacity()) reallocData(uint(d->size) + 2u, true); d->data()[d->size++] = c.unicode(); d->data()[d->size] = '\0'; @@ -1041,7 +1041,7 @@ inline QChar *QString::data() inline const QChar *QString::constData() const { return reinterpret_cast<const QChar*>(d->data()); } inline void QString::detach() -{ if (d->ref.isShared() || !d->isMutable()) reallocData(uint(d->size) + 1u); } +{ if (d->needsDetach()) reallocData(uint(d->size) + 1u); } inline bool QString::isDetached() const { return !d->ref.isShared(); } inline void QString::clear() @@ -1263,7 +1263,7 @@ inline QString::~QString() { if (!d->ref.deref()) Data::deallocate(d); } inline void QString::reserve(int asize) { - if (d->ref.isShared() || asize >= capacity()) + if (d->needsDetach() || asize >= capacity()) reallocData(qMax(asize, size()) + 1u); // we're not shared anymore, for sure @@ -1272,7 +1272,9 @@ inline void QString::reserve(int asize) inline void QString::squeeze() { - if (d->ref.isShared() || d->size < capacity()) + if ((d->flags & Data::CapacityReserved) == 0) + return; + if (d->needsDetach() || d->size < capacity()) reallocData(uint(d->size) + 1u); // we're not shared anymore, for sure diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index bc48619349..3123d7467f 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -222,7 +222,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, return nullptr; size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); - options |= ArrayOption(AllocatedDataType); + options |= AllocatedDataType | Mutable; QArrayData *header = allocateData(allocSize, options); if (header) { quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) @@ -252,6 +252,7 @@ QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, options |= ArrayOption(AllocatedDataType); size_t headerSize = sizeof(QArrayData); size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); + options |= AllocatedDataType | Mutable; 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 babccc6017..8c21fd55c8 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -56,6 +56,7 @@ 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 /// this option is used by the Q_ARRAY_LITERAL and similar macros StaticDataFlags = RawDataType, @@ -102,7 +103,16 @@ struct Q_CORE_EXPORT QArrayData // follow COW principles. bool isMutable() const { - return flags & AllocatedDataType; + return flags & Mutable; + } + + // Returns true if a detach is necessary before modifying the data + // This method is intentionally not const: if you want to know whether + // detaching is necessary, you should be in a non-const function already + bool needsDetach() + { + // ### optimize me -- this currently requires 3 conditionals! + return !isMutable() || ref.isShared(); } size_t detachCapacity(size_t newSize) const diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index ffeaff5862..b7236d485a 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -126,11 +126,6 @@ public: return d; } - bool needsDetach() const - { - return (!d->isMutable() || d->ref.isShared()); - } - void swap(QArrayDataPointer &other) noexcept { qSwap(d, other.d); @@ -144,7 +139,7 @@ public: bool detach() { - if (needsDetach()) { + if (d->needsDetach()) { Data *copy = clone(d->detachFlags()); QArrayDataPointer old(d); d = copy; diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 9ef2ace471..a596beedcf 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -390,10 +390,11 @@ inline QVector<T>::QVector(const QVector<T> &v) template <typename T> void QVector<T>::detach() { + // ### check whether this is still required if (d->ref.isStatic()) return; - if (!isDetached()) + if (d->needsDetach()) realloc(d->allocatedCapacity(), d->detachFlags()); Q_ASSERT(isDetached()); } diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp index cc65662e26..f5748ea060 100644 --- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -2163,7 +2163,7 @@ void tst_QByteArray::movablity() const int newSize = size + 2; const bool newIsEmpty = false; const bool newIsNull = false; - const int newCapacity = 16; + const int newCapacity = memSpace.capacity(); // move back memSpace -> array array.~QByteArray(); diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index f3e3a1bb50..c9a77a6f42 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -159,7 +159,7 @@ public: if (size() == newSize) return; - if (d.needsDetach() || newSize > capacity()) { + if (d->needsDetach() || newSize > capacity()) { SimpleVector detached(Data::allocate( d->detachCapacity(newSize), d->detachFlags())); if (newSize) { @@ -195,7 +195,7 @@ public: return; T *const begin = d->begin(); - if (d.needsDetach() + if (d->needsDetach() || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( d->detachCapacity(size() + (last - first)), @@ -216,7 +216,7 @@ public: if (first == last) return; - if (d.needsDetach() + if (d->needsDetach() || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( d->detachCapacity(size() + (last - first)), @@ -256,7 +256,7 @@ public: const iterator begin = d->begin(); const iterator where = begin + position; const iterator end = begin + d->size; - if (d.needsDetach() + if (d->needsDetach() || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( d->detachCapacity(size() + (last - first)), @@ -294,7 +294,7 @@ public: const T *const begin = d->begin(); const T *const end = begin + d->size; - if (d.needsDetach()) { + if (d->needsDetach()) { SimpleVector detached(Data::allocate( d->detachCapacity(size() - (last - first)), d->detachFlags())); |