Q[Multi]Hash::reserve(): do nothing if desired size is less than current

Calling Q[Multi]Hash::reserve(n) when n is much smaller than the
current amount of elements in the hash, could result in an infinite
loop, because at some point the algorithm could not find a free bucket
for the element.

Fixing it by returning early if the new desired capacity is less than
current.

Fixes: QTBUG-102067
Pick-to: 6.3 6.2
Change-Id: I38ef0b2168c4e2a317eedf91b2155b1fdffb1c27
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ivan Solovev 2022-03-30 17:09:32 +02:00
parent 87098106d0
commit d11941db41
2 changed files with 37 additions and 0 deletions

View File

@ -944,6 +944,9 @@ public:
inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
void reserve(qsizetype size)
{
// reserve(0) is used in squeeze()
if (size && (this->capacity() >= size))
return;
if (isDetached())
d->rehash(size);
else
@ -1507,6 +1510,9 @@ public:
inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; }
void reserve(qsizetype size)
{
// reserve(0) is used in squeeze()
if (size && (this->capacity() >= size))
return;
if (isDetached())
d->rehash(size);
else

View File

@ -98,6 +98,7 @@ private slots:
void fineTuningInEmptyHash();
void reserveShared();
void reserveLessThanCurrentAmount();
void QTBUG98265();
@ -2667,6 +2668,36 @@ void tst_QHash::reserveShared()
QCOMPARE(hash.capacity(), oldCap);
}
void tst_QHash::reserveLessThanCurrentAmount()
{
{
QHash<int, int> hash;
for (int i = 0; i < 1000; ++i)
hash.insert(i, i * 10);
// This used to hang in an infinite loop: QTBUG-102067
hash.reserve(1);
// Make sure that hash still has all elements
for (int i = 0; i < 1000; ++i)
QCOMPARE(hash.value(i), i * 10);
}
{
QMultiHash<int, int> hash;
for (int i = 0; i < 1000; ++i) {
hash.insert(i, i * 10);
hash.insert(i, i * 10 + 1);
}
// This used to hang in infinite loop: QTBUG-102067
hash.reserve(1);
// Make sure that hash still has all elements
for (int i = 0; i < 1000; ++i)
QCOMPARE(hash.values(i), QList<int>() << i * 10 + 1 << i * 10);
}
}
void tst_QHash::QTBUG98265()
{
QMultiHash<QUuid, QByteArray> a;