Fix capacity reservation for shared QByteArray
We can squeeze, but not by discarding elements. Make sure the size of the object stays intact after changing the reserved capacity. I've also added unit tests for other containers, just to be sure. Task-number: QTBUG-37750 Change-Id: I5135b095943b7589423c51cebcb52af792468e61 Reviewed-by: Marc Mutz <marc.mutz@kdab.com> Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
This commit is contained in:
parent
3e930baa98
commit
f1540a2966
@ -462,7 +462,7 @@ inline int QByteArray::capacity() const
|
||||
inline void QByteArray::reserve(int asize)
|
||||
{
|
||||
if (d->ref.isShared() || uint(asize) + 1u > d->alloc) {
|
||||
reallocData(uint(asize) + 1u, d->detachFlags() | Data::CapacityReserved);
|
||||
reallocData(qMax(uint(size()), uint(asize)) + 1u, d->detachFlags() | Data::CapacityReserved);
|
||||
} else {
|
||||
// cannot set unconditionally, since d could be the shared_null or
|
||||
// otherwise static
|
||||
|
@ -1855,6 +1855,21 @@ void tst_QByteArray::reserve()
|
||||
QVERIFY(data == qba.data());
|
||||
}
|
||||
|
||||
qba.resize(capacity);
|
||||
|
||||
QByteArray copy = qba;
|
||||
qba.reserve(capacity / 2);
|
||||
QCOMPARE(qba.size(), capacity); // we didn't shrink the size!
|
||||
QCOMPARE(qba.capacity(), capacity);
|
||||
QCOMPARE(copy.capacity(), capacity);
|
||||
|
||||
copy = qba;
|
||||
qba.reserve(capacity * 2);
|
||||
QCOMPARE(qba.size(), capacity);
|
||||
QCOMPARE(qba.capacity(), capacity * 2);
|
||||
QCOMPARE(copy.capacity(), capacity);
|
||||
QVERIFY(qba.constData() != data);
|
||||
|
||||
QByteArray nil1, nil2;
|
||||
nil1.reserve(0);
|
||||
nil2.squeeze();
|
||||
|
@ -278,6 +278,8 @@ private slots:
|
||||
void setSharableComplex() const;
|
||||
void eraseValidIteratorsOnSharedList() const;
|
||||
void insertWithValidIteratorsOnSharedList() const;
|
||||
|
||||
void reserve() const;
|
||||
private:
|
||||
template<typename T> void length() const;
|
||||
template<typename T> void append() const;
|
||||
@ -1669,5 +1671,31 @@ void tst_QList::insertWithValidIteratorsOnSharedList() const
|
||||
QCOMPARE(a.at(1), 15);
|
||||
}
|
||||
|
||||
void tst_QList::reserve() const
|
||||
{
|
||||
// Note:
|
||||
// This test depends on QList's current behavior that ints are stored in the array itself.
|
||||
// This test would not work for QList<Complex>.
|
||||
int capacity = 100;
|
||||
QList<int> list;
|
||||
list.reserve(capacity);
|
||||
list << 0;
|
||||
int *data = &list[0];
|
||||
|
||||
for (int i = 1; i < capacity; i++) {
|
||||
list << i;
|
||||
QCOMPARE(&list.at(0), data);
|
||||
}
|
||||
|
||||
QList<int> copy = list;
|
||||
list.reserve(capacity / 2);
|
||||
QCOMPARE(list.size(), capacity); // we didn't shrink the size!
|
||||
|
||||
copy = list;
|
||||
list.reserve(capacity * 2);
|
||||
QCOMPARE(list.size(), capacity);
|
||||
QVERIFY(&list.at(0) != data);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QList)
|
||||
#include "tst_qlist.moc"
|
||||
|
@ -4277,14 +4277,23 @@ void tst_QString::capacity()
|
||||
QVERIFY( (int)s2.capacity() >= res );
|
||||
QCOMPARE( s2, s1 );
|
||||
|
||||
s2 = s1; // share again
|
||||
s2.reserve( res * 2 );
|
||||
QVERIFY( (int)s2.capacity() >= res * 2 );
|
||||
QVERIFY(s2.constData() != s1.constData());
|
||||
QCOMPARE( s2, s1 );
|
||||
|
||||
// don't share again -- s2 must be detached for squeeze() to do anything
|
||||
s2.squeeze();
|
||||
QVERIFY( (int)s2.capacity() == res );
|
||||
QCOMPARE( s2, s1 );
|
||||
|
||||
s2 = s1; // share again
|
||||
int oldsize = s1.size();
|
||||
s2.reserve( res / 2 );
|
||||
QVERIFY( (int)s2.capacity() >= res / 2 );
|
||||
QVERIFY( (int)s2.capacity() >= oldsize );
|
||||
QCOMPARE( s2, s1 );
|
||||
}
|
||||
|
||||
void tst_QString::section_data()
|
||||
|
@ -1942,6 +1942,7 @@ void tst_QVector::reserve()
|
||||
a.resize(2);
|
||||
QVector<Foo> b(a);
|
||||
b.reserve(1);
|
||||
QCOMPARE(b.size(), a.size());
|
||||
}
|
||||
QCOMPARE(fooCtor, fooDtor);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user