diff options
Diffstat (limited to 'src/corelib/tools/qarraydata.h')
-rw-r--r-- | src/corelib/tools/qarraydata.h | 238 |
1 files changed, 86 insertions, 152 deletions
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 856a9521ad..da83fc1a21 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -1,75 +1,54 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2019 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2019 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QARRAYDATA_H #define QARRAYDATA_H #include <QtCore/qpair.h> #include <QtCore/qatomic.h> +#include <QtCore/qflags.h> +#include <QtCore/qcontainerfwd.h> #include <string.h> 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; -struct Q_CORE_EXPORT QArrayData +struct QArrayData { - enum ArrayOption { - /// this option is used by the allocate() function - DefaultAllocationFlags = 0, - CapacityReserved = 0x1, //!< the capacity was reserved by the user, try to keep it - GrowsForward = 0x2, //!< allocate with eyes towards growing through append() - GrowsBackwards = 0x4 //!< allocate with eyes towards growing through prepend() + enum AllocationOption { + Grow, + KeepSize + }; + + enum GrowthPosition { + GrowsAtEnd, + GrowsAtBeginning + }; + + enum ArrayOption { + ArrayOptionDefault = 0, + CapacityReserved = 0x1 //!< the capacity was reserved by the user, try to keep it }; Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) QBasicAtomicInt ref_; - uint flags; + ArrayOptions flags; qsizetype alloc; - inline qsizetype allocatedCapacity() noexcept + qsizetype allocatedCapacity() noexcept { return alloc; } - inline qsizetype constAllocatedCapacity() const noexcept + qsizetype constAllocatedCapacity() const noexcept { return alloc; } @@ -95,7 +74,7 @@ struct Q_CORE_EXPORT QArrayData // Returns true if a detach is necessary before modifying the data // This method is intentionally not const: if you want to know whether // detaching is necessary, you should be in a non-const function already - bool needsDetach() const noexcept + bool needsDetach() noexcept { return ref_.loadRelaxed() > 1; } @@ -107,127 +86,74 @@ struct Q_CORE_EXPORT QArrayData return newSize; } - ArrayOptions detachFlags() const noexcept - { - ArrayOptions result = DefaultAllocationFlags; - if (flags & CapacityReserved) - result |= CapacityReserved; - return result; - } - - Q_REQUIRED_RESULT -#if defined(Q_CC_GNU) - __attribute__((__malloc__)) -#endif - 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, - qsizetype objectSize, qsizetype newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept; - static void deallocate(QArrayData *data, qsizetype objectSize, + Q_DECL_MALLOCLIKE + static Q_CORE_EXPORT void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment, + 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 std::pair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer, + qsizetype objectSize, qsizetype newCapacity, AllocationOption option) noexcept; + static Q_CORE_EXPORT void deallocate(QArrayData *data, qsizetype objectSize, qsizetype alignment) noexcept; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions) +namespace QtPrivate { +// QArrayData with strictest alignment requirements supported by malloc() +#if defined(Q_PROCESSOR_X86_32) && defined(Q_CC_GNU) +// GCC's definition is incorrect since GCC 8 (commit r240248 in SVN; commit +// 63012d9a57edc950c5f30242d1e19318b5708060 in Git). This is applied to all +// GCC-like compilers in case they decide to follow GCC's lead in being wrong. +constexpr size_t MaxPrimitiveAlignment = 2 * sizeof(void *); +#else +constexpr size_t MaxPrimitiveAlignment = alignof(std::max_align_t); +#endif + +struct alignas(MaxPrimitiveAlignment) AlignedQArrayData : QArrayData +{ +}; +} + template <class T> struct QTypedArrayData : QArrayData { - class iterator { - T *i = nullptr; - public: - typedef std::random_access_iterator_tag iterator_category; - typedef qsizetype difference_type; - typedef T value_type; - typedef T *pointer; - typedef T &reference; - - inline constexpr iterator() = default; - inline iterator(T *n) : i(n) {} - inline T &operator*() const { return *i; } - inline T *operator->() const { return i; } - inline T &operator[](qsizetype j) const { return *(i + j); } - inline constexpr bool operator==(iterator o) const { return i == o.i; } - inline constexpr bool operator!=(iterator o) const { return i != o.i; } - inline constexpr bool operator<(iterator other) const { return i < other.i; } - inline constexpr bool operator<=(iterator other) const { return i <= other.i; } - inline constexpr bool operator>(iterator other) const { return i > other.i; } - inline constexpr bool operator>=(iterator other) const { return i >= other.i; } - inline constexpr bool operator==(pointer p) const { return i == p; } - inline constexpr bool operator!=(pointer p) const { return i != p; } - inline iterator &operator++() { ++i; return *this; } - inline iterator operator++(int) { T *n = i; ++i; return n; } - inline iterator &operator--() { i--; return *this; } - inline iterator operator--(int) { T *n = i; i--; return n; } - inline iterator &operator+=(qsizetype j) { i+=j; return *this; } - inline iterator &operator-=(qsizetype j) { i-=j; return *this; } - inline iterator operator+(qsizetype j) const { return iterator(i+j); } - inline iterator operator-(qsizetype j) const { return iterator(i-j); } - friend inline iterator operator+(qsizetype j, iterator k) { return k + j; } - inline qsizetype operator-(iterator j) const { return i - j.i; } - inline operator T*() const { return i; } - }; - - class const_iterator { - const T *i = nullptr; - public: - typedef std::random_access_iterator_tag iterator_category; - typedef qsizetype difference_type; - typedef T value_type; - typedef const T *pointer; - typedef const T &reference; - - inline constexpr const_iterator() = default; - inline const_iterator(const T *n) : i(n) {} - inline constexpr const_iterator(iterator o): i(o) {} - inline const T &operator*() const { return *i; } - inline const T *operator->() const { return i; } - inline const T &operator[](qsizetype j) const { return *(i + j); } - inline constexpr bool operator==(const_iterator o) const { return i == o.i; } - inline constexpr bool operator!=(const_iterator o) const { return i != o.i; } - inline constexpr bool operator<(const_iterator other) const { return i < other.i; } - inline constexpr bool operator<=(const_iterator other) const { return i <= other.i; } - inline constexpr bool operator>(const_iterator other) const { return i > other.i; } - inline constexpr bool operator>=(const_iterator other) const { return i >= other.i; } - inline constexpr bool operator==(iterator o) const { return i == const_iterator(o).i; } - inline constexpr bool operator!=(iterator o) const { return i != const_iterator(o).i; } - inline constexpr bool operator==(pointer p) const { return i == p; } - inline constexpr bool operator!=(pointer p) const { return i != p; } - inline const_iterator &operator++() { ++i; return *this; } - inline const_iterator operator++(int) { const T *n = i; ++i; return n; } - inline const_iterator &operator--() { i--; return *this; } - inline const_iterator operator--(int) { const T *n = i; i--; return n; } - inline const_iterator &operator+=(qsizetype j) { i+=j; return *this; } - inline const_iterator &operator-=(qsizetype j) { i-=j; return *this; } - inline const_iterator operator+(qsizetype j) const { return const_iterator(i+j); } - inline const_iterator operator-(qsizetype j) const { return const_iterator(i-j); } - friend inline const_iterator operator+(qsizetype j, const_iterator k) { return k + j; } - inline qsizetype operator-(const_iterator j) const { return i - j.i; } - inline operator const T*() const { return i; } - }; + struct AlignmentDummy { QtPrivate::AlignedQArrayData header; T data; }; - class AlignmentDummy { QArrayData header; T data; }; - - Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(qsizetype capacity, - ArrayOptions options = DefaultAllocationFlags) + [[nodiscard]] static std::pair<QTypedArrayData *, T *> allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize) { static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData)); QArrayData *d; - void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, options); -#if (defined(Q_CC_GNU) && Q_CC_GNU >= 407) || QT_HAS_BUILTIN(__builtin_assume_aligned) + 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) + // and yet we do offer results that have stricter alignment result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy)); #endif - return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result)); + return {static_cast<QTypedArrayData *>(d), static_cast<T *>(result)}; } - static QPair<QTypedArrayData *, T *> - reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity, - ArrayOptions options = DefaultAllocationFlags) + static std::pair<QTypedArrayData *, T *> + reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity, AllocationOption option) { static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData)); - QPair<QArrayData *, void *> pair = - QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, options); - return qMakePair(static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second)); + std::pair<QArrayData *, void *> pair = + QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, option); + return {static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second)}; } static void deallocate(QArrayData *data) noexcept @@ -244,6 +170,12 @@ struct QTypedArrayData (quintptr(data) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1)); return static_cast<T *>(start); } + + constexpr static qsizetype max_size() noexcept + { + // -1 to deal with the pointer one-past-the-end + return (QtPrivate::MaxAllocSize - sizeof(QtPrivate::AlignedQArrayData) - 1) / sizeof(T); + } }; namespace QtPrivate { @@ -284,6 +216,8 @@ struct Q_CORE_EXPORT QContainerImplHelper }; } +#undef Q_DECL_MALLOCLIKE + QT_END_NAMESPACE #endif // include guard |