Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-07 10:16:05

0001 // Copyright (C) 2025 Aurélien Brooke <aurelien@bahiasoft.fr>
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QALLOC_H
0005 #define QALLOC_H
0006 
0007 //
0008 //  W A R N I N G
0009 //  -------------
0010 //
0011 // This file is not part of the Qt API.  It exists purely as an
0012 // implementation detail.  This header file may change from version to
0013 // version without notice, or even be removed.
0014 //
0015 // We mean it.
0016 //
0017 
0018 #include <QtCore/qtconfigmacros.h>
0019 #include <QtCore/qtcoreexports.h>
0020 #include <QtCore/qnumeric.h>
0021 #include <QtCore/qtypeinfo.h>
0022 
0023 #include <cstddef>
0024 
0025 QT_BEGIN_NAMESPACE
0026 
0027 namespace QtPrivate {
0028 
0029 /**
0030  * \internal
0031  * \return the size that would be allocated for the given request.
0032  *
0033  * Computes the actual allocation size for \a allocSize and \a alignment,
0034  * as determined by the active allocator, without performing the allocation.
0035  *
0036  * In practice, it only returns nonzero when using jemalloc.
0037  */
0038 Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
0039 size_t expectedAllocSize(size_t allocSize, size_t alignment) noexcept;
0040 
0041 /**
0042  * \internal
0043  * \brief Computes the best allocation size for the requested minimum capacity, and updates capacity.
0044  *
0045  * Computes the allocation size starting from \a headerSize and a requested minimum capacity in \a capacity,
0046  * multiplied by the \a elementSize and adjusted by the \a unusedCapacity.
0047  * The final capacity is written back into \a capacity.
0048  * The \a headerSize and \a unusedCapacity values are not included in the final reported capacity.
0049  */
0050 inline size_t fittedAllocSize(size_t headerSize, size_t *capacity,
0051                               size_t elementSize, size_t unusedCapacity, size_t alignment) noexcept
0052 {
0053     size_t totalCapacity = 0; // = capacity + unusedCapacity
0054     if (Q_UNLIKELY(qAddOverflow(*capacity, unusedCapacity, &totalCapacity)))
0055         return 0; // or handle error
0056 
0057     size_t payloadSize = 0; // = totalCapacity * elementSize
0058     if (Q_UNLIKELY(qMulOverflow(totalCapacity, elementSize, &payloadSize)))
0059         return 0;
0060 
0061     size_t allocSize = 0; // = headerSize + payloadSize
0062     if (Q_UNLIKELY(qAddOverflow(headerSize, payloadSize, &allocSize)))
0063         return 0;
0064 
0065     if (size_t fittedSize = expectedAllocSize(allocSize, alignment); fittedSize != 0) {
0066         // no need to overflow/underflow check from fittedSize,
0067         // since allocSize <= fittedSize <= SIZE_T_MAX
0068         *capacity = (fittedSize - headerSize) / elementSize - unusedCapacity;
0069         size_t newTotalCapacity = *capacity + unusedCapacity;
0070         size_t newPayloadSize = newTotalCapacity * elementSize;
0071         return headerSize + newPayloadSize;
0072     }
0073 
0074     return allocSize;
0075 }
0076 
0077 #ifdef Q_CC_GNU
0078 __attribute__((malloc))
0079 #endif
0080 inline void *fittedMalloc(size_t headerSize, size_t *capacity,
0081                           size_t elementSize, size_t unusedCapacity) noexcept
0082 {
0083     size_t allocSize = fittedAllocSize(headerSize, capacity,
0084                                        elementSize, unusedCapacity, alignof(std::max_align_t));
0085     if (Q_LIKELY(allocSize != 0))
0086         return malloc(allocSize);
0087     else
0088         return nullptr;
0089 }
0090 inline void *fittedMalloc(size_t headerSize, qsizetype *capacity,
0091                           size_t elementSize, size_t unusedCapacity = 0) noexcept
0092 {
0093     size_t uCapacity = size_t(*capacity);
0094     void *ptr = fittedMalloc(headerSize, &uCapacity, elementSize, unusedCapacity);
0095     *capacity = qsizetype(uCapacity);
0096     return ptr;
0097 }
0098 
0099 inline void *fittedRealloc(void *ptr, size_t headerSize, size_t *capacity,
0100                            size_t elementSize, size_t unusedCapacity) noexcept
0101 {
0102     size_t newCapacity = *capacity;
0103     size_t allocSize = fittedAllocSize(headerSize, &newCapacity,
0104                                        elementSize, unusedCapacity, alignof(std::max_align_t));
0105     if (Q_LIKELY(allocSize != 0)) {
0106         void *newPtr = realloc(ptr, allocSize);
0107         if (newPtr)
0108             *capacity = newCapacity;
0109         return newPtr;
0110     } else {
0111         return nullptr;
0112     }
0113 }
0114 inline void *fittedRealloc(void *ptr, size_t headerSize, qsizetype *capacity,
0115                            size_t elementSize, size_t unusedCapacity = 0) noexcept
0116 {
0117     size_t uCapacity = size_t(*capacity);
0118     ptr = fittedRealloc(ptr, headerSize, &uCapacity, elementSize, unusedCapacity);
0119     *capacity = qsizetype(uCapacity);
0120     return ptr;
0121 }
0122 
0123 Q_CORE_EXPORT void sizedFree(void *ptr, size_t allocSize) noexcept;
0124 inline void sizedFree(void *ptr, size_t capacity, size_t elementSize) noexcept
0125 {
0126     sizedFree(ptr, capacity * elementSize);
0127 }
0128 
0129 } // namespace QtPrivate
0130 
0131 QT_END_NAMESPACE
0132 
0133 #endif // QALLOC_H