diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 1a1b2d86b0e..1b5fa8e5eb5 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -1175,7 +1175,8 @@ QByteArray &QByteArray::operator=(const char *str) const auto capacityAtEnd = d->allocatedCapacity() - d.freeSpaceAtBegin(); if (d->needsDetach() || len > capacityAtEnd || (len < size() && len < (capacityAtEnd >> 1))) - reallocData(len, d->detachFlags()); + // ### inefficient! reallocData() does copy the old data and we then overwrite it in the next line + reallocData(len, QArrayData::KeepSize); memcpy(d.data(), str, len + 1); // include null terminator d.size = len; } @@ -1676,7 +1677,7 @@ void QByteArray::resize(qsizetype size) const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin(); if (d->needsDetach() || size > capacityAtEnd) - reallocData(size, d->detachFlags() | Data::GrowsForward); + reallocData(size, QArrayData::Grow); d.size = size; if (d->allocatedCapacity()) d.data()[size] = 0; @@ -1700,7 +1701,7 @@ QByteArray &QByteArray::fill(char ch, qsizetype size) return *this; } -void QByteArray::reallocData(qsizetype alloc, Data::ArrayOptions options) +void QByteArray::reallocData(qsizetype alloc, QArrayData::AllocationOption option) { if (!alloc) { d = DataPointer::fromRawData(&_empty, 0); @@ -1713,13 +1714,13 @@ void QByteArray::reallocData(qsizetype alloc, Data::ArrayOptions options) const bool slowReallocatePath = d.freeSpaceAtBegin() > 0; if (d->needsDetach() || slowReallocatePath) { - DataPointer dd(Data::allocate(alloc, options), qMin(alloc, d.size)); + DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size)); if (dd.size > 0) ::memcpy(dd.data(), d.data(), dd.size); dd.data()[dd.size] = 0; d = dd; } else { - d->reallocate(alloc, options & (QArrayData::GrowsBackwards|QArrayData::GrowsForward) ? QArrayData::Grow : QArrayData::KeepSize); + d->reallocate(alloc, option); } } @@ -1729,7 +1730,7 @@ void QByteArray::reallocGrowData(qsizetype n) n = 1; if (d->needsDetach()) { - DataPointer dd(DataPointer::allocateGrow(d, n, DataPointer::AllocateAtEnd)); + DataPointer dd(DataPointer::allocateGrow(d, n, QArrayData::AllocateAtEnd)); dd->copyAppend(d.data(), d.data() + d.size); dd.data()[dd.size] = 0; d = dd; @@ -1936,9 +1937,9 @@ QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data) sizeToGrow += i - oldSize; if (d->needsDetach() || (sizeToGrow > d.freeSpaceAtBegin() && sizeToGrow > d.freeSpaceAtEnd())) { - DataPointer::AllocationPosition pos = DataPointer::AllocateAtEnd; + QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd; if (oldSize != 0 && i <= (oldSize >> 1)) - pos = DataPointer::AllocateAtBeginning; + pos = QArrayData::AllocateAtBeginning; DataPointer detached(DataPointer::allocateGrow(d, sizeToGrow, pos)); auto where = d.constBegin() + qMin(i, d->size); @@ -2000,9 +2001,9 @@ QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch) sizeToGrow += i - oldSize; if (d->needsDetach() || (sizeToGrow > d.freeSpaceAtBegin() && sizeToGrow > d.freeSpaceAtEnd())) { - DataPointer::AllocationPosition pos = DataPointer::AllocateAtEnd; + QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd; if (oldSize != 0 && i <= (oldSize >> 1)) - pos = DataPointer::AllocateAtBeginning; + pos = QArrayData::AllocateAtBeginning; DataPointer detached(DataPointer::allocateGrow(d, sizeToGrow, pos)); auto where = d.constBegin() + qMin(i, d->size); diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index c70a7a82d9b..95b607e9dc3 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -509,7 +509,7 @@ public: } private: - void reallocData(qsizetype alloc, Data::ArrayOptions options); + void reallocData(qsizetype alloc, QArrayData::AllocationOption option); void reallocGrowData(qsizetype n); void expand(qsizetype i); QByteArray nulTerminated() const; @@ -562,7 +562,7 @@ inline const char *QByteArray::data() const inline const char *QByteArray::constData() const { return data(); } inline void QByteArray::detach() -{ if (d->needsDetach()) reallocData(size(), d->detachFlags()); } +{ if (d->needsDetach()) reallocData(size(), QArrayData::KeepSize); } inline bool QByteArray::isDetached() const { return !d->isShared(); } inline QByteArray::QByteArray(const QByteArray &a) noexcept : d(a.d) @@ -572,22 +572,20 @@ inline qsizetype QByteArray::capacity() const { return qsizetype(d->constAllocat inline void QByteArray::reserve(qsizetype asize) { - if (d->needsDetach() || asize > capacity() - d->freeSpaceAtBegin()) { - reallocData(qMax(size(), asize), d->detachFlags() | Data::CapacityReserved); - } else { + if (d->needsDetach() || asize > capacity() - d->freeSpaceAtBegin()) + reallocData(qMax(size(), asize), QArrayData::KeepSize); + if (d->constAllocatedCapacity()) d->setFlag(Data::CapacityReserved); - } } inline void QByteArray::squeeze() { if (!d.isMutable()) return; - if (d->needsDetach() || size() < capacity()) { - reallocData(size(), d->detachFlags() & ~Data::CapacityReserved); - } else { + if (d->needsDetach() || size() < capacity()) + reallocData(size(), QArrayData::KeepSize); + if (d->constAllocatedCapacity()) d->clearFlag(Data::CapacityReserved); - } } inline char &QByteArray::operator[](qsizetype i) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index ebdb5710414..40d69c9d9c6 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -2415,7 +2415,7 @@ void QString::resize(qsizetype size) const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin(); if (d->needsDetach() || size > capacityAtEnd) - reallocData(size, d->detachFlags() | Data::GrowsForward); + reallocData(size, QArrayData::Grow); d.size = size; if (d->allocatedCapacity()) d.data()[size] = 0; @@ -2497,7 +2497,7 @@ void QString::resize(qsizetype size, QChar fillChar) \sa reserve(), capacity() */ -void QString::reallocData(qsizetype alloc, Data::ArrayOptions allocOptions) +void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option) { if (!alloc) { d = DataPointer::fromRawData(&_empty, 0); @@ -2510,13 +2510,13 @@ void QString::reallocData(qsizetype alloc, Data::ArrayOptions allocOptions) const bool slowReallocatePath = d.freeSpaceAtBegin() > 0; if (d->needsDetach() || slowReallocatePath) { - DataPointer dd(Data::allocate(alloc, allocOptions), qMin(alloc, d.size)); + DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size)); if (dd.size > 0) ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar)); dd.data()[dd.size] = 0; d = dd; } else { - d->reallocate(alloc, allocOptions & (QArrayData::GrowsBackwards|QArrayData::GrowsForward) ? QArrayData::Grow : QArrayData::KeepSize); + d->reallocate(alloc, option); } } @@ -2526,7 +2526,7 @@ void QString::reallocGrowData(qsizetype n) n = 1; if (d->needsDetach()) { - DataPointer dd(DataPointer::allocateGrow(d, n, DataPointer::AllocateAtEnd)); + DataPointer dd(DataPointer::allocateGrow(d, n, QArrayData::AllocateAtEnd)); dd->copyAppend(d.data(), d.data() + d.size); dd.data()[dd.size] = 0; d = dd; @@ -2737,9 +2737,9 @@ QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size) sizeToGrow += i - oldSize; if (d->needsDetach() || (sizeToGrow > d.freeSpaceAtBegin() && sizeToGrow > d.freeSpaceAtEnd())) { - DataPointer::AllocationPosition pos = DataPointer::AllocateAtEnd; + QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd; if (oldSize != 0 && i <= (oldSize >> 1)) - pos = DataPointer::AllocateAtBeginning; + pos = QArrayData::AllocateAtBeginning; DataPointer detached(DataPointer::allocateGrow(d, sizeToGrow, pos)); auto where = d.constBegin() + qMin(i, d->size); @@ -4054,7 +4054,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) if (!iterator.hasNext()) // no matches at all return *this; - reallocData(d.size, d->detachFlags()); + reallocData(d.size, QArrayData::KeepSize); qsizetype numCaptures = re.captureCount(); @@ -6157,7 +6157,7 @@ const ushort *QString::utf16() const { if (!d->isMutable()) { // ensure '\0'-termination for ::fromRawData strings - const_cast(this)->reallocData(d.size, d->detachFlags()); + const_cast(this)->reallocData(d.size, QArrayData::KeepSize); } return reinterpret_cast(d.data()); } diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 66a99d4e43a..013b367b5ce 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -1058,7 +1058,7 @@ private: DataPointer d; static const char16_t _empty; - void reallocData(qsizetype alloc, Data::ArrayOptions options); + void reallocData(qsizetype alloc, QArrayData::AllocationOption option); void reallocGrowData(qsizetype n); static int compare_helper(const QChar *data1, qsizetype length1, const QChar *data2, qsizetype length2, @@ -1195,7 +1195,7 @@ inline QChar *QString::data() inline const QChar *QString::constData() const { return data(); } inline void QString::detach() -{ if (d->needsDetach()) reallocData(d.size, d->detachFlags()); } +{ if (d->needsDetach()) reallocData(d.size, QArrayData::KeepSize); } inline bool QString::isDetached() const { return !d->isShared(); } inline void QString::clear() @@ -1267,22 +1267,20 @@ inline QString::~QString() {} inline void QString::reserve(qsizetype asize) { - if (d->needsDetach() || asize >= capacity() - d.freeSpaceAtBegin()) { - reallocData(qMax(asize, size()), d->detachFlags() | Data::CapacityReserved); - } else { + if (d->needsDetach() || asize >= capacity() - d.freeSpaceAtBegin()) + reallocData(qMax(asize, size()), QArrayData::KeepSize); + if (d->constAllocatedCapacity()) d->setFlag(Data::CapacityReserved); - } } inline void QString::squeeze() { if (!d.isMutable()) return; - if (d->needsDetach() || size() < capacity()) { - reallocData(d.size, d->detachFlags() & ~Data::CapacityReserved); - } else { + if (d->needsDetach() || size() < capacity()) + reallocData(d.size, QArrayData::KeepSize); + if (d->constAllocatedCapacity()) d->clearFlag(Data::CapacityReserved); - } } inline QString &QString::setUtf16(const ushort *autf16, qsizetype asize) diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 4feb52a7103..3217e87cc8e 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -185,7 +185,7 @@ static QArrayData *allocateData(qsizetype allocSize) } void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment, - qsizetype capacity, ArrayOptions options) noexcept + qsizetype capacity, QArrayData::AllocationOption option) noexcept { Q_ASSERT(dptr); // Alignment is a power of two @@ -208,7 +208,7 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al } Q_ASSERT(headerSize > 0); - qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, (options & (GrowsForward|GrowsBackwards)) ? QArrayData::Grow : QArrayData::KeepSize); + qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option); allocSize = reserveExtraBytes(allocSize); if (Q_UNLIKELY(allocSize < 0)) { // handle overflow. cannot allocate reliably *dptr = nullptr; @@ -220,7 +220,6 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al if (header) { // find where offset should point to so that data() is aligned to alignment bytes data = QTypedArrayData::dataStart(header, alignment); - header->flags = options & CapacityReserved; header->alloc = qsizetype(capacity); } diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 76f2c330430..9ada91d04bf 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -56,12 +56,14 @@ struct Q_CORE_EXPORT QArrayData KeepSize }; - enum ArrayOption { - /// this option is used by the allocate() function - DefaultAllocationFlags = 0, - CapacityReserved = 0x1, //!< the capacity was reserved by the user, try to keep it - GrowsForward = 0x2, //!< allocate with eyes towards growing through append() - GrowsBackwards = 0x4 //!< allocate with eyes towards growing through prepend() + enum AllocationPosition { + AllocateAtEnd, + AllocateAtBeginning + }; + + enum ArrayOption { + ArrayOptionDefault = 0, + CapacityReserved = 0x1 //!< the capacity was reserved by the user, try to keep it }; Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) @@ -112,20 +114,12 @@ struct Q_CORE_EXPORT QArrayData return newSize; } - ArrayOptions detachFlags() const noexcept - { - ArrayOptions result = DefaultAllocationFlags; - if (flags & CapacityReserved) - result |= CapacityReserved; - return result; - } - [[nodiscard]] #if defined(Q_CC_GNU) __attribute__((__malloc__)) #endif static void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment, - qsizetype capacity, ArrayOptions options = DefaultAllocationFlags) noexcept; + qsizetype capacity, AllocationOption option = QArrayData::KeepSize) noexcept; [[nodiscard]] static QPair reallocateUnaligned(QArrayData *data, void *dataPointer, qsizetype objectSize, qsizetype newCapacity, AllocationOption option) noexcept; static void deallocate(QArrayData *data, qsizetype objectSize, @@ -213,12 +207,11 @@ struct QTypedArrayData struct AlignmentDummy { QArrayData header; T data; }; - [[nodiscard]] static QPair allocate(qsizetype capacity, - ArrayOptions options = DefaultAllocationFlags) + [[nodiscard]] static QPair allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize) { static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData)); QArrayData *d; - void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, options); + void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option); #if (defined(Q_CC_GNU) && Q_CC_GNU >= 407) || QT_HAS_BUILTIN(__builtin_assume_aligned) result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy)); #endif diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index a904341effe..7121da66602 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -1094,33 +1094,6 @@ public: } } - // Returns whether reallocation is desirable before adding more elements - // into the container. This is a helper function that one can use to - // theoretically improve average operations performance. Ignoring this - // function does not affect the correctness of the array operations. - bool shouldGrowBeforeInsert(const_iterator where, qsizetype n) const noexcept - { - if (this->d == nullptr) - return true; - if (this->d->flags & QArrayData::CapacityReserved) - return false; - if (!(this->d->flags & (QArrayData::GrowsForward | QArrayData::GrowsBackwards))) - return false; - Q_ASSERT(where >= this->begin() && where <= this->end()); // in range - - const qsizetype freeAtBegin = this->freeSpaceAtBegin(); - const qsizetype freeAtEnd = this->freeSpaceAtEnd(); - - // Idea: always reallocate when not enough space at the corresponding end - if (where == this->end()) { // append or size == 0 - return freeAtEnd < n; - } else if (where == this->begin()) { // prepend - return freeAtBegin < n; - } else { // general insert - return (freeAtBegin < n && freeAtEnd < n); - } - } - // using Base::truncate; // using Base::destroyAll; // using Base::assign; diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index 398dc1a607c..d483a5a5e5b 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -165,7 +165,7 @@ public: bool detach() { if (needsDetach()) { - QPair copy = clone(detachFlags()); + QPair copy = clone(); QArrayDataPointer old(d, ptr, size); d = copy.first; ptr = copy.second; @@ -185,10 +185,9 @@ public: bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; } bool needsDetach() const noexcept { return !d || d->needsDetach(); } qsizetype detachCapacity(qsizetype newSize) const noexcept { return d ? d->detachCapacity(newSize) : newSize; } - const typename Data::ArrayOptions flags() const noexcept { return d ? typename Data::ArrayOption(d->flags) : Data::DefaultAllocationFlags; } + const typename Data::ArrayOptions flags() const noexcept { return d ? typename Data::ArrayOption(d->flags) : Data::ArrayOptionDefault; } void setFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags |= f; } void clearFlag(typename Data::ArrayOptions f) noexcept { Q_ASSERT(d); d->flags &= ~f; } - typename Data::ArrayOptions detachFlags() const noexcept { return d ? d->detachFlags() : Data::DefaultAllocationFlags; } Data *d_ptr() noexcept { return d; } void setBegin(T *begin) noexcept { ptr = begin; } @@ -207,40 +206,8 @@ public: return d->constAllocatedCapacity() - freeSpaceAtBegin() - this->size; } - static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, - qsizetype newSize, QArrayData::ArrayOptions options) - { - return allocateGrow(from, from.detachCapacity(newSize), newSize, options); - } - - static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype capacity, - qsizetype newSize, QArrayData::ArrayOptions options) - { - auto [header, dataPtr] = Data::allocate(capacity, options); - const bool valid = header != nullptr && dataPtr != nullptr; - const bool grows = (options & (Data::GrowsForward | Data::GrowsBackwards)); - if (!valid || !grows) - return QArrayDataPointer(header, dataPtr); - - // must always hold true, as valid is the first condition we check and - // if-statement short-circuits - Q_ASSERT(valid); - - // Idea: * when growing backwards, adjust pointer to prepare free space at the beginning - // * when growing forward, adjust by the previous data pointer offset - - // TODO: what's with CapacityReserved? - dataPtr += (options & Data::GrowsBackwards) ? (header->alloc - newSize) / 2 - : from.freeSpaceAtBegin(); - return QArrayDataPointer(header, dataPtr); - } - - enum AllocationPosition { - AllocateAtEnd, - AllocateAtBeginning - }; // allocate and grow. Ensure that at the minimum requiredSpace is available at the requested end - static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, AllocationPosition position) + static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, QArrayData::AllocationPosition position) { // calculate new capacity. We keep the free capacity at the side that does not have to grow // to avoid quadratic behavior with mixed append/prepend cases @@ -249,10 +216,10 @@ public: qsizetype minimalCapacity = qMax(from.size, from.constAllocatedCapacity()) + n; // subtract the free space at the side we want to allocate. This ensures that the total size requested is // the existing allocation at the other side + size + n. - minimalCapacity -= (position == AllocateAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin(); + minimalCapacity -= (position == QArrayData::AllocateAtEnd) ? from.freeSpaceAtEnd() : from.freeSpaceAtBegin(); qsizetype capacity = from.detachCapacity(minimalCapacity); const bool grows = capacity > from.constAllocatedCapacity(); - auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::GrowsBackwards : QArrayData::DefaultAllocationFlags); + auto [header, dataPtr] = Data::allocate(capacity, grows ? QArrayData::Grow : QArrayData::KeepSize); const bool valid = header != nullptr && dataPtr != nullptr; if (!valid) return QArrayDataPointer(header, dataPtr); @@ -261,8 +228,9 @@ public: // * when growing forward, adjust by the previous data pointer offset // TODO: what's with CapacityReserved? - dataPtr += (position == AllocateAtBeginning) ? qMax(0, (header->alloc - from.size - n) / 2) + dataPtr += (position == QArrayData::AllocateAtBeginning) ? qMax(0, (header->alloc - from.size - n) / 2) : from.freeSpaceAtBegin(); + header->flags = from.flags(); return QArrayDataPointer(header, dataPtr); } @@ -277,14 +245,15 @@ public: } private: - [[nodiscard]] QPair clone(QArrayData::ArrayOptions options) const + [[nodiscard]] QPair clone() const { - QPair pair = Data::allocate(detachCapacity(size), options); + QPair pair = Data::allocate(detachCapacity(size), QArrayData::KeepSize); QArrayDataPointer copy(pair.first, pair.second, 0); if (size) copy->copyAppend(begin(), end()); - pair.first = copy.d; + if (pair.first) + pair.first->flags = flags(); copy.d = nullptr; copy.ptr = nullptr; return pair; diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index e278b70b2d7..960bf18cacc 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -291,7 +291,7 @@ public: return; if (d->needsDetach()) { // must allocate memory - DataPointer detached(Data::allocate(d.allocatedCapacity(), d->detachFlags())); + DataPointer detached(Data::allocate(d.allocatedCapacity())); d.swap(detached); } else { d->truncate(0); @@ -582,8 +582,7 @@ inline void QList::resize_internal(qsizetype newSize) if (d->needsDetach() || newSize > capacity() - d.freeSpaceAtBegin()) { // must allocate memory - DataPointer detached(Data::allocate(d->detachCapacity(newSize), - d->detachFlags())); + DataPointer detached(Data::allocate(d->detachCapacity(newSize))); if (size() && newSize) { detached->copyAppend(constBegin(), constBegin() + qMin(newSize, size())); } @@ -608,9 +607,10 @@ void QList::reserve(qsizetype asize) } } - DataPointer detached(Data::allocate(qMax(asize, size()), - d->detachFlags() | Data::CapacityReserved)); + DataPointer detached(Data::allocate(qMax(asize, size()))); detached->copyAppend(constBegin(), constEnd()); + if (detached.d_ptr()) + detached->setFlag(Data::CapacityReserved); d.swap(detached); } @@ -621,15 +621,14 @@ inline void QList::squeeze() return; if (d->needsDetach() || size() < capacity()) { // must allocate memory - DataPointer detached(Data::allocate(size(), d->detachFlags() & ~Data::CapacityReserved)); + DataPointer detached(Data::allocate(size())); if (size()) { detached->copyAppend(constBegin(), constEnd()); } d.swap(detached); - } else { - // We're detached so this is fine - d->clearFlag(Data::CapacityReserved); } + // We're detached so this is fine + d->clearFlag(Data::CapacityReserved); } template @@ -646,7 +645,7 @@ inline void QList::remove(qsizetype i, qsizetype n) ((d->flags() & Data::CapacityReserved) == 0 && newSize < d->allocatedCapacity()/2)) { // allocate memory - DataPointer detached(Data::allocate(d->detachCapacity(newSize), d->detachFlags())); + DataPointer detached(Data::allocate(d->detachCapacity(newSize))); const_iterator where = constBegin() + i; if (newSize) { detached->copyAppend(constBegin(), where); @@ -672,7 +671,7 @@ inline void QList::append(const_iterator i1, const_iterator i2) return; const auto distance = std::distance(i1, i2); if (d->needsDetach() || distance > d.freeSpaceAtEnd()) { - DataPointer detached(DataPointer::allocateGrow(d, distance, DataPointer::AllocateAtEnd)); + DataPointer detached(DataPointer::allocateGrow(d, distance, QArrayData::AllocateAtEnd)); detached->copyAppend(constBegin(), constEnd()); detached->copyAppend(i1, i2); d.swap(detached); @@ -691,7 +690,7 @@ inline void QList::append(QList &&other) return append(other); if (d->needsDetach() || other.size() > d.freeSpaceAtEnd()) { - DataPointer detached(DataPointer::allocateGrow(d, other.size(), DataPointer::AllocateAtEnd)); + DataPointer detached(DataPointer::allocateGrow(d, other.size(), QArrayData::AllocateAtEnd)); if (!d->needsDetach()) detached->moveAppend(begin(), end()); @@ -711,7 +710,7 @@ template inline typename QList::reference QList::emplaceFront(Args &&... args) { if (d->needsDetach() || !d.freeSpaceAtBegin()) { - DataPointer detached(DataPointer::allocateGrow(d, 1, DataPointer::AllocateAtBeginning)); + DataPointer detached(DataPointer::allocateGrow(d, 1, QArrayData::AllocateAtBeginning)); detached->emplace(detached.begin(), std::forward(args)...); if (!d.needsDetach()) @@ -737,9 +736,9 @@ QList::insert(qsizetype i, qsizetype n, parameter_type t) // it's not worth wasting CPU cycles for that if (d->needsDetach() || (n > d.freeSpaceAtBegin() && n > d.freeSpaceAtEnd())) { - typename DataPointer::AllocationPosition pos = DataPointer::AllocateAtEnd; + typename QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd; if (d.size != 0 && i <= (d.size >> 1)) - pos = DataPointer::AllocateAtBeginning; + pos = QArrayData::AllocateAtBeginning; DataPointer detached(DataPointer::allocateGrow(d, n, pos)); const_iterator where = constBegin() + i; @@ -767,9 +766,9 @@ QList::emplace(qsizetype i, Args&&... args) Q_ASSERT_X(i >= 0 && i <= d->size, "QList::insert", "index out of range"); if (d->needsDetach() || (d.size == d.constAllocatedCapacity())) { - typename DataPointer::AllocationPosition pos = DataPointer::AllocateAtEnd; + typename QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd; if (d.size != 0 && i <= (d.size >> 1)) - pos = DataPointer::AllocateAtBeginning; + pos = QArrayData::AllocateAtBeginning; DataPointer detached(DataPointer::allocateGrow(d, 1, pos)); const_iterator where = constBegin() + i; @@ -810,8 +809,7 @@ inline QList &QList::fill(parameter_type t, qsizetype newSize) newSize = size(); if (d->needsDetach() || newSize > capacity()) { // must allocate memory - DataPointer detached(Data::allocate(d->detachCapacity(newSize), - d->detachFlags())); + DataPointer detached(Data::allocate(d->detachCapacity(newSize))); detached->copyAppend(newSize, t); d.swap(detached); } else { diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index 4f35ff5e919..d5205fba44d 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -51,25 +51,31 @@ public: { } - explicit SimpleVector(size_t n, typename Data::ArrayOptions f = Data::DefaultAllocationFlags) - : d(Data::allocate(n, f)) + explicit SimpleVector(size_t n, bool capacityReserved = false) + : d(Data::allocate(n)) { if (n) d->appendInitialize(n); + if (capacityReserved) + d.setFlag(QArrayData::CapacityReserved); } - SimpleVector(size_t n, const T &t, typename Data::ArrayOptions f = Data::DefaultAllocationFlags) - : d(Data::allocate(n, f)) + SimpleVector(size_t n, const T &t, bool capacityReserved = false) + : d(Data::allocate(n)) { if (n) d->copyAppend(n, t); + if (capacityReserved) + d.setFlag(QArrayData::CapacityReserved); } - SimpleVector(const T *begin, const T *end, typename Data::ArrayOptions f = Data::DefaultAllocationFlags) - : d(Data::allocate(end - begin, f)) + SimpleVector(const T *begin, const T *end, bool capacityReserved = false) + : d(Data::allocate(end - begin)) { if (end - begin) d->copyAppend(begin, end); + if (capacityReserved) + d.setFlag(QArrayData::CapacityReserved); } SimpleVector(Data *header, T *data, size_t len = 0) @@ -153,10 +159,11 @@ public: } } - SimpleVector detached(Data::allocate(qMax(n, size()), - d->detachFlags() | Data::CapacityReserved)); - if (size()) + SimpleVector detached(Data::allocate(qMax(n, size()))); + if (size()) { detached.d->copyAppend(constBegin(), constEnd()); + detached.d->setFlag(QArrayData::CapacityReserved); + } detached.swap(*this); } @@ -166,8 +173,7 @@ public: return; if (d->needsDetach() || newSize > capacity()) { - SimpleVector detached(Data::allocate( - d->detachCapacity(newSize), d->detachFlags())); + SimpleVector detached(Data::allocate(d->detachCapacity(newSize))); if (newSize) { if (newSize < size()) { const T *const begin = constBegin(); @@ -201,14 +207,9 @@ public: return; T *const begin = d->begin(); - const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin(), last - first); - const auto newSize = size() + (last - first); - if (d->needsDetach() - || capacity() - size() < size_t(last - first) - || shouldGrow) { - const auto flags = d->detachFlags() | Data::GrowsBackwards; - SimpleVector detached(DataPointer::allocateGrow(d, d->detachCapacity(newSize), newSize, - flags)); + const auto n = (last - first); + if (d->needsDetach() || n > d.freeSpaceAtBegin()) { + SimpleVector detached(DataPointer::allocateGrow(d, n, QArrayData::AllocateAtBeginning)); detached.d->copyAppend(first, last); detached.d->copyAppend(begin, begin + d->size); @@ -227,7 +228,7 @@ public: auto requiredSize = qsizetype(last - first); if (d->needsDetach() || d.freeSpaceAtEnd() < requiredSize) { - SimpleVector detached(DataPointer::allocateGrow(d, requiredSize, DataPointer::AllocateAtEnd)); + SimpleVector detached(DataPointer::allocateGrow(d, requiredSize, QArrayData::AllocateAtEnd)); if (d->size) { const T *const begin = constBegin(); @@ -263,16 +264,13 @@ public: const iterator begin = d->begin(); const iterator where = begin + position; const iterator end = begin + d->size; - const bool shouldGrow = d->shouldGrowBeforeInsert(d.begin() + position, last - first); - const auto newSize = size() + (last - first); - if (d->needsDetach() - || capacity() - size() < size_t(last - first) - || shouldGrow) { - auto flags = d->detachFlags() | Data::GrowsForward; - if (size_t(position) <= (size() + (last - first)) / 4) - flags |= Data::GrowsBackwards; - SimpleVector detached(DataPointer::allocateGrow(d, d->detachCapacity(newSize), newSize, - flags)); + const qsizetype n = last - first; + if (d->needsDetach() || (n > d.freeSpaceAtBegin() && n > d.freeSpaceAtEnd())) { + typename QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd; + if (d.size != 0 && position <= (d.size >> 1)) + pos = QArrayData::AllocateAtBeginning; + + SimpleVector detached(DataPointer::allocateGrow(d, n, pos)); if (position) detached.d->copyAppend(begin, where); @@ -307,9 +305,7 @@ public: const T *const end = begin + d->size; if (d->needsDetach()) { - SimpleVector detached(Data::allocate( - d->detachCapacity(size() - (last - first)), - d->detachFlags())); + SimpleVector detached(Data::allocate(d->detachCapacity(size() - (last - first)))); if (first != begin) detached.d->copyAppend(begin, first); detached.d->copyAppend(last, end); diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index f8d85a37e77..15b38f3645b 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -80,7 +80,7 @@ private slots: void grow(); void freeSpace_data(); void freeSpace(); - void dataPointerAllocate_data() { arrayOps_data(); } + void dataPointerAllocate_data(); void dataPointerAllocate(); #ifndef QT_NO_EXCEPTIONS void exceptionSafetyPrimitives_constructor(); @@ -126,7 +126,7 @@ void tst_QArrayData::simpleVector() SimpleVector v1; SimpleVector v2(v1); - SimpleVector v3(nullptr, nullptr, 0); + SimpleVector v3(nullptr, (int *)nullptr, 0); SimpleVector v4(nullptr, data, 0); SimpleVector v5(nullptr, data, 1); SimpleVector v6(nullptr, data, 7); @@ -457,8 +457,7 @@ void tst_QArrayData::allocate_data() { QTest::addColumn("objectSize"); QTest::addColumn("alignment"); - QTest::addColumn("allocateOptions"); - QTest::addColumn("isCapacityReserved"); + QTest::addColumn("grow"); struct { char const *typeName; @@ -472,13 +471,10 @@ void tst_QArrayData::allocate_data() struct { char const *description; - QArrayData::ArrayOptions allocateOptions; - bool isCapacityReserved; + bool grow; } options[] = { - { "Default", QArrayData::DefaultAllocationFlags, false }, - { "Reserved", QArrayData::CapacityReserved, true }, - { "Grow", QArrayData::GrowsForward, false }, - { "GrowBack", QArrayData::GrowsBackwards, false } + { "Default", false }, + { "Grow", true } }; for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i) @@ -488,15 +484,14 @@ void tst_QArrayData::allocate_data() + QLatin1String(": ") + QLatin1String(options[j].description))) << types[i].objectSize << types[i].alignment - << options[j].allocateOptions << options[j].isCapacityReserved; + << options[j].grow; } void tst_QArrayData::allocate() { QFETCH(size_t, objectSize); QFETCH(size_t, alignment); - QFETCH(QArrayData::ArrayOptions, allocateOptions); - QFETCH(bool, isCapacityReserved); + QFETCH(bool, grow); // Minimum alignment that can be requested is that of QArrayData. // Typically, this alignment is sizeof(void *) and ensured by malloc. @@ -507,16 +502,14 @@ void tst_QArrayData::allocate() for (qsizetype capacity = 1; capacity <= 1024; capacity <<= 1) { QArrayData *data; - void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, - capacity, QArrayData::ArrayOptions(allocateOptions)); + void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, grow ? QArrayData::Grow : QArrayData::KeepSize); keeper.headers.append(data); - if (allocateOptions & (QArrayData::GrowsForward | QArrayData::GrowsBackwards)) + if (grow) QVERIFY(data->allocatedCapacity() > capacity); else QCOMPARE(data->allocatedCapacity(), capacity); - QCOMPARE(bool(data->flags & QArrayData::CapacityReserved), isCapacityReserved); // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. @@ -528,8 +521,7 @@ void tst_QArrayData::reallocate() { QFETCH(size_t, objectSize); QFETCH(size_t, alignment); - QFETCH(QArrayData::ArrayOptions, allocateOptions); - QFETCH(bool, isCapacityReserved); + QFETCH(bool, grow); // Minimum alignment that can be requested is that of QArrayData. // Typically, this alignment is sizeof(void *) and ensured by malloc. @@ -538,28 +530,24 @@ void tst_QArrayData::reallocate() int capacity = 10; Deallocator keeper(objectSize, minAlignment); QArrayData *data; - void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, - QArrayData::ArrayOptions(allocateOptions) & ~QArrayData::GrowsForward); + void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, grow ? QArrayData::Grow : QArrayData::KeepSize); keeper.headers.append(data); memset(dataPointer, 'A', objectSize * capacity); // now try to reallocate int newCapacity = 40; - auto pair = QArrayData::reallocateUnaligned(data, dataPointer, objectSize, newCapacity, - (allocateOptions & (QArrayData::GrowsBackwards|QArrayData::GrowsForward)) ? - QArrayData::Grow : QArrayData::KeepSize); + auto pair = QArrayData::reallocateUnaligned(data, dataPointer, objectSize, newCapacity, grow ? QArrayData::Grow : QArrayData::KeepSize); data = pair.first; dataPointer = pair.second; QVERIFY(data); keeper.headers.clear(); keeper.headers.append(data); - if (allocateOptions & (QArrayData::GrowsForward | QArrayData::GrowsBackwards)) + if (grow) QVERIFY(data->allocatedCapacity() > newCapacity); else QCOMPARE(data->allocatedCapacity(), newCapacity); - QCOMPARE(!(data->flags & QArrayData::CapacityReserved), !isCapacityReserved); for (int i = 0; i < capacity; ++i) QCOMPARE(static_cast(dataPointer)[i], 'A'); @@ -593,8 +581,7 @@ void tst_QArrayData::alignment() for (int i = 0; i < 100; ++i) { QArrayData *data; - void *dataPointer = QArrayData::allocate(&data, sizeof(Unaligned), - minAlignment, 8, QArrayData::DefaultAllocationFlags); + void *dataPointer = QArrayData::allocate(&data, sizeof(Unaligned), minAlignment, 8, QArrayData::KeepSize); keeper.headers.append(data); QVERIFY(data); @@ -773,27 +760,15 @@ size_t CountedObject::liveCount = 0; void tst_QArrayData::arrayOps_data() { - QTest::addColumn("allocationOptions"); + QTest::addColumn("capacityReserved"); - QTest::newRow("default-alloc") << QArrayData::ArrayOptions(QArrayData::DefaultAllocationFlags); - QTest::newRow("grows-forward") << QArrayData::ArrayOptions(QArrayData::GrowsForward); - QTest::newRow("grows-backwards") << QArrayData::ArrayOptions(QArrayData::GrowsBackwards); - QTest::newRow("grows-bidirectional") - << QArrayData::ArrayOptions(QArrayData::GrowsForward | QArrayData::GrowsBackwards); - QTest::newRow("reserved-capacity") - << QArrayData::ArrayOptions(QArrayData::CapacityReserved); - QTest::newRow("reserved-capacity-grows-forward") - << QArrayData::ArrayOptions(QArrayData::GrowsForward | QArrayData::CapacityReserved); - QTest::newRow("reserved-capacity-grows-backwards") - << QArrayData::ArrayOptions(QArrayData::GrowsBackwards | QArrayData::CapacityReserved); - QTest::newRow("reserved-capacity-grows-bidirectional") - << QArrayData::ArrayOptions(QArrayData::GrowsForward | QArrayData::GrowsBackwards - | QArrayData::CapacityReserved); + QTest::newRow("default") << false; + QTest::newRow("capacity-reserved") << true; } void tst_QArrayData::arrayOps() { - QFETCH(QArrayData::ArrayOptions, allocationOptions); + QFETCH(bool, capacityReserved); CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker); const int intArray[5] = { 80, 101, 100, 114, 111 }; @@ -819,9 +794,9 @@ void tst_QArrayData::arrayOps() //////////////////////////////////////////////////////////////////////////// // copyAppend (I) - SimpleVector vi(intArray, intArray + 5, allocationOptions); - SimpleVector vs(stringArray, stringArray + 5, allocationOptions); - SimpleVector vo(objArray, objArray + 5, allocationOptions); + SimpleVector vi(intArray, intArray + 5, capacityReserved); + SimpleVector vs(stringArray, stringArray + 5, capacityReserved); + SimpleVector vo(objArray, objArray + 5, capacityReserved); QCOMPARE(CountedObject::liveCount, size_t(10)); for (int i = 0; i < 5; ++i) { @@ -847,9 +822,9 @@ void tst_QArrayData::arrayOps() QString referenceString = QLatin1String("reference"); CountedObject referenceObject; - vi = SimpleVector(5, referenceInt, allocationOptions); - vs = SimpleVector(5, referenceString, allocationOptions); - vo = SimpleVector(5, referenceObject, allocationOptions); + vi = SimpleVector(5, referenceInt, capacityReserved); + vs = SimpleVector(5, referenceString, capacityReserved); + vo = SimpleVector(5, referenceObject, capacityReserved); QCOMPARE(vi.size(), size_t(5)); QCOMPARE(vs.size(), size_t(5)); @@ -976,14 +951,14 @@ void tst_QArrayData::arrayOps2_data() void tst_QArrayData::arrayOps2() { - QFETCH(QArrayData::ArrayOptions, allocationOptions); + QFETCH(bool, capacityReserved); CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker); //////////////////////////////////////////////////////////////////////////// // appendInitialize - SimpleVector vi(5, allocationOptions); - SimpleVector vs(5, allocationOptions); - SimpleVector vo(5, allocationOptions); + SimpleVector vi(5, capacityReserved); + SimpleVector vs(5, capacityReserved); + SimpleVector vo(5, capacityReserved); QCOMPARE(vi.size(), size_t(5)); QCOMPARE(vs.size(), size_t(5)); @@ -1119,13 +1094,13 @@ void tst_QArrayData::arrayOps2() void tst_QArrayData::arrayOpsExtra_data() { - arrayOps_data(); + dataPointerAllocate_data(); } void tst_QArrayData::arrayOpsExtra() { QSKIP("Skipped while changing QArrayData operations.", SkipAll); - QFETCH(QArrayData::ArrayOptions, allocationOptions); + QFETCH(QArrayData::AllocationPosition, allocationPosition); CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker); constexpr size_t inputSize = 5; @@ -1144,14 +1119,11 @@ void tst_QArrayData::arrayOpsExtra() for (size_t i = 0; i < 5; ++i) QCOMPARE(objArray[i].id, i); - const auto setupDataPointers = [&allocationOptions] (size_t capacity, size_t initialSize = 0) { + const auto setupDataPointers = [&allocationPosition] (size_t capacity, size_t initialSize = 0) { const qsizetype alloc = qsizetype(capacity); - auto i = QArrayDataPointer::allocateGrow(QArrayDataPointer(), alloc, - initialSize, allocationOptions); - auto s = QArrayDataPointer::allocateGrow(QArrayDataPointer(), alloc, - initialSize, allocationOptions); - auto o = QArrayDataPointer::allocateGrow(QArrayDataPointer(), alloc, - initialSize, allocationOptions); + auto i = QArrayDataPointer::allocateGrow(QArrayDataPointer(), alloc, allocationPosition); + auto s = QArrayDataPointer::allocateGrow(QArrayDataPointer(), alloc, allocationPosition); + auto o = QArrayDataPointer::allocateGrow(QArrayDataPointer(), alloc, allocationPosition); if (initialSize) { i->appendInitialize(initialSize); s->appendInitialize(initialSize); @@ -1168,7 +1140,7 @@ void tst_QArrayData::arrayOpsExtra() const auto cloneArrayDataPointer = [] (auto &dataPointer, size_t capacity) { using ArrayPointer = std::decay_t; using Type = std::decay_t; - ArrayPointer copy(QTypedArrayData::allocate(qsizetype(capacity), dataPointer.flags())); + ArrayPointer copy(QTypedArrayData::allocate(qsizetype(capacity))); copy->copyAppend(dataPointer.begin(), dataPointer.end()); return copy; }; @@ -1273,7 +1245,7 @@ void tst_QArrayData::arrayOpsExtra() std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); }); // sanity checks: - if (allocationOptions & QArrayData::GrowsBackwards) { + if (allocationPosition & QArrayData::AllocateAtBeginning) { QVERIFY(intData.freeSpaceAtBegin() > 0); QVERIFY(strData.freeSpaceAtBegin() > 0); QVERIFY(objData.freeSpaceAtBegin() > 0); @@ -1372,7 +1344,7 @@ void tst_QArrayData::arrayOpsExtra() std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); }); // sanity checks: - if (allocationOptions & QArrayData::GrowsBackwards) { + if (allocationPosition & QArrayData::AllocateAtBeginning) { QVERIFY(intData.freeSpaceAtBegin() > 0); QVERIFY(strData.freeSpaceAtBegin() > 0); QVERIFY(objData.freeSpaceAtBegin() > 0); @@ -1471,7 +1443,7 @@ void tst_QArrayData::arrayOpsExtra() std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); }); // sanity checks: - if (allocationOptions & QArrayData::GrowsBackwards) { + if (allocationPosition & QArrayData::AllocateAtBeginning) { QVERIFY(intData.freeSpaceAtBegin() > 0); QVERIFY(strData.freeSpaceAtBegin() > 0); QVERIFY(objData.freeSpaceAtBegin() > 0); @@ -2045,44 +2017,46 @@ void tst_QArrayData::grow() void tst_QArrayData::freeSpace_data() { - QTest::addColumn("allocationOptions"); QTest::addColumn("n"); for (const size_t n : {1, 3, 5, 7, 16, 25}) { QString suffix = QString::number(n) + QLatin1String("-elements"); - QTest::newRow(qPrintable(QLatin1String("default-alloc-") + suffix)) - << QArrayData::ArrayOptions(QArrayData::DefaultAllocationFlags) << n; - QTest::newRow(qPrintable(QLatin1String("grows-forward-") + suffix)) - << QArrayData::ArrayOptions(QArrayData::GrowsForward) << n; - QTest::newRow(qPrintable(QLatin1String("grows-bidirectional-") + suffix)) - << QArrayData::ArrayOptions(QArrayData::GrowsForward | QArrayData::GrowsBackwards) << n; + QTest::newRow(qPrintable(QLatin1String("alloc-") + suffix)) + << n; } } void tst_QArrayData::freeSpace() { - QFETCH(QArrayData::ArrayOptions, allocationOptions); QFETCH(size_t, n); - const auto testFreeSpace = [] (auto dummy, auto options, qsizetype n) { + const auto testFreeSpace = [] (auto dummy, qsizetype n) { using Type = std::decay_t; using DataPointer = QArrayDataPointer; Q_UNUSED(dummy); const qsizetype capacity = n + 1; - auto ptr = DataPointer::allocateGrow(DataPointer(), capacity, n, options); + auto ptr = DataPointer::allocateGrow(DataPointer(), capacity, QArrayData::AllocateAtEnd); const auto alloc = qsizetype(ptr.constAllocatedCapacity()); QVERIFY(alloc >= capacity); QCOMPARE(ptr.freeSpaceAtBegin() + ptr.freeSpaceAtEnd(), alloc); }; - RUN_TEST_FUNC(testFreeSpace, char(0), allocationOptions, n); - RUN_TEST_FUNC(testFreeSpace, char16_t(0), allocationOptions, n); - RUN_TEST_FUNC(testFreeSpace, int(0), allocationOptions, n); - RUN_TEST_FUNC(testFreeSpace, QString(), allocationOptions, n); - RUN_TEST_FUNC(testFreeSpace, CountedObject(), allocationOptions, n); + RUN_TEST_FUNC(testFreeSpace, char(0), n); + RUN_TEST_FUNC(testFreeSpace, char16_t(0), n); + RUN_TEST_FUNC(testFreeSpace, int(0), n); + RUN_TEST_FUNC(testFreeSpace, QString(), n); + RUN_TEST_FUNC(testFreeSpace, CountedObject(), n); +} + +void tst_QArrayData::dataPointerAllocate_data() +{ + QTest::addColumn("allocationPosition"); + + QTest::newRow("at-end") << QArrayData::AllocateAtEnd; + QTest::newRow("at-begin") << QArrayData::AllocateAtBeginning; } void tst_QArrayData::dataPointerAllocate() { - QFETCH(QArrayData::ArrayOptions, allocationOptions); + QFETCH(QArrayData::AllocationPosition, allocationPosition); const auto createDataPointer = [] (qsizetype capacity, auto initValue) { using Type = std::decay_t; Q_UNUSED(initValue); @@ -2098,21 +2072,18 @@ void tst_QArrayData::dataPointerAllocate() oldDataPointer->insert(oldDataPointer.begin(), 1, initValue); // trigger prepend QVERIFY(!oldDataPointer.needsDetach()); - auto newDataPointer = DataPointer::allocateGrow( - oldDataPointer, oldDataPointer->detachCapacity(newSize), newSize, allocationOptions); + auto newDataPointer = DataPointer::allocateGrow(oldDataPointer, newSize, allocationPosition); const auto newAlloc = newDataPointer.constAllocatedCapacity(); const auto freeAtBegin = newDataPointer.freeSpaceAtBegin(); const auto freeAtEnd = newDataPointer.freeSpaceAtEnd(); QVERIFY(newAlloc > oldDataPointer.constAllocatedCapacity()); QCOMPARE(freeAtBegin + freeAtEnd, newAlloc); - if (allocationOptions & QArrayData::GrowsBackwards) { - // bad check, but will suffice for now, hopefully - QCOMPARE(freeAtBegin, (newAlloc - newSize) / 2); - } else if (allocationOptions & QArrayData::GrowsForward) { + if (allocationPosition == QArrayData::AllocateAtBeginning) { + QVERIFY(freeAtBegin > 0); + } else if (allocationPosition & QArrayData::AllocateAtEnd) { QCOMPARE(freeAtBegin, oldDataPointer.freeSpaceAtBegin()); - } else { - QCOMPARE(freeAtBegin, 0); + QVERIFY(freeAtEnd > 0); } }; @@ -2133,18 +2104,18 @@ void tst_QArrayData::dataPointerAllocate() auto oldDataPointerCopy = oldDataPointer; // force detach later QVERIFY(oldDataPointer.needsDetach()); - auto newDataPointer = DataPointer::allocateGrow( - oldDataPointer, oldDataPointer->detachCapacity(newSize), newSize, allocationOptions); + auto newDataPointer = DataPointer::allocateGrow(oldDataPointer, oldDataPointer->detachCapacity(newSize), allocationPosition); const auto newAlloc = newDataPointer.constAllocatedCapacity(); const auto freeAtBegin = newDataPointer.freeSpaceAtBegin(); const auto freeAtEnd = newDataPointer.freeSpaceAtEnd(); QVERIFY(newAlloc > oldDataPointer.constAllocatedCapacity()); QCOMPARE(freeAtBegin + freeAtEnd, newAlloc); - if (allocationOptions & QArrayData::GrowsBackwards) { - QCOMPARE(freeAtBegin, (newAlloc - newSize) / 2); - } else { - QCOMPARE(freeAtBegin, 0); + if (allocationPosition == QArrayData::AllocateAtBeginning) { + QVERIFY(freeAtBegin > 0); + } else if (allocationPosition & QArrayData::AllocateAtEnd) { + QCOMPARE(freeAtBegin, oldDataPointer.freeSpaceAtBegin()); + QVERIFY(freeAtEnd > 0); } };