/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** 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 http://www.qt.io/terms-conditions. For further ** information use the contact form at http://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 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QARRAYDATA_H #define QARRAYDATA_H #include #include QT_BEGIN_NAMESPACE struct Q_CORE_EXPORT QArrayData { QtPrivate::RefCount ref; int size; uint alloc : 31; uint capacityReserved : 1; qptrdiff offset; // in bytes from beginning of header void *data() { Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); return reinterpret_cast(this) + offset; } const void *data() const { Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData)); return reinterpret_cast(this) + offset; } // 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 alloc != 0; } enum AllocationOption { CapacityReserved = 0x1, #if QT_SUPPORTS(UNSHARABLE_CONTAINERS) Unsharable = 0x2, #endif RawData = 0x4, Grow = 0x8, Default = 0 }; Q_DECLARE_FLAGS(AllocationOptions, AllocationOption) size_t detachCapacity(size_t newSize) const { if (capacityReserved && newSize < alloc) return alloc; return newSize; } AllocationOptions detachFlags() const { AllocationOptions result; if (capacityReserved) result |= CapacityReserved; return result; } AllocationOptions cloneFlags() const { AllocationOptions result; if (capacityReserved) result |= CapacityReserved; return result; } static QArrayData *allocate(size_t objectSize, size_t alignment, size_t capacity, AllocationOptions options = Default) Q_DECL_NOTHROW Q_REQUIRED_RESULT; static void deallocate(QArrayData *data, size_t objectSize, size_t alignment) Q_DECL_NOTHROW; static const QArrayData shared_null[2]; static QArrayData *sharedNull() Q_DECL_NOTHROW { return const_cast(shared_null); } }; Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocationOptions) 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(0) {} 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); } 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(0) {} 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); } 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 T *data() { return static_cast(QArrayData::data()); } const T *data() const { return static_cast(QArrayData::data()); } iterator begin(iterator = iterator()) { return data(); } iterator end(iterator = iterator()) { return data() + size; } const_iterator begin(const_iterator = const_iterator()) const { return data(); } const_iterator end(const_iterator = const_iterator()) const { return data() + size; } const_iterator constBegin(const_iterator = const_iterator()) const { return data(); } const_iterator constEnd(const_iterator = const_iterator()) const { return data() + size; } class AlignmentDummy { QArrayData header; T data; }; static QTypedArrayData *allocate(size_t capacity, AllocationOptions options = Default) Q_REQUIRED_RESULT { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return static_cast(QArrayData::allocate(sizeof(T), Q_ALIGNOF(AlignmentDummy), capacity, options)); } static void deallocate(QArrayData *data) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy)); } static QTypedArrayData *fromRawData(const T *data, size_t n, AllocationOptions options = Default) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); QTypedArrayData *result = allocate(0, options | RawData); if (result) { Q_ASSERT(!result->ref.isShared()); // No shared empty, please! result->offset = reinterpret_cast(data) - reinterpret_cast(result); result->size = int(n); } return result; } static QTypedArrayData *sharedNull() Q_DECL_NOTHROW { 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 QTypedArrayData *unsharableEmpty() { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return allocate(/* capacity */ 0, Unsharable); } }; template struct QStaticArrayData { QArrayData header; T data[N]; }; // Support for returning QArrayDataPointer from functions template struct QArrayDataPointerRef { QTypedArrayData *ptr; }; #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \ /**/ #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(type, size) \ Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size,\ ((sizeof(QArrayData) + (Q_ALIGNOF(type) - 1)) & ~(Q_ALIGNOF(type) - 1) )) \ /**/ //////////////////////////////////////////////////////////////////////////////// // 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. #if defined(Q_COMPILER_VARIADIC_MACROS) #if defined(Q_COMPILER_LAMBDA) // 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(); \ }()) \ /**/ #endif #endif // defined(Q_COMPILER_VARIADIC_MACROS) #if defined(Q_ARRAY_LITERAL) #define Q_ARRAY_LITERAL_IMPL(Type, ...) \ union { Type type_must_be_POD; } dummy; Q_UNUSED(dummy) \ \ /* Portable compile-time array size computation */ \ Type data[] = { __VA_ARGS__ }; Q_UNUSED(data) \ enum { Size = sizeof(data) / sizeof(data[0]) }; \ \ static const QStaticArrayData literal = { \ Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } }; \ \ QArrayDataPointerRef ref = \ { static_cast *>( \ const_cast(&literal.header)) }; \ /**/ #else // As a fallback, memory is allocated and data copied to the heap. // The fallback macro does NOT use variadic macros and does NOT support // variable number of arguments. It is suitable for char arrays. namespace QtPrivate { template inline QArrayDataPointerRef qMakeArrayLiteral(const T (&array)[N]) { union { T type_must_be_POD; } dummy; Q_UNUSED(dummy) QArrayDataPointerRef result = { QTypedArrayData::allocate(N) }; Q_CHECK_PTR(result.ptr); ::memcpy(result.ptr->data(), array, N * sizeof(T)); result.ptr->size = N; return result; } } #define Q_ARRAY_LITERAL(Type, Array) \ QT_PREPEND_NAMESPACE(QtPrivate::qMakeArrayLiteral)( Array ) #endif // !defined(Q_ARRAY_LITERAL) 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