diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index ae4cbc3081..78fbc9cf32 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -91,6 +91,13 @@ struct Q_CORE_EXPORT QArrayData Q_DECLARE_FLAGS(AllocationOptions, AllocationOption) + size_t detachCapacity(size_t newSize) const + { + if (capacityReserved && newSize < alloc) + return alloc; + return newSize; + } + AllocationOptions detachFlags() const { AllocationOptions result; diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index f5ad53aa54..4eb90ac35e 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -171,7 +171,7 @@ public: private: Data *clone(QArrayData::AllocationOptions options) const Q_REQUIRED_RESULT { - QArrayDataPointer copy(Data::allocate(d->alloc ? d->alloc : d->size, + QArrayDataPointer copy(Data::allocate(d->detachCapacity(d->size), options)); if (d->size) copy->copyAppend(d->begin(), d->end()); diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index 0cc7561b46..54c9fae589 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -184,7 +184,7 @@ public: if (d->ref.isShared() || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( - qMax(capacity(), size() + (last - first)), + d->detachCapacity(size() + (last - first)), d->detachFlags() | Data::Grow)); detached.d->copyAppend(first, last); @@ -205,7 +205,7 @@ public: if (d->ref.isShared() || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( - qMax(capacity(), size() + (last - first)), + d->detachCapacity(size() + (last - first)), d->detachFlags() | Data::Grow)); if (d->size) { @@ -245,7 +245,7 @@ public: if (d->ref.isShared() || capacity() - size() < size_t(last - first)) { SimpleVector detached(Data::allocate( - qMax(capacity(), size() + (last - first)), + d->detachCapacity(size() + (last - first)), d->detachFlags() | Data::Grow)); if (position) diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 6d3bbf046f..b3b8040b1c 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -1175,8 +1175,10 @@ void tst_QArrayData::setSharable_data() QArrayDataPointer emptyReserved(QTypedArrayData::allocate(5, QArrayData::CapacityReserved)); - QArrayDataPointer nonEmpty(QTypedArrayData::allocate(10, + QArrayDataPointer nonEmpty(QTypedArrayData::allocate(5, QArrayData::Default)); + QArrayDataPointer nonEmptyExtraCapacity( + QTypedArrayData::allocate(10, QArrayData::Default)); QArrayDataPointer nonEmptyReserved(QTypedArrayData::allocate(15, QArrayData::CapacityReserved)); QArrayDataPointer staticArray( @@ -1185,13 +1187,15 @@ void tst_QArrayData::setSharable_data() QTypedArrayData::fromRawData(staticArrayData.data, 10)); nonEmpty->copyAppend(5, 1); + nonEmptyExtraCapacity->copyAppend(5, 1); nonEmptyReserved->copyAppend(7, 2); QTest::newRow("shared-null") << null << size_t(0) << size_t(0) << false << 0; QTest::newRow("shared-empty") << empty << size_t(0) << size_t(0) << false << 0; // unsharable-empty implicitly tested in shared-empty QTest::newRow("empty-reserved") << emptyReserved << size_t(0) << size_t(5) << true << 0; - QTest::newRow("non-empty") << nonEmpty << size_t(5) << size_t(10) << false << 1; + QTest::newRow("non-empty") << nonEmpty << size_t(5) << size_t(5) << false << 1; + QTest::newRow("non-empty-extra-capacity") << nonEmptyExtraCapacity << size_t(5) << size_t(10) << false << 1; QTest::newRow("non-empty-reserved") << nonEmptyReserved << size_t(7) << size_t(15) << true << 2; QTest::newRow("static-array") << staticArray << size_t(10) << size_t(0) << false << 3; QTest::newRow("raw-data") << rawData << size_t(10) << size_t(0) << false << 3; @@ -1229,8 +1233,10 @@ void tst_QArrayData::setSharable() // Unshare, must detach array.setSharable(false); - // Immutability (alloc == 0) is lost on detach - if (capacity == 0 && size != 0) + // Immutability (alloc == 0) is lost on detach, as is additional capacity + // if capacityReserved flag is not set. + if ((capacity == 0 && size != 0) + || (!isCapacityReserved && capacity > size)) capacity = size; QVERIFY(!array->ref.isShared());