QArrayData: add allocate1 and allocate2 for 1- and 2-byte types
This makes the two most-often used QTypedArrayData::allocate() -- the ones for char (for QByteArray) and char16_t (for QString) -- go to specialized versions, which have much simpler code. After all, multiplications by 1 are quite trivial. I didn't check whether an LTO compiler was const-propagating the sizes in inlined calls from qstring.cpp and qbytearray.cpp. But not everyone uses LTO, so this benefits everyone, in a very hot path, for minimal cost. Change-Id: Ifa1111900d6945ea8e05fffd177dd1ce659b3fd5 Reviewed-by: Marc Mutz <marc.mutz@qt.io> (cherry picked from commit 4d7864f0517679ebe70a2a96afdae5dc4f5a2d62) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
377066e407
commit
5d534ee9a9
@ -151,21 +151,19 @@ namespace {
|
|||||||
struct alignas(std::max_align_t) AlignedQArrayData : QArrayData
|
struct alignas(std::max_align_t) AlignedQArrayData : QArrayData
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AllocationResult {
|
||||||
|
void *data;
|
||||||
|
QArrayData *header;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline AllocationResult
|
||||||
void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
|
allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
|
||||||
qsizetype capacity, QArrayData::AllocationOption option) noexcept
|
QArrayData::AllocationOption option) noexcept
|
||||||
{
|
{
|
||||||
Q_ASSERT(dptr);
|
if (capacity == 0)
|
||||||
// Alignment is a power of two
|
return {};
|
||||||
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
|
|
||||||
&& !(alignment & (alignment - 1)));
|
|
||||||
|
|
||||||
if (capacity == 0) {
|
|
||||||
*dptr = nullptr;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsizetype headerSize = sizeof(AlignedQArrayData);
|
qsizetype headerSize = sizeof(AlignedQArrayData);
|
||||||
const qsizetype headerAlignment = alignof(AlignedQArrayData);
|
const qsizetype headerAlignment = alignof(AlignedQArrayData);
|
||||||
@ -181,10 +179,8 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
|
|||||||
auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option);
|
auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option);
|
||||||
capacity = blockSize.elementCount;
|
capacity = blockSize.elementCount;
|
||||||
qsizetype allocSize = blockSize.size;
|
qsizetype allocSize = blockSize.size;
|
||||||
if (Q_UNLIKELY(allocSize < 0)) { // handle overflow. cannot allocate reliably
|
if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot allocate reliably
|
||||||
*dptr = nullptr;
|
return {};
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QArrayData *header = allocateData(allocSize);
|
QArrayData *header = allocateData(allocSize);
|
||||||
void *data = nullptr;
|
void *data = nullptr;
|
||||||
@ -194,8 +190,40 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
|
|||||||
header->alloc = qsizetype(capacity);
|
header->alloc = qsizetype(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
*dptr = header;
|
return { data, header };
|
||||||
return data;
|
}
|
||||||
|
|
||||||
|
// Generic size and alignment allocation function
|
||||||
|
void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
|
||||||
|
qsizetype capacity, AllocationOption option) noexcept
|
||||||
|
{
|
||||||
|
Q_ASSERT(dptr);
|
||||||
|
// Alignment is a power of two
|
||||||
|
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
|
||||||
|
&& !(alignment & (alignment - 1)));
|
||||||
|
|
||||||
|
auto r = allocateHelper(objectSize, alignment, capacity, option);
|
||||||
|
*dptr = r.header;
|
||||||
|
return r.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed size and alignment allocation functions
|
||||||
|
void *QArrayData::allocate1(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
|
||||||
|
{
|
||||||
|
Q_ASSERT(dptr);
|
||||||
|
|
||||||
|
auto r = allocateHelper(1, alignof(AlignedQArrayData), capacity, option);
|
||||||
|
*dptr = r.header;
|
||||||
|
return r.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *QArrayData::allocate2(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
|
||||||
|
{
|
||||||
|
Q_ASSERT(dptr);
|
||||||
|
|
||||||
|
auto r = allocateHelper(2, alignof(AlignedQArrayData), capacity, option);
|
||||||
|
*dptr = r.header;
|
||||||
|
return r.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QArrayData *, void *>
|
QPair<QArrayData *, void *>
|
||||||
|
@ -11,6 +11,12 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#if __has_cpp_attribute(gnu::malloc)
|
||||||
|
# define Q_DECL_MALLOCLIKE [[nodiscard, gnu::malloc]]
|
||||||
|
#else
|
||||||
|
# define Q_DECL_MALLOCLIKE [[nodiscard]]
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class T> struct QTypedArrayData;
|
template <class T> struct QTypedArrayData;
|
||||||
|
|
||||||
struct QArrayData
|
struct QArrayData
|
||||||
@ -78,12 +84,16 @@ struct QArrayData
|
|||||||
return newSize;
|
return newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
Q_DECL_MALLOCLIKE
|
||||||
#if defined(Q_CC_GNU)
|
|
||||||
__attribute__((__malloc__))
|
|
||||||
#endif
|
|
||||||
static Q_CORE_EXPORT void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
|
static Q_CORE_EXPORT void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
|
||||||
qsizetype capacity, AllocationOption option = QArrayData::KeepSize) noexcept;
|
qsizetype capacity, AllocationOption option = QArrayData::KeepSize) noexcept;
|
||||||
|
Q_DECL_MALLOCLIKE
|
||||||
|
static Q_CORE_EXPORT void *allocate1(QArrayData **pdata, qsizetype capacity,
|
||||||
|
AllocationOption option = QArrayData::KeepSize) noexcept;
|
||||||
|
Q_DECL_MALLOCLIKE
|
||||||
|
static Q_CORE_EXPORT void *allocate2(QArrayData **pdata, qsizetype capacity,
|
||||||
|
AllocationOption option = QArrayData::KeepSize) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] static Q_CORE_EXPORT QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
|
[[nodiscard]] static Q_CORE_EXPORT QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
|
||||||
qsizetype objectSize, qsizetype newCapacity, AllocationOption option) noexcept;
|
qsizetype objectSize, qsizetype newCapacity, AllocationOption option) noexcept;
|
||||||
static Q_CORE_EXPORT void deallocate(QArrayData *data, qsizetype objectSize,
|
static Q_CORE_EXPORT void deallocate(QArrayData *data, qsizetype objectSize,
|
||||||
@ -102,8 +112,18 @@ struct QTypedArrayData
|
|||||||
{
|
{
|
||||||
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
|
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
|
||||||
QArrayData *d;
|
QArrayData *d;
|
||||||
void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option);
|
void *result;
|
||||||
|
if constexpr (sizeof(T) == 1) {
|
||||||
|
// necessarily, alignof(T) == 1
|
||||||
|
result = allocate1(&d, capacity, option);
|
||||||
|
} else if constexpr (sizeof(T) == 2) {
|
||||||
|
// alignof(T) may be 1, but that makes no difference
|
||||||
|
result = allocate2(&d, capacity, option);
|
||||||
|
} else {
|
||||||
|
result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option);
|
||||||
|
}
|
||||||
#if __has_builtin(__builtin_assume_aligned)
|
#if __has_builtin(__builtin_assume_aligned)
|
||||||
|
// and yet we do offer results that have stricter alignment
|
||||||
result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy));
|
result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy));
|
||||||
#endif
|
#endif
|
||||||
return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result));
|
return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result));
|
||||||
@ -172,6 +192,8 @@ struct Q_CORE_EXPORT QContainerImplHelper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef Q_DECL_MALLOCLIKE
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // include guard
|
#endif // include guard
|
||||||
|
Loading…
x
Reference in New Issue
Block a user