Allow allocating more than 2G items in a vector
Also adjust qCalculateBlockSize() to be able to handle large allocations. QVector::length() is currently still limited to 2G items, that will get changed in a later commit. Change-Id: I3a92fbfd7f281d30844c5fafa3b9a474bc347c19 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
ded37aedc9
commit
215ca73534
|
|
@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
|
|||
* containers to allocate memory and grow the memory block during append
|
||||
* operations.
|
||||
*
|
||||
* They take size_t parameters and return size_t so they will change sizes
|
||||
* They take qsizetype parameters and return qsizetype so they will change sizes
|
||||
* according to the pointer width. However, knowing Qt containers store the
|
||||
* container size and element indexes in ints, these functions never return a
|
||||
* size larger than INT_MAX. This is done by casting the element count and
|
||||
|
|
@ -79,29 +79,21 @@ QT_BEGIN_NAMESPACE
|
|||
Both \a elementCount and \a headerSize can be zero, but \a elementSize
|
||||
cannot.
|
||||
|
||||
This function returns SIZE_MAX (~0) on overflow or if the memory block size
|
||||
would not fit an int.
|
||||
This function returns -1 on overflow or if the memory block size
|
||||
would not fit a qsizetype.
|
||||
*/
|
||||
size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t headerSize) noexcept
|
||||
qsizetype qCalculateBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize) noexcept
|
||||
{
|
||||
unsigned count = unsigned(elementCount);
|
||||
unsigned size = unsigned(elementSize);
|
||||
unsigned header = unsigned(headerSize);
|
||||
Q_ASSERT(elementSize);
|
||||
Q_ASSERT(size == elementSize);
|
||||
Q_ASSERT(header == headerSize);
|
||||
|
||||
if (Q_UNLIKELY(count != elementCount))
|
||||
return std::numeric_limits<size_t>::max();
|
||||
size_t bytes;
|
||||
if (Q_UNLIKELY(mul_overflow(size_t(elementSize), size_t(elementCount), &bytes)) ||
|
||||
Q_UNLIKELY(add_overflow(bytes, size_t(headerSize), &bytes)))
|
||||
return -1;
|
||||
if (Q_UNLIKELY(qsizetype(bytes) < 0))
|
||||
return -1;
|
||||
|
||||
unsigned bytes;
|
||||
if (Q_UNLIKELY(mul_overflow(size, count, &bytes)) ||
|
||||
Q_UNLIKELY(add_overflow(bytes, header, &bytes)))
|
||||
return std::numeric_limits<size_t>::max();
|
||||
if (Q_UNLIKELY(int(bytes) < 0)) // catches bytes >= 2GB
|
||||
return std::numeric_limits<size_t>::max();
|
||||
|
||||
return bytes;
|
||||
return qsizetype(bytes);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -116,38 +108,39 @@ size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t heade
|
|||
Both \a elementCount and \a headerSize can be zero, but \a elementSize
|
||||
cannot.
|
||||
|
||||
This function returns SIZE_MAX (~0) on overflow or if the memory block size
|
||||
would not fit an int.
|
||||
This function returns -1 on overflow or if the memory block size
|
||||
would not fit a qsizetype.
|
||||
|
||||
\note The memory block may contain up to \a elementSize - 1 bytes more than
|
||||
needed.
|
||||
*/
|
||||
CalculateGrowingBlockSizeResult
|
||||
qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t headerSize) noexcept
|
||||
qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize) noexcept
|
||||
{
|
||||
CalculateGrowingBlockSizeResult result = {
|
||||
std::numeric_limits<size_t>::max(),std::numeric_limits<size_t>::max()
|
||||
qsizetype(-1), qsizetype(-1)
|
||||
};
|
||||
|
||||
unsigned bytes = unsigned(qCalculateBlockSize(elementCount, elementSize, headerSize));
|
||||
if (int(bytes) < 0) // catches std::numeric_limits<size_t>::max()
|
||||
qsizetype bytes = qCalculateBlockSize(elementCount, elementSize, headerSize);
|
||||
if (bytes < 0)
|
||||
return result;
|
||||
|
||||
unsigned morebytes = qNextPowerOfTwo(bytes);
|
||||
if (Q_UNLIKELY(int(morebytes) < 0)) {
|
||||
// catches morebytes == 2GB
|
||||
size_t morebytes = static_cast<size_t>(qNextPowerOfTwo(quint64(bytes)));
|
||||
if (Q_UNLIKELY(qsizetype(morebytes) < 0)) {
|
||||
// grow by half the difference between bytes and morebytes
|
||||
// this slows the growth and avoids trying to allocate exactly
|
||||
// 2G of memory (on 32bit), something that many OSes can't deliver
|
||||
bytes += (morebytes - bytes) / 2;
|
||||
} else {
|
||||
bytes = morebytes;
|
||||
bytes = qsizetype(morebytes);
|
||||
}
|
||||
|
||||
result.elementCount = (bytes - unsigned(headerSize)) / unsigned(elementSize);
|
||||
result.elementCount = (bytes - headerSize) / elementSize;
|
||||
result.size = result.elementCount * elementSize + headerSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize, uint options)
|
||||
static inline qsizetype calculateBlockSize(qsizetype &capacity, qsizetype objectSize, qsizetype headerSize, uint options)
|
||||
{
|
||||
// Calculate the byte size
|
||||
// allocSize = objectSize * capacity + headerSize, but checked for overflow
|
||||
|
|
@ -161,9 +154,9 @@ static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, siz
|
|||
}
|
||||
}
|
||||
|
||||
static QArrayData *allocateData(size_t allocSize, uint options)
|
||||
static QArrayData *allocateData(qsizetype allocSize, uint options)
|
||||
{
|
||||
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
|
||||
QArrayData *header = static_cast<QArrayData *>(::malloc(size_t(allocSize)));
|
||||
if (header) {
|
||||
header->ref_.storeRelaxed(1);
|
||||
header->flags = options;
|
||||
|
|
@ -172,12 +165,12 @@ static QArrayData *allocateData(size_t allocSize, uint options)
|
|||
return header;
|
||||
}
|
||||
|
||||
void *QArrayData::allocate(QArrayData **dptr, size_t objectSize, size_t alignment,
|
||||
size_t capacity, ArrayOptions options) noexcept
|
||||
void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
|
||||
qsizetype capacity, ArrayOptions options) noexcept
|
||||
{
|
||||
Q_ASSERT(dptr);
|
||||
// Alignment is a power of two
|
||||
Q_ASSERT(alignment >= alignof(QArrayData)
|
||||
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
|
||||
&& !(alignment & (alignment - 1)));
|
||||
|
||||
if (capacity == 0) {
|
||||
|
|
@ -185,26 +178,25 @@ void *QArrayData::allocate(QArrayData **dptr, size_t objectSize, size_t alignmen
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
size_t headerSize = sizeof(QArrayData);
|
||||
qsizetype headerSize = sizeof(QArrayData);
|
||||
const qsizetype headerAlignment = alignof(QArrayData);
|
||||
|
||||
if (alignment > alignof(QArrayData)) {
|
||||
if (alignment > headerAlignment) {
|
||||
// Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
|
||||
// can properly align the data array. This assumes malloc is able to
|
||||
// provide appropriate alignment for the header -- as it should!
|
||||
headerSize += alignment - alignof(QArrayData);
|
||||
headerSize += alignment - headerAlignment;
|
||||
}
|
||||
Q_ASSERT(headerSize > 0);
|
||||
|
||||
if (headerSize > size_t(MaxAllocSize))
|
||||
return nullptr;
|
||||
|
||||
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
|
||||
qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
|
||||
QArrayData *header = allocateData(allocSize, options);
|
||||
quintptr data = 0;
|
||||
if (header) {
|
||||
// find where offset should point to so that data() is aligned to alignment bytes
|
||||
data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
|
||||
& ~(alignment - 1);
|
||||
header->alloc = uint(capacity);
|
||||
header->alloc = qsizetype(capacity);
|
||||
}
|
||||
|
||||
*dptr = header;
|
||||
|
|
@ -213,12 +205,12 @@ void *QArrayData::allocate(QArrayData **dptr, size_t objectSize, size_t alignmen
|
|||
|
||||
QPair<QArrayData *, void *>
|
||||
QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
|
||||
size_t objectSize, size_t capacity, ArrayOptions options) noexcept
|
||||
qsizetype objectSize, qsizetype capacity, ArrayOptions options) noexcept
|
||||
{
|
||||
Q_ASSERT(!data || !data->isShared());
|
||||
|
||||
size_t headerSize = sizeof(QArrayData);
|
||||
size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
|
||||
qsizetype headerSize = sizeof(QArrayData);
|
||||
qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
|
||||
qptrdiff offset = dataPointer ? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data) : headerSize;
|
||||
QArrayData *header = static_cast<QArrayData *>(::realloc(data, size_t(allocSize)));
|
||||
if (header) {
|
||||
|
|
@ -229,11 +221,11 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
|
|||
return qMakePair(static_cast<QArrayData *>(header), dataPointer);
|
||||
}
|
||||
|
||||
void QArrayData::deallocate(QArrayData *data, size_t objectSize,
|
||||
size_t alignment) noexcept
|
||||
void QArrayData::deallocate(QArrayData *data, qsizetype objectSize,
|
||||
qsizetype alignment) noexcept
|
||||
{
|
||||
// Alignment is a power of two
|
||||
Q_ASSERT(alignment >= alignof(QArrayData)
|
||||
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
|
||||
&& !(alignment & (alignment - 1)));
|
||||
Q_UNUSED(objectSize);
|
||||
Q_UNUSED(alignment);
|
||||
|
|
|
|||
|
|
@ -62,14 +62,14 @@ struct Q_CORE_EXPORT QArrayData
|
|||
|
||||
QBasicAtomicInt ref_;
|
||||
uint flags;
|
||||
uint alloc;
|
||||
qsizetype alloc;
|
||||
|
||||
inline size_t allocatedCapacity() noexcept
|
||||
inline qsizetype allocatedCapacity() noexcept
|
||||
{
|
||||
return alloc;
|
||||
}
|
||||
|
||||
inline size_t constAllocatedCapacity() const noexcept
|
||||
inline qsizetype constAllocatedCapacity() const noexcept
|
||||
{
|
||||
return alloc;
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ struct Q_CORE_EXPORT QArrayData
|
|||
return ref_.loadRelaxed() > 1;
|
||||
}
|
||||
|
||||
size_t detachCapacity(size_t newSize) const noexcept
|
||||
qsizetype detachCapacity(qsizetype newSize) const noexcept
|
||||
{
|
||||
if (flags & CapacityReserved && newSize < constAllocatedCapacity())
|
||||
return constAllocatedCapacity();
|
||||
|
|
@ -119,12 +119,12 @@ struct Q_CORE_EXPORT QArrayData
|
|||
#if defined(Q_CC_GNU)
|
||||
__attribute__((__malloc__))
|
||||
#endif
|
||||
static void *allocate(QArrayData **pdata, size_t objectSize, size_t alignment,
|
||||
size_t capacity, ArrayOptions options = DefaultAllocationFlags) noexcept;
|
||||
static void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
|
||||
qsizetype capacity, ArrayOptions options = DefaultAllocationFlags) noexcept;
|
||||
Q_REQUIRED_RESULT static QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
|
||||
size_t objectSize, size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) Q_DECL_NOTHROW;
|
||||
static void deallocate(QArrayData *data, size_t objectSize,
|
||||
size_t alignment) noexcept;
|
||||
qsizetype objectSize, qsizetype newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept;
|
||||
static void deallocate(QArrayData *data, qsizetype objectSize,
|
||||
qsizetype alignment) noexcept;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions)
|
||||
|
|
@ -202,7 +202,7 @@ struct QTypedArrayData
|
|||
|
||||
class AlignmentDummy { QArrayData header; T data; };
|
||||
|
||||
Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(size_t capacity,
|
||||
Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(qsizetype capacity,
|
||||
ArrayOptions options = DefaultAllocationFlags)
|
||||
{
|
||||
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
|
||||
|
|
@ -215,7 +215,7 @@ struct QTypedArrayData
|
|||
}
|
||||
|
||||
static QPair<QTypedArrayData *, T *>
|
||||
reallocateUnaligned(QTypedArrayData *data, T *dataPointer, size_t capacity,
|
||||
reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity,
|
||||
ArrayOptions options = DefaultAllocationFlags)
|
||||
{
|
||||
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
|
||||
|
|
|
|||
|
|
@ -88,19 +88,19 @@ Q_DECL_CONSTEXPR inline int fromOct(uint c) noexcept
|
|||
|
||||
// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size.
|
||||
enum {
|
||||
MaxAllocSize = INT_MAX
|
||||
MaxAllocSize = (std::numeric_limits<int>::max)()
|
||||
};
|
||||
|
||||
struct CalculateGrowingBlockSizeResult {
|
||||
size_t size;
|
||||
size_t elementCount;
|
||||
qsizetype size;
|
||||
qsizetype elementCount;
|
||||
};
|
||||
|
||||
// Implemented in qarraydata.cpp:
|
||||
size_t Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
|
||||
qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t headerSize = 0) noexcept;
|
||||
qsizetype Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
|
||||
qCalculateBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize = 0) noexcept;
|
||||
CalculateGrowingBlockSizeResult Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
|
||||
qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t headerSize = 0) noexcept ;
|
||||
qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizetype headerSize = 0) noexcept ;
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
|
|
|||
|
|
@ -1446,53 +1446,62 @@ void tst_QByteArray::toULongLong()
|
|||
QCOMPARE(b, ok);
|
||||
}
|
||||
|
||||
static bool checkSize(size_t value, size_t min)
|
||||
static bool checkSize(qsizetype value, qsizetype min)
|
||||
{
|
||||
return value >= min && value <= INT_MAX;
|
||||
return value >= min && value <= std::numeric_limits<qsizetype>::max();
|
||||
}
|
||||
|
||||
// global functions defined in qbytearray.cpp
|
||||
void tst_QByteArray::blockSizeCalculations()
|
||||
{
|
||||
qsizetype MaxAllocSize = std::numeric_limits<qsizetype>::max();
|
||||
|
||||
// Not very important, but please behave :-)
|
||||
QCOMPARE(qCalculateBlockSize(0, 1), size_t(0));
|
||||
QCOMPARE(qCalculateBlockSize(0, 1), qsizetype(0));
|
||||
QVERIFY(qCalculateGrowingBlockSize(0, 1).size <= MaxAllocSize);
|
||||
QVERIFY(qCalculateGrowingBlockSize(0, 1).elementCount <= MaxAllocSize);
|
||||
|
||||
// boundary condition
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize, 1), size_t(MaxAllocSize));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/2, 2), size_t(MaxAllocSize) - 1);
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/2, 2, 1), size_t(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize, 1).size, size_t(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize, 1).elementCount, size_t(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2, 2, 1).size, size_t(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2, 2, 1).elementCount, size_t(MaxAllocSize)/2);
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize, 1), qsizetype(MaxAllocSize));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/2, 2), qsizetype(MaxAllocSize) - 1);
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/2, 2, 1), qsizetype(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize, 1).size, qsizetype(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize, 1).elementCount, qsizetype(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2, 2, 1).size, qsizetype(MaxAllocSize));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2, 2, 1).elementCount, qsizetype(MaxAllocSize)/2);
|
||||
|
||||
// error conditions
|
||||
QCOMPARE(qCalculateBlockSize(uint(MaxAllocSize) + 1, 1), size_t(~0));
|
||||
QCOMPARE(qCalculateBlockSize(size_t(-1), 1), size_t(~0));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize, 1, 1), size_t(~0));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/2 + 1, 2), size_t(~0));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(uint(MaxAllocSize) + 1, 1).size, size_t(~0));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2 + 1, 2).size, size_t(~0));
|
||||
QCOMPARE(qCalculateBlockSize(qint64(MaxAllocSize) + 1, 1), qsizetype(-1));
|
||||
QCOMPARE(qCalculateBlockSize(qsizetype(-1), 1), qsizetype(-1));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize, 1, 1), qsizetype(-1));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/2 + 1, 2), qsizetype(-1));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(quint64(MaxAllocSize) + 1, 1).size, qsizetype(-1));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2 + 1, 2).size, qsizetype(-1));
|
||||
|
||||
// overflow conditions
|
||||
#if QT_POINTER_SIZE == 4
|
||||
// on 32-bit platforms, (1 << 16) * (1 << 16) = (1 << 32) which is zero
|
||||
QCOMPARE(qCalculateBlockSize(1 << 16, 1 << 16), size_t(~0));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/4, 16), size_t(~0));
|
||||
QCOMPARE(qCalculateBlockSize(1 << 16, 1 << 16), qsizetype(-1));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/4, 16), qsizetype(-1));
|
||||
// on 32-bit platforms, (1 << 30) * 3 + (1 << 30) would overflow to zero
|
||||
QCOMPARE(qCalculateBlockSize(1U << 30, 3, 1U << 30), size_t(~0));
|
||||
|
||||
QCOMPARE(qCalculateBlockSize(1U << 30, 3, 1U << 30), qsizetype(-1));
|
||||
#else
|
||||
// on 64-bit platforms, (1 << 32) * (1 << 32) = (1 << 64) which is zero
|
||||
QCOMPARE(qCalculateBlockSize(1LL << 32, 1LL << 32), qsizetype(-1));
|
||||
QCOMPARE(qCalculateBlockSize(MaxAllocSize/4, 16), qsizetype(-1));
|
||||
// on 64-bit platforms, (1 << 30) * 3 + (1 << 30) would overflow to zero
|
||||
QCOMPARE(qCalculateBlockSize(1ULL << 62, 3, 1ULL << 62), qsizetype(-1));
|
||||
#endif
|
||||
// exact block sizes
|
||||
for (int i = 1; i < 1 << 31; i <<= 1) {
|
||||
QCOMPARE(qCalculateBlockSize(0, 1, i), size_t(i));
|
||||
QCOMPARE(qCalculateBlockSize(i, 1), size_t(i));
|
||||
QCOMPARE(qCalculateBlockSize(i + i/2, 1), size_t(i + i/2));
|
||||
QCOMPARE(qCalculateBlockSize(0, 1, i), qsizetype(i));
|
||||
QCOMPARE(qCalculateBlockSize(i, 1), qsizetype(i));
|
||||
QCOMPARE(qCalculateBlockSize(i + i/2, 1), qsizetype(i + i/2));
|
||||
}
|
||||
for (int i = 1; i < 1 << 30; i <<= 1) {
|
||||
QCOMPARE(qCalculateBlockSize(i, 2), 2 * size_t(i));
|
||||
QCOMPARE(qCalculateBlockSize(i, 2, 1), 2 * size_t(i) + 1);
|
||||
QCOMPARE(qCalculateBlockSize(i, 2, 16), 2 * size_t(i) + 16);
|
||||
QCOMPARE(qCalculateBlockSize(i, 2), 2 * qsizetype(i));
|
||||
QCOMPARE(qCalculateBlockSize(i, 2, 1), 2 * qsizetype(i) + 1);
|
||||
QCOMPARE(qCalculateBlockSize(i, 2, 16), 2 * qsizetype(i) + 16);
|
||||
}
|
||||
|
||||
// growing sizes
|
||||
|
|
@ -1507,19 +1516,19 @@ void tst_QByteArray::blockSizeCalculations()
|
|||
|
||||
// growth should be limited
|
||||
for (int elementSize = 1; elementSize < (1<<8); elementSize <<= 1) {
|
||||
size_t alloc = 1;
|
||||
qsizetype alloc = 1;
|
||||
forever {
|
||||
QVERIFY(checkSize(qCalculateGrowingBlockSize(alloc, elementSize).size, alloc * elementSize));
|
||||
size_t newAlloc = qCalculateGrowingBlockSize(alloc, elementSize).elementCount;
|
||||
qsizetype newAlloc = qCalculateGrowingBlockSize(alloc, elementSize).elementCount;
|
||||
QVERIFY(checkSize(newAlloc, alloc));
|
||||
if (newAlloc == alloc)
|
||||
break; // no growth, we're at limit
|
||||
alloc = newAlloc;
|
||||
}
|
||||
QVERIFY(checkSize(alloc, size_t(MaxAllocSize) / elementSize));
|
||||
QVERIFY(checkSize(alloc, qsizetype(MaxAllocSize) / elementSize));
|
||||
|
||||
// the next allocation should be invalid
|
||||
QCOMPARE(qCalculateGrowingBlockSize(alloc + 1, elementSize).size, size_t(~0));
|
||||
QCOMPARE(qCalculateGrowingBlockSize(alloc + 1, elementSize).size, qsizetype(-1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue