summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qarraydata.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qarraydata.h')
-rw-r--r--src/corelib/tools/qarraydata.h304
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 {