| /**************************************************************************** |
| ** |
| ** 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 <QtCore/qrefcount.h> |
| #include <string.h> |
| |
| 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<char *>(this) + offset; |
| } |
| |
| const void *data() const |
| { |
| Q_ASSERT(size == 0 |
| || offset < 0 || size_t(offset) >= sizeof(QArrayData)); |
| return reinterpret_cast<const char *>(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<QArrayData*>(shared_null); } |
| }; |
| |
| Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocationOptions) |
| |
| template <class T> |
| 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<T *>(QArrayData::data()); } |
| const T *data() const { return static_cast<const T *>(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<QTypedArrayData *>(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<const char *>(data) |
| - reinterpret_cast<const char *>(result); |
| result->size = int(n); |
| } |
| return result; |
| } |
| |
| static QTypedArrayData *sharedNull() Q_DECL_NOTHROW |
| { |
| Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); |
| return static_cast<QTypedArrayData *>(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 <class T, size_t N> |
| struct QStaticArrayData |
| { |
| QArrayData header; |
| T data[N]; |
| }; |
| |
| // Support for returning QArrayDataPointer<T> from functions |
| template <class T> |
| struct QArrayDataPointerRef |
| { |
| QTypedArrayData<T> *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<Type> { \ |
| /* 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<Type> 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<Type, Size> literal = { \ |
| Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } }; \ |
| \ |
| QArrayDataPointerRef<Type> ref = \ |
| { static_cast<QTypedArrayData<Type> *>( \ |
| const_cast<QArrayData *>(&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 <class T, size_t N> |
| inline QArrayDataPointerRef<T> qMakeArrayLiteral(const T (&array)[N]) |
| { |
| union { T type_must_be_POD; } dummy; Q_UNUSED(dummy) |
| |
| QArrayDataPointerRef<T> result = { QTypedArrayData<T>::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)<Type>( 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 |