diff options
Diffstat (limited to 'src/corelib/tools/qarraydata.h')
-rw-r--r-- | src/corelib/tools/qarraydata.h | 304 |
1 files changed, 135 insertions, 169 deletions
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index dcd95924c1..d996b9c56b 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** 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. @@ -40,32 +41,64 @@ #ifndef QARRAYDATA_H #define QARRAYDATA_H -#include <QtCore/qrefcount.h> +#include <QtCore/qpair.h> +#include <QtCore/qatomic.h> #include <string.h> QT_BEGIN_NAMESPACE +template <class T> struct QTypedArrayData; + struct Q_CORE_EXPORT QArrayData { - QtPrivate::RefCount ref; - int size; - uint alloc : 31; - uint capacityReserved : 1; + 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; + } - qptrdiff offset; // in bytes from beginning of header + inline size_t constAllocatedCapacity() const + { + return alloc; + } - void *data() + /// Returns true if sharing took place + bool ref() { - Q_ASSERT(size == 0 - || offset < 0 || size_t(offset) >= sizeof(QArrayData)); - return reinterpret_cast<char *>(this) + offset; + if (!isStatic()) + ref_.ref(); + return true; } - const void *data() const + /// Returns false if deallocation is necessary + bool deref() { - Q_ASSERT(size == 0 - || offset < 0 || size_t(offset) >= sizeof(QArrayData)); - return reinterpret_cast<const char *>(this) + offset; + if (isStatic()) + return true; + return ref_.deref(); } // This refers to array data mutability, not "header data" represented by @@ -73,183 +106,140 @@ struct Q_CORE_EXPORT QArrayData // follow COW principles. bool isMutable() const { - return alloc != 0; + return flags & MutableData; } - enum AllocationOption { - CapacityReserved = 0x1, -#if !defined(QT_NO_UNSHARABLE_CONTAINERS) - Unsharable = 0x2, -#endif - RawData = 0x4, - Grow = 0x8, + bool isStatic() const + { + return flags & ImmutableHeader; + } - Default = 0 - }; + bool isShared() const + { + return ref_.loadRelaxed() != 1; + } - Q_DECLARE_FLAGS(AllocationOptions, AllocationOption) + // 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 (capacityReserved && newSize < alloc) - return alloc; + if (flags & CapacityReserved && newSize < constAllocatedCapacity()) + return constAllocatedCapacity(); return newSize; } - AllocationOptions detachFlags() const + ArrayOptions detachFlags() const { - AllocationOptions result; - if (capacityReserved) + ArrayOptions result = DefaultAllocationFlags; + if (flags & CapacityReserved) result |= CapacityReserved; return result; } - AllocationOptions cloneFlags() const + ArrayOptions cloneFlags() const { - AllocationOptions result; - if (capacityReserved) + ArrayOptions result = DefaultAllocationFlags; + if (flags & CapacityReserved) result |= CapacityReserved; return result; } - Q_REQUIRED_RESULT static QArrayData *allocate(size_t objectSize, size_t alignment, - size_t capacity, AllocationOptions options = Default) noexcept; + 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, AllocationOptions newOptions = Default) noexcept; + size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) noexcept; + Q_REQUIRED_RESULT static QPair<QArrayData *, void *> 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<QArrayData*>(shared_null); } + static void *sharedNullData() + { + QArrayData *const null = const_cast<QArrayData *>(&shared_null[1]); + return null; + } }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::AllocationOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions) + +template <class T, size_t N> +struct QStaticArrayData +{ + // static arrays are of type RawDataType + QArrayData header; + T data[N]; +}; + +// Support for returning QArrayDataPointer<T> from functions +template <class T> +struct QArrayDataPointerRef +{ + QTypedArrayData<T> *ptr; + T *data; + uint size; +}; 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(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 - - 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; }; - Q_REQUIRED_RESULT static QTypedArrayData *allocate(size_t capacity, - AllocationOptions options = Default) + Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(size_t capacity, + ArrayOptions options = DefaultAllocationFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T), - Q_ALIGNOF(AlignmentDummy), capacity, options)); + 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<QTypedArrayData *>(d), static_cast<T *>(result)); } - static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity, - AllocationOptions options = Default) + static QPair<QTypedArrayData *, T *> + reallocateUnaligned(QTypedArrayData *data, T *dataPointer, size_t capacity, + ArrayOptions options = DefaultAllocationFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T), - capacity, options)); + QPair<QArrayData *, void *> pair = + QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, options); + return qMakePair(static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second)); } static void deallocate(QArrayData *data) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy)); + QArrayData::deallocate(data, sizeof(T), alignof(AlignmentDummy)); } - static QTypedArrayData *fromRawData(const T *data, size_t n, - AllocationOptions options = Default) + static QArrayDataPointerRef<T> fromRawData(const T *data, size_t n, + ArrayOptions options = DefaultRawFlags) { 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); + QArrayDataPointerRef<T> result = { + static_cast<QTypedArrayData *>(prepareRawData(options)), const_cast<T *>(data), uint(n) + }; + if (result.ptr) { + Q_ASSERT(!result.ptr->isShared()); // No shared empty, please! } return result; } @@ -266,38 +256,13 @@ struct QTypedArrayData return allocate(/* capacity */ 0); } -#if !defined(QT_NO_UNSHARABLE_CONTAINERS) - static QTypedArrayData *unsharableEmpty() + static T *sharedNullData() { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - return allocate(/* capacity */ 0, Unsharable); + return static_cast<T *>(QArrayData::sharedNullData()); } -#endif -}; - -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 @@ -333,15 +298,16 @@ struct QArrayDataPointerRef Q_ARRAY_LITERAL_CHECK_LITERAL_TYPE(Type); \ \ /* Portable compile-time array size computation */ \ - Q_CONSTEXPR Type data[] = { __VA_ARGS__ }; Q_UNUSED(data); \ + static Type const data[] = { __VA_ARGS__ }; \ enum { Size = sizeof(data) / sizeof(data[0]) }; \ \ - static const QStaticArrayData<Type, Size> literal = { \ - Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(Type, Size), { __VA_ARGS__ } }; \ + static const QArrayData literal = { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 }; \ \ QArrayDataPointerRef<Type> ref = \ { static_cast<QTypedArrayData<Type> *>( \ - const_cast<QArrayData *>(&literal.header)) }; \ + const_cast<QArrayData *>(&literal)), \ + const_cast<Type *>(data), \ + Size }; \ /**/ namespace QtPrivate { |