/**************************************************************************** ** ** Copyright (C) 2016 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$ ** ****************************************************************************/ #ifndef QARRAYDATA_H #define QARRAYDATA_H #include #include #include QT_BEGIN_NAMESPACE template struct QTypedArrayData; struct Q_CORE_EXPORT QArrayData { enum ArrayOption { RawDataType = 0x0001, //!< this class is really a QArrayData AllocatedDataType = 0x0002, //!< this class is really a QArrayAllocatedData DataTypeBits = 0x000f, CapacityReserved = 0x0010, //!< the capacity was reserved by the user, try to keep it GrowsForward = 0x0020, //!< allocate with eyes towards growing through append() GrowsBackwards = 0x0040, //!< allocate with eyes towards growing through prepend() MutableData = 0x0080, //!< the data can be changed; doesn't say anything about the header ImmutableHeader = 0x0100, //!< the header is static, it can't be changed /// this option is used by the Q_ARRAY_LITERAL and similar macros StaticDataFlags = RawDataType | ImmutableHeader, /// this option is used by the allocate() function DefaultAllocationFlags = MutableData, /// this option is used by the prepareRawData() function DefaultRawFlags = 0 }; Q_DECLARE_FLAGS(ArrayOptions, ArrayOption) QBasicAtomicInt ref_; uint flags; uint alloc; inline size_t allocatedCapacity() { return alloc; } inline size_t constAllocatedCapacity() const { return alloc; } /// Returns true if sharing took place bool ref() { if (!isStatic()) ref_.ref(); return true; } /// Returns false if deallocation is necessary bool deref() { if (isStatic()) return true; return ref_.deref(); } // This refers to array data mutability, not "header data" represented by // data members in QArrayData. Shared data (array and header) must still // follow COW principles. bool isMutable() const { return flags & MutableData; } bool isStatic() const { return flags & ImmutableHeader; } bool isShared() const { return ref_.loadRelaxed() != 1; } // 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() { // requires two conditionals return !isMutable() || isShared(); } size_t detachCapacity(size_t newSize) const { if (flags & CapacityReserved && newSize < constAllocatedCapacity()) return constAllocatedCapacity(); return newSize; } ArrayOptions detachFlags() const { ArrayOptions result = DefaultAllocationFlags; if (flags & CapacityReserved) result |= CapacityReserved; return result; } ArrayOptions cloneFlags() const { 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, size_t objectSize, size_t alignment, size_t capacity, ArrayOptions options = DefaultAllocationFlags) noexcept; Q_REQUIRED_RESULT static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize, size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept; Q_REQUIRED_RESULT static QPair reallocateUnaligned(QArrayData *data, void *dataPointer, size_t objectSize, size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) Q_DECL_NOTHROW; Q_REQUIRED_RESULT static QArrayData *prepareRawData(ArrayOptions options = ArrayOptions(RawDataType)) Q_DECL_NOTHROW; static void deallocate(QArrayData *data, size_t objectSize, size_t alignment) noexcept; static const QArrayData shared_null[2]; static QArrayData *sharedNull() noexcept { return const_cast(shared_null); } static void *sharedNullData() { QArrayData *const null = const_cast(&shared_null[1]); return null; } }; Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions) template struct QStaticArrayData { // static arrays are of type RawDataType QArrayData header; T data[N]; }; // Support for returning QArrayDataPointer from functions template struct QArrayDataPointerRef { QTypedArrayData *ptr; T *data; uint size; }; template struct QTypedArrayData : QArrayData { #ifdef QT_STRICT_ITERATORS class iterator { public: T *i; typedef std::random_access_iterator_tag iterator_category; typedef int difference_type; typedef T value_type; typedef T *pointer; typedef T &reference; inline iterator() : i(nullptr) {} inline iterator(T *n) : i(n) {} inline iterator(const iterator &o): i(o.i){} // #### Qt 6: remove, the implicit version is fine inline T &operator*() const { return *i; } inline T *operator->() const { return i; } inline T &operator[](int j) const { return *(i + j); } inline bool operator==(const iterator &o) const { return i == o.i; } inline bool operator!=(const iterator &o) const { return i != o.i; } inline bool operator<(const iterator& other) const { return i < other.i; } inline bool operator<=(const iterator& other) const { return i <= other.i; } inline bool operator>(const iterator& other) const { return i > other.i; } inline bool operator>=(const iterator& other) const { return i >= other.i; } 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+=(int j) { i+=j; return *this; } inline iterator &operator-=(int j) { i-=j; return *this; } inline iterator operator+(int j) const { return iterator(i+j); } inline iterator operator-(int j) const { return iterator(i-j); } friend inline iterator operator+(int j, iterator k) { return k + j; } inline int operator-(iterator j) const { return i - j.i; } inline operator T*() const { return i; } }; friend class iterator; class const_iterator { public: const T *i; typedef std::random_access_iterator_tag iterator_category; typedef int difference_type; typedef T value_type; typedef const T *pointer; typedef const T &reference; inline const_iterator() : i(nullptr) {} inline const_iterator(const T *n) : i(n) {} inline const_iterator(const const_iterator &o): i(o.i) {} // #### Qt 6: remove, the default version is fine inline explicit const_iterator(const iterator &o): i(o.i) {} inline const T &operator*() const { return *i; } inline const T *operator->() const { return i; } inline const T &operator[](int j) const { return *(i + j); } inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline bool operator<(const const_iterator& other) const { return i < other.i; } inline bool operator<=(const const_iterator& other) const { return i <= other.i; } inline bool operator>(const const_iterator& other) const { return i > other.i; } inline bool operator>=(const const_iterator& other) const { return i >= other.i; } 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+=(int j) { i+=j; return *this; } inline const_iterator &operator-=(int j) { i-=j; return *this; } inline const_iterator operator+(int j) const { return const_iterator(i+j); } inline const_iterator operator-(int j) const { return const_iterator(i-j); } friend inline const_iterator operator+(int j, const_iterator k) { return k + j; } inline int operator-(const_iterator j) const { return i - j.i; } inline operator const T*() const { return i; } }; friend class const_iterator; #else typedef T* iterator; typedef const T* const_iterator; #endif class AlignmentDummy { QArrayData header; T data; }; Q_REQUIRED_RESULT static QPair allocate(size_t capacity, ArrayOptions options = DefaultAllocationFlags) { Q_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) result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy)); #endif return qMakePair(static_cast(d), static_cast(result)); } static QPair reallocateUnaligned(QTypedArrayData *data, T *dataPointer, size_t capacity, ArrayOptions options = DefaultAllocationFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QPair pair = QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, options); return qMakePair(static_cast(pair.first), static_cast(pair.second)); } static void deallocate(QArrayData *data) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QArrayData::deallocate(data, sizeof(T), alignof(AlignmentDummy)); } static QArrayDataPointerRef fromRawData(const T *data, size_t n, ArrayOptions options = DefaultRawFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QArrayDataPointerRef result = { static_cast(prepareRawData(options)), const_cast(data), uint(n) }; if (result.ptr) { Q_ASSERT(!result.ptr->isShared()); // No shared empty, please! } return result; } static QTypedArrayData *sharedNull() noexcept { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return static_cast(QArrayData::sharedNull()); } static QTypedArrayData *sharedEmpty() { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return allocate(/* capacity */ 0); } static T *sharedNullData() { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return static_cast(QArrayData::sharedNullData()); } }; //////////////////////////////////////////////////////////////////////////////// // Q_ARRAY_LITERAL // The idea here is to place a (read-only) copy of header and array data in an // mmappable portion of the executable (typically, .rodata section). This is // accomplished by hiding a static const instance of QStaticArrayData, which is // POD. // Hide array inside a lambda #define Q_ARRAY_LITERAL(Type, ...) \ ([]() -> QArrayDataPointerRef { \ /* MSVC 2010 Doesn't support static variables in a lambda, but */ \ /* happily accepts them in a static function of a lambda-local */ \ /* struct :-) */ \ struct StaticWrapper { \ static QArrayDataPointerRef get() \ { \ Q_ARRAY_LITERAL_IMPL(Type, __VA_ARGS__) \ return ref; \ } \ }; \ return StaticWrapper::get(); \ }()) \ /**/ #ifdef Q_COMPILER_CONSTEXPR #define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) Q_STATIC_ASSERT(std::is_literal_type::value) #else #define Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type) do {} while (0) #endif #define Q_ARRAY_LITERAL_IMPL(Type, ...) \ Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type); \ \ /* Portable compile-time array size computation */ \ static Type const data[] = { __VA_ARGS__ }; \ enum { Size = sizeof(data) / sizeof(data[0]) }; \ \ static const QArrayData literal = { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }; \ \ QArrayDataPointerRef ref = \ { static_cast *>( \ const_cast(&literal)), \ const_cast(data), \ Size }; \ /**/ namespace QtPrivate { struct Q_CORE_EXPORT QContainerImplHelper { enum CutResult { Null, Empty, Full, Subset }; static CutResult mid(int originalLength, int *position, int *length); }; } QT_END_NAMESPACE #endif // include guard