Move container block-size calculations to qarraydata.cpp
These were in qbytearray.cpp, which doesn't use them, is big and I intend to move it to a different directory than the header, qtools_p.h, that declares them. So move them to a small file that does use them. Change-Id: I5a4684f8c7628e617546019cc3f01d92d829f085 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
parent
a3b931e7c4
commit
c7e6407f84
|
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
|
|
@ -41,11 +41,114 @@
|
|||
#include <QtCore/qarraydata.h>
|
||||
#include <QtCore/private/qnumeric_p.h>
|
||||
#include <QtCore/private/qtools_p.h>
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*
|
||||
* This pair of functions is declared in qtools_p.h and is used by the Qt
|
||||
* 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
|
||||
* 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
|
||||
* memory block size to int in several comparisons: the check for negative is
|
||||
* very fast on most platforms as the code only needs to check the sign bit.
|
||||
*
|
||||
* These functions return SIZE_MAX on overflow, which can be passed to malloc()
|
||||
* and will surely cause a NULL return (there's no way you can allocate a
|
||||
* memory block the size of your entire VM space).
|
||||
*/
|
||||
|
||||
/*!
|
||||
\internal
|
||||
\since 5.7
|
||||
|
||||
Returns the memory block size for a container containing \a elementCount
|
||||
elements, each of \a elementSize bytes, plus a header of \a headerSize
|
||||
bytes. That is, this function returns \c
|
||||
{elementCount * elementSize + headerSize}
|
||||
|
||||
but unlike the simple calculation, it checks for overflows during the
|
||||
multiplication and the addition.
|
||||
|
||||
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.
|
||||
*/
|
||||
size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t 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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
\since 5.7
|
||||
|
||||
Returns the memory block size and the number of elements that will fit in
|
||||
that block for a container containing \a elementCount elements, each of \a
|
||||
elementSize bytes, plus a header of \a headerSize bytes. This function
|
||||
assumes the container will grow and pre-allocates a growth factor.
|
||||
|
||||
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.
|
||||
|
||||
\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
|
||||
{
|
||||
CalculateGrowingBlockSizeResult result = {
|
||||
std::numeric_limits<size_t>::max(),std::numeric_limits<size_t>::max()
|
||||
};
|
||||
|
||||
unsigned bytes = unsigned(qCalculateBlockSize(elementCount, elementSize, headerSize));
|
||||
if (int(bytes) < 0) // catches std::numeric_limits<size_t>::max()
|
||||
return result;
|
||||
|
||||
unsigned morebytes = qNextPowerOfTwo(bytes);
|
||||
if (Q_UNLIKELY(int(morebytes) < 0)) {
|
||||
// catches morebytes == 2GB
|
||||
// grow by half the difference between bytes and morebytes
|
||||
bytes += (morebytes - bytes) / 2;
|
||||
} else {
|
||||
bytes = morebytes;
|
||||
}
|
||||
|
||||
result.elementCount = (bytes - unsigned(headerSize)) / unsigned(elementSize);
|
||||
result.size = bytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
// End of qtools_p.h implementation
|
||||
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
|
|
@ -130,106 +130,6 @@ int qFindByteArray(
|
|||
const char *haystack0, int haystackLen, int from,
|
||||
const char *needle0, int needleLen);
|
||||
|
||||
/*
|
||||
* This pair of functions is declared in qtools_p.h and is used by the Qt
|
||||
* 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
|
||||
* 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
|
||||
* memory block size to int in several comparisons: the check for negative is
|
||||
* very fast on most platforms as the code only needs to check the sign bit.
|
||||
*
|
||||
* These functions return SIZE_MAX on overflow, which can be passed to malloc()
|
||||
* and will surely cause a NULL return (there's no way you can allocate a
|
||||
* memory block the size of your entire VM space).
|
||||
*/
|
||||
|
||||
/*!
|
||||
\internal
|
||||
\since 5.7
|
||||
|
||||
Returns the memory block size for a container containing \a elementCount
|
||||
elements, each of \a elementSize bytes, plus a header of \a headerSize
|
||||
bytes. That is, this function returns \c
|
||||
{elementCount * elementSize + headerSize}
|
||||
|
||||
but unlike the simple calculation, it checks for overflows during the
|
||||
multiplication and the addition.
|
||||
|
||||
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.
|
||||
*/
|
||||
size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t 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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
\since 5.7
|
||||
|
||||
Returns the memory block size and the number of elements that will fit in
|
||||
that block for a container containing \a elementCount elements, each of \a
|
||||
elementSize bytes, plus a header of \a headerSize bytes. This function
|
||||
assumes the container will grow and pre-allocates a growth factor.
|
||||
|
||||
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.
|
||||
|
||||
\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
|
||||
{
|
||||
CalculateGrowingBlockSizeResult result = {
|
||||
std::numeric_limits<size_t>::max(),std::numeric_limits<size_t>::max()
|
||||
};
|
||||
|
||||
unsigned bytes = unsigned(qCalculateBlockSize(elementCount, elementSize, headerSize));
|
||||
if (int(bytes) < 0) // catches std::numeric_limits<size_t>::max()
|
||||
return result;
|
||||
|
||||
unsigned morebytes = qNextPowerOfTwo(bytes);
|
||||
if (Q_UNLIKELY(int(morebytes) < 0)) {
|
||||
// catches morebytes == 2GB
|
||||
// grow by half the difference between bytes and morebytes
|
||||
bytes += (morebytes - bytes) / 2;
|
||||
} else {
|
||||
bytes = morebytes;
|
||||
}
|
||||
|
||||
result.elementCount = (bytes - unsigned(headerSize)) / unsigned(elementSize);
|
||||
result.size = bytes;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Safe and portable C string functions; extensions to standard string.h
|
||||
*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
|
|
@ -96,7 +96,7 @@ struct CalculateGrowingBlockSizeResult {
|
|||
size_t elementCount;
|
||||
};
|
||||
|
||||
// implemented in qbytearray.cpp
|
||||
// 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;
|
||||
CalculateGrowingBlockSizeResult Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
|
||||
|
|
|
|||
Loading…
Reference in New Issue