diff options
-rw-r--r-- | src/corelib/text/qbytearray.cpp | 29 | ||||
-rw-r--r-- | src/corelib/text/qstring.cpp | 28 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.cpp | 29 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.h | 81 | ||||
-rw-r--r-- | src/corelib/tools/qarraydataops.h | 6 | ||||
-rw-r--r-- | src/corelib/tools/qarraydatapointer.h | 118 | ||||
-rw-r--r-- | src/corelib/tools/qvector.h | 20 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/simplevector.h | 25 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp | 175 |
9 files changed, 268 insertions, 243 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 78395a47e3..7562227d7d 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -731,7 +731,7 @@ QByteArray qUncompress(const uchar* data, int nbytes) return invalidCompressedData(); } - QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1)); + QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1).first); if (Q_UNLIKELY(d.data() == nullptr)) return invalidCompressedData(); @@ -764,7 +764,8 @@ QByteArray qUncompress(const uchar* data, int nbytes) return invalidCompressedData(); } else { // grow the block - QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1); + char *dataPointer = d->data(); + QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), dataPointer, len + 1).first; if (Q_UNLIKELY(p == nullptr)) return invalidCompressedData(); d.take(); // don't free @@ -1204,7 +1205,7 @@ QByteArray &QByteArray::operator=(const char *str) if (!str) { x = Data::sharedNull(); } else if (!*str) { - x = Data::allocate(0); + x = Data::allocate(0).first; } else { const int len = int(strlen(str)); const int fullLen = len + 1; @@ -1693,9 +1694,9 @@ QByteArray::QByteArray(const char *data, int size) if (size < 0) size = int(strlen(data)); if (!size) { - d = Data::allocate(0); + d = Data::allocate(0).first; } else { - d = Data::allocate(uint(size) + 1u); + d = Data::allocate(uint(size) + 1u).first; Q_CHECK_PTR(d); d->size = size; memcpy(d->data(), data, size); @@ -1714,9 +1715,9 @@ QByteArray::QByteArray(const char *data, int size) QByteArray::QByteArray(int size, char ch) { if (size <= 0) { - d = Data::allocate(0); + d = Data::allocate(0).first; } else { - d = Data::allocate(uint(size) + 1u); + d = Data::allocate(uint(size) + 1u).first; Q_CHECK_PTR(d); d->size = size; memset(d->data(), ch, size); @@ -1732,7 +1733,7 @@ QByteArray::QByteArray(int size, char ch) QByteArray::QByteArray(int size, Qt::Initialization) { - d = Data::allocate(uint(size) + 1u); + d = Data::allocate(uint(size) + 1u).first; Q_CHECK_PTR(d); d->size = size; d->data()[size] = '\0'; @@ -1769,7 +1770,7 @@ void QByteArray::resize(int size) // which is used in place of the Qt 3 idiom: // QByteArray a(sz); // - Data *x = Data::allocate(uint(size) + 1u); + Data *x = Data::allocate(uint(size) + 1u).first; Q_CHECK_PTR(x); x->size = size; x->data()[size] = '\0'; @@ -1806,7 +1807,7 @@ QByteArray &QByteArray::fill(char ch, int size) void QByteArray::reallocData(uint alloc, Data::ArrayOptions options) { if (d->needsDetach()) { - Data *x = Data::allocate(alloc, options); + Data *x = Data::allocate(alloc, options).first; Q_CHECK_PTR(x); x->size = qMin(int(alloc) - 1, d->size); ::memcpy(x->data(), d->data(), x->size); @@ -1815,7 +1816,7 @@ void QByteArray::reallocData(uint alloc, Data::ArrayOptions options) Data::deallocate(d); d = x; } else { - Data *x = Data::reallocateUnaligned(d, alloc, options); + Data *x = Data::reallocateUnaligned(d, d->data(), alloc, options).first; Q_CHECK_PTR(x); d = x; } @@ -3130,7 +3131,7 @@ QByteArray QByteArray::mid(int pos, int len) const return QByteArray(); case QContainerImplHelper::Empty: { - QByteArrayDataPtr empty = { Data::allocate(0) }; + QByteArrayDataPtr empty = { Data::allocate(0).first }; return QByteArray(empty); } case QContainerImplHelper::Full: @@ -4444,9 +4445,9 @@ QByteArray QByteArray::fromRawData(const char *data, int size) if (!data) { x = Data::sharedNull(); } else if (!size) { - x = Data::allocate(0); + x = Data::allocate(0).first; } else { - x = Data::fromRawData(data, size); + x = Data::fromRawData(data, size).ptr; Q_CHECK_PTR(x); } QByteArrayDataPtr dataPtr = { x }; diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 4d3f2016ac..8ae365338d 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -2109,9 +2109,9 @@ QString::QString(const QChar *unicode, int size) ++size; } if (!size) { - d = Data::allocate(0); + d = Data::allocate(0).first; } else { - d = Data::allocate(size + 1); + d = Data::allocate(size + 1).first; Q_CHECK_PTR(d); d->size = size; memcpy(d->data(), unicode, size * sizeof(QChar)); @@ -2129,9 +2129,9 @@ QString::QString(const QChar *unicode, int size) QString::QString(int size, QChar ch) { if (size <= 0) { - d = Data::allocate(0); + d = Data::allocate(0).first; } else { - d = Data::allocate(size + 1); + d = Data::allocate(size + 1).first; Q_CHECK_PTR(d); d->size = size; d->data()[size] = '\0'; @@ -2151,7 +2151,7 @@ QString::QString(int size, QChar ch) */ QString::QString(int size, Qt::Initialization) { - d = Data::allocate(size + 1); + d = Data::allocate(size + 1).first; Q_CHECK_PTR(d); d->size = size; d->data()[size] = '\0'; @@ -2169,7 +2169,7 @@ QString::QString(int size, Qt::Initialization) */ QString::QString(QChar ch) { - d = Data::allocate(2); + d = Data::allocate(2).first; Q_CHECK_PTR(d); d->size = 1; d->data()[0] = ch.unicode(); @@ -2354,7 +2354,7 @@ void QString::reallocData(uint alloc, bool grow) allocOptions |= QArrayData::GrowsForward; if (d->needsDetach()) { - Data *x = Data::allocate(alloc, allocOptions); + Data *x = Data::allocate(alloc, allocOptions).first; Q_CHECK_PTR(x); x->size = qMin(int(alloc) - 1, d->size); ::memcpy(x->data(), d->data(), x->size * sizeof(QChar)); @@ -2363,7 +2363,7 @@ void QString::reallocData(uint alloc, bool grow) Data::deallocate(d); d = x; } else { - Data *p = Data::reallocateUnaligned(d, alloc, allocOptions); + Data *p = Data::reallocateUnaligned(d, d->data(), alloc, allocOptions).first; Q_CHECK_PTR(p); d = p; } @@ -4898,7 +4898,7 @@ QString QString::mid(int position, int n) const return QString(); case QContainerImplHelper::Empty: { - QStringDataPtr empty = { Data::allocate(0) }; + QStringDataPtr empty = { Data::allocate(0).first }; return QString(empty); } case QContainerImplHelper::Full: @@ -5354,11 +5354,11 @@ QString::Data *QString::fromLatin1_helper(const char *str, int size) if (!str) { d = Data::sharedNull(); } else if (size == 0 || (!*str && size < 0)) { - d = Data::allocate(0); + d = Data::allocate(0).first; } else { if (size < 0) size = qstrlen(str); - d = Data::allocate(size + 1); + d = Data::allocate(size + 1).first; Q_CHECK_PTR(d); d->size = size; d->data()[size] = '\0'; @@ -5418,7 +5418,7 @@ QString QString::fromLocal8Bit_helper(const char *str, int size) if (!str) return QString(); if (size == 0 || (!*str && size < 0)) { - QStringDataPtr empty = { Data::allocate(0) }; + QStringDataPtr empty = { Data::allocate(0).first }; return QString(empty); } #if QT_CONFIG(textcodec) @@ -9124,9 +9124,9 @@ QString QString::fromRawData(const QChar *unicode, int size) if (!unicode) { x = Data::sharedNull(); } else if (!size) { - x = Data::allocate(0); + x = Data::allocate(0).first; } else { - x = Data::fromRawData(reinterpret_cast<const ushort *>(unicode), size); + x = Data::fromRawData(reinterpret_cast<const ushort *>(unicode), size).ptr; Q_CHECK_PTR(x); } QStringDataPtr dataPtr = { x }; diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index aa7fac15ef..8052c2ca69 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -198,16 +198,19 @@ static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint opt return header; } -QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, +void *QArrayData::allocate(QArrayData **dptr, size_t objectSize, size_t alignment, size_t capacity, ArrayOptions options) noexcept { + Q_ASSERT(dptr); // Alignment is a power of two Q_ASSERT(alignment >= alignof(QArrayData) && !(alignment & (alignment - 1))); - if (capacity == 0) + if (capacity == 0) { // optimization for empty headers - return const_cast<QArrayData *>(&qt_array_empty); + *dptr = const_cast<QArrayData *>(&qt_array_empty); + return sharedNullData(); + } size_t headerSize = sizeof(QArrayData); @@ -225,14 +228,17 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, options |= AllocatedDataType | MutableData; options &= ~ImmutableHeader; QArrayData *header = allocateData(allocSize, options); + quintptr data = 0; if (header) { - quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) + // find where offset should point to so that data() is aligned to alignment bytes + data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1); header->offset = data - quintptr(header); header->alloc = capacity; } - return header; + *dptr = header; + return reinterpret_cast<void *>(data); } QArrayData *QArrayData::prepareRawData(ArrayOptions options) Q_DECL_NOTHROW @@ -243,8 +249,9 @@ QArrayData *QArrayData::prepareRawData(ArrayOptions options) Q_DECL_NOTHROW return header; } -QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity, - ArrayOptions options) noexcept +QPair<QArrayData *, void *> +QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer, + size_t objectSize, size_t capacity, ArrayOptions options) noexcept { Q_ASSERT(data); Q_ASSERT(data->isMutable()); @@ -252,12 +259,14 @@ QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t headerSize = sizeof(QArrayData); size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); + qptrdiff offset = reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data); options |= AllocatedDataType | MutableData; - options &= ~ImmutableHeader; QArrayData *header = reallocateData(data, allocSize, options); - if (header) + if (header) { header->alloc = capacity; - return header; + dataPointer = reinterpret_cast<char *>(header) + offset; + } + return qMakePair(static_cast<QArrayData *>(header), dataPointer); } void QArrayData::deallocate(QArrayData *data, size_t objectSize, diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 56d61340f0..6cf0ea1cb6 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -41,11 +41,14 @@ #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 { enum ArrayOption { @@ -169,10 +172,12 @@ struct Q_CORE_EXPORT QArrayData #if defined(Q_CC_GNU) __attribute__((__malloc__)) #endif - static QArrayData *allocate(size_t objectSize, size_t alignment, + 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<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, @@ -190,6 +195,23 @@ struct Q_CORE_EXPORT QArrayData 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 @@ -282,27 +304,26 @@ struct QTypedArrayData class AlignmentDummy { QArrayData header; T data; }; - Q_REQUIRED_RESULT static QTypedArrayData *allocate(size_t capacity, + Q_REQUIRED_RESULT static QPair<QTypedArrayData *, T *> allocate(size_t capacity, ArrayOptions options = DefaultAllocationFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - void *result = QArrayData::allocate(sizeof(T), - 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 static_cast<QTypedArrayData *>(result); + return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result)); } - static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity, + static QPair<QTypedArrayData *, T *> + reallocateUnaligned(QTypedArrayData *data, T *dataPointer, size_t capacity, ArrayOptions options = DefaultAllocationFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - void *result = QArrayData::reallocateUnaligned(data, sizeof(T), 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 static_cast<QTypedArrayData *>(result); + 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) @@ -311,17 +332,18 @@ struct QTypedArrayData QArrayData::deallocate(data, sizeof(T), alignof(AlignmentDummy)); } - static QTypedArrayData *fromRawData(const T *data, size_t n, + static QArrayDataPointerRef<T> fromRawData(const T *data, size_t n, ArrayOptions options = DefaultRawFlags) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); - QTypedArrayData *result = static_cast<QTypedArrayData *>(prepareRawData(options)); - if (result) { - Q_ASSERT(!result->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! + result.ptr->offset = reinterpret_cast<const char *>(data) + - reinterpret_cast<const char *>(result.ptr); + result.ptr->size = int(n); } return result; } @@ -345,21 +367,6 @@ struct QTypedArrayData } }; -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; -}; - #define Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \ { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, size, 0, offset } \ /**/ @@ -412,7 +419,9 @@ struct QArrayDataPointerRef \ QArrayDataPointerRef<Type> ref = \ { static_cast<QTypedArrayData<Type> *>( \ - const_cast<QArrayData *>(&literal.header)) }; \ + const_cast<QArrayData *>(&literal.header)), \ + const_cast<Type *>(literal.data), \ + Size }; \ /**/ namespace QtPrivate { diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index ac7fc7bc4e..8fe35952bf 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -47,6 +47,8 @@ QT_BEGIN_NAMESPACE +template <class T> struct QArrayDataPointer; + namespace QtPrivate { QT_WARNING_PUSH @@ -56,7 +58,7 @@ QT_WARNING_DISABLE_GCC("-Wstringop-overflow") template <class T> struct QPodArrayOps - : QTypedArrayData<T> + : public QArrayDataPointer<T> { typedef T parameter_type; @@ -148,7 +150,7 @@ QT_WARNING_POP template <class T> struct QGenericArrayOps - : QTypedArrayData<T> + : public QArrayDataPointer<T> { typedef const T ¶meter_type; diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index 86997985d1..c52b84f4ce 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -52,26 +52,38 @@ private: typedef QArrayDataOps<T> DataOps; public: + typedef typename Data::iterator iterator; + typedef typename Data::const_iterator const_iterator; + QArrayDataPointer() noexcept - : d(Data::sharedNull()) + : d(Data::sharedNull()), b(Data::sharedNullData()), size(0) { } QArrayDataPointer(const QArrayDataPointer &other) - : d(other.d->ref() - ? other.d - : other.clone(other.d->cloneFlags())) + : d(other.d), b(other.b), size(other.size) + { + if (!other.d->ref()) { + // must clone + QPair<Data *, T *> pair = other.clone(other.d->cloneFlags()); + d = pair.first; + b = pair.second; + } + } + + QArrayDataPointer(Data *header, T *data, size_t n = 0) + : d(header), b(data), size(n) { } - explicit QArrayDataPointer(QTypedArrayData<T> *ptr) - : d(ptr) + explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> data, size_t n = 0) + : d(data.first), b(data.second), size(n) { - Q_CHECK_PTR(ptr); + Q_CHECK_PTR(d); } QArrayDataPointer(QArrayDataPointerRef<T> ref) - : d(ref.ptr) + : d(ref.ptr), b(ref.data), size(ref.size) { } @@ -83,7 +95,7 @@ public: } QArrayDataPointer(QArrayDataPointer &&other) noexcept - : d(other.d) + : d(other.d), b(other.b), size(other.size) { other.d = Data::sharedNull(); } @@ -95,16 +107,28 @@ public: return *this; } - DataOps &operator*() const + DataOps &operator*() + { + Q_ASSERT(d); + return *static_cast<DataOps *>(this); + } + + DataOps *operator->() + { + Q_ASSERT(d); + return static_cast<DataOps *>(this); + } + + const DataOps &operator*() const { Q_ASSERT(d); - return *static_cast<DataOps *>(d); + return *static_cast<const DataOps *>(this); } - DataOps *operator->() const + const DataOps *operator->() const { Q_ASSERT(d); - return static_cast<DataOps *>(d); + return static_cast<const DataOps *>(this); } ~QArrayDataPointer() @@ -121,62 +145,92 @@ public: return d == Data::sharedNull(); } - Data *data() const - { - return d; - } + T *data() { return b; } + const T *data() const { return b; } + + iterator begin() { return data(); } + iterator end() { return data() + size; } + const_iterator begin() const { return data(); } + const_iterator end() const { return data() + size; } + const_iterator constBegin() const { return data(); } + const_iterator constEnd() const { return data() + size; } void swap(QArrayDataPointer &other) noexcept { qSwap(d, other.d); + qSwap(b, other.b); + qSwap(size, other.size); } void clear() { - QArrayDataPointer tmp(d); + QArrayDataPointer tmp(d, b, size); d = Data::sharedNull(); + b = reinterpret_cast<T *>(d); + size = 0; } bool detach() { if (d->needsDetach()) { - Data *copy = clone(d->detachFlags()); - QArrayDataPointer old(d); - d = copy; + QPair<Data *, T *> copy = clone(d->detachFlags()); + QArrayDataPointer old(d, b, size); + d = copy.first; + b = copy.second; return true; } return false; } + // forwards from QArrayData + int allocatedCapacity() { return d->allocatedCapacity(); } + int constAllocatedCapacity() const { return d->constAllocatedCapacity(); } + int refCounterValue() const { return d->refCounterValue(); } + bool ref() { return d->ref(); } + bool deref() { return d->deref(); } + bool isMutable() const { return d->isMutable(); } + bool isStatic() const { return d->isStatic(); } + bool isShared() const { return d->isShared(); } + bool needsDetach() const { return d->needsDetach(); } + size_t detachCapacity(size_t newSize) const { return d->detachCapacity(newSize); } + typename Data::ArrayOptions &flags() { return reinterpret_cast<typename Data::ArrayOptions &>(d->flags); } + typename Data::ArrayOptions flags() const { return typename Data::ArrayOption(d->flags); } + typename Data::ArrayOptions detachFlags() const { return d->detachFlags(); } + typename Data::ArrayOptions cloneFlags() const { return d->cloneFlags(); } + private: - Q_REQUIRED_RESULT Data *clone(QArrayData::ArrayOptions options) const + Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const { - Data *x = Data::allocate(d->detachCapacity(d->size), options); - Q_CHECK_PTR(x); - QArrayDataPointer copy(x); - - if (d->size) - copy->copyAppend(d->begin(), d->end()); + QPair<Data *, T *> pair = Data::allocate(d->detachCapacity(size), + options); + Q_CHECK_PTR(pair.first); + QArrayDataPointer copy(pair.first, pair.second, 0); + if (size) + copy->copyAppend(begin(), end()); - Data *result = copy.d; + pair.first = copy.d; copy.d = Data::sharedNull(); - return result; + return pair; } Data *d; + T *b; + +public: + uint size; }; template <class T> inline bool operator==(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) { - return lhs.data() == rhs.data(); + return lhs.data() == rhs.data() && lhs.size == rhs.size; } template <class T> inline bool operator!=(const QArrayDataPointer<T> &lhs, const QArrayDataPointer<T> &rhs) { - return lhs.data() != rhs.data(); + return lhs.data() != rhs.data() || lhs.size != rhs.size; } template <class T> diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index bf422e72d4..330bf8bb98 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -369,11 +369,11 @@ inline QVector<T>::QVector(const QVector<T> &v) d = v.d; } else { if (v.d->flags & Data::CapacityReserved) { - d = Data::allocate(v.d->allocatedCapacity()); + d = Data::allocate(v.d->allocatedCapacity()).first; Q_CHECK_PTR(d); d->flags |= Data::CapacityReserved; } else { - d = Data::allocate(v.d->size); + d = Data::allocate(v.d->size).first; Q_CHECK_PTR(d); } if (v.d->size) { @@ -394,9 +394,10 @@ void QVector<T>::detach() if (d->isStatic()) return; - if (d->needsDetach()) + if (d->needsDetach()) { realloc(d->allocatedCapacity(), d->detachFlags()); - Q_ASSERT(isDetached()); + Q_ASSERT(isDetached()); + } } template <typename T> @@ -497,7 +498,7 @@ QVector<T>::QVector(int asize) { Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0."); if (Q_LIKELY(asize > 0)) { - d = Data::allocate(asize); + d = Data::allocate(asize).first; Q_CHECK_PTR(d); d->size = asize; defaultConstruct(d->begin(), d->end()); @@ -511,7 +512,7 @@ QVector<T>::QVector(int asize, const T &t) { Q_ASSERT_X(asize >= 0, "QVector::QVector", "Size must be greater than or equal to 0."); if (asize > 0) { - d = Data::allocate(asize); + d = Data::allocate(asize).first; Q_CHECK_PTR(d); d->size = asize; T* i = d->end(); @@ -531,7 +532,7 @@ template <typename T> QVector<T>::QVector(std::initializer_list<T> args) { if (args.size() > 0) { - d = Data::allocate(args.size()); + d = Data::allocate(args.size()).first; Q_CHECK_PTR(d); // std::initializer_list<T>::iterator is guaranteed to be // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct @@ -585,7 +586,8 @@ void QVector<T>::realloc(int aalloc, QArrayData::ArrayOptions options) QT_TRY { // allocate memory - x = Data::allocate(aalloc, options); + auto pair = Data::allocate(aalloc, options); + x = pair.first; Q_CHECK_PTR(x); // aalloc is bigger then 0 so it is not [un]sharedEmpty Q_ASSERT(!x->isStatic()); @@ -749,7 +751,7 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, T &&t) Q_ASSERT_X(isValidIterator(before), "QVector::insert", "The specified iterator argument 'before' is invalid"); const auto offset = std::distance(d->begin(), before); - if (!isDetached() || d->size + 1 > int(d->alloc)) + if (!isDetached() || d->size + 1 > int(d->allocatedCapacity())) realloc(d->size + 1, QArrayData::GrowsForward); if (!QTypeInfoQuery<T>::isRelocatable) { T *i = d->end(); diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index aa791b600c..94cee5d887 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -76,12 +76,23 @@ public: { } - explicit SimpleVector(Data *ptr) - : d(ptr) + template <size_t N> + explicit SimpleVector(QStaticArrayData<T, N> &ptr) + : d(static_cast<Data *>(&ptr.header), ptr.data, N) + { + } + + SimpleVector(Data *header, T *data, size_t len = 0) + : d(header, data, len) + { + } + + explicit SimpleVector(QPair<Data*, T*> ptr, size_t len = 0) + : d(ptr, len) { } - bool empty() const { return d->size == 0; } + bool empty() const { return d.size == 0; } bool isNull() const { return d.isNull(); } bool isEmpty() const { return this->empty(); } @@ -89,8 +100,8 @@ public: bool isShared() const { return d->isShared(); } bool isSharedWith(const SimpleVector &other) const { return d == other.d; } - size_t size() const { return d->size; } - size_t capacity() const { return d->allocatedCapacity(); } + size_t size() const { return d.size; } + size_t capacity() const { return d->constAllocatedCapacity(); } iterator begin() { detach(); return d->begin(); } iterator end() { detach(); return d->end(); } @@ -139,10 +150,10 @@ public: return; if (n <= capacity()) { - if (d->flags & Data::CapacityReserved) + if (d->flags() & Data::CapacityReserved) return; if (!d->isShared()) { - d->flags |= Data::CapacityReserved; + d->flags() |= Data::CapacityReserved; return; } } diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 44066e29a1..3a19f944d3 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -56,7 +56,6 @@ class tst_QArrayData : public QObject private slots: void referenceCounting(); void sharedNullEmpty(); - void staticData(); void simpleVector(); void simpleVectorReserve_data(); void simpleVectorReserve(); @@ -127,7 +126,8 @@ void tst_QArrayData::referenceCounting() void tst_QArrayData::sharedNullEmpty() { QArrayData *null = const_cast<QArrayData *>(QArrayData::shared_null); - QArrayData *empty = QArrayData::allocate(1, alignof(QArrayData), 0); + QArrayData *empty; + QArrayData::allocate(&empty, 1, alignof(QArrayData), 0); QVERIFY(null->isStatic()); QVERIFY(null->isShared()); @@ -149,37 +149,11 @@ void tst_QArrayData::sharedNullEmpty() QVERIFY(null != empty); - QCOMPARE(null->size, 0); QCOMPARE(null->allocatedCapacity(), size_t(0)); - QCOMPARE(empty->size, 0); QCOMPARE(empty->allocatedCapacity(), size_t(0)); } -void tst_QArrayData::staticData() -{ - QStaticArrayData<char, 10> charArray = { - Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(char, 10), - { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' } - }; - QStaticArrayData<int, 10> intArray = { - Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } - }; - QStaticArrayData<double, 10> doubleArray = { - Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(double, 10), - { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f } - }; - - QCOMPARE(charArray.header.size, 10); - QCOMPARE(intArray.header.size, 10); - QCOMPARE(doubleArray.header.size, 10); - - QCOMPARE(charArray.header.data(), reinterpret_cast<void *>(&charArray.data)); - QCOMPARE(intArray.header.data(), reinterpret_cast<void *>(&intArray.data)); - QCOMPARE(doubleArray.header.data(), reinterpret_cast<void *>(&doubleArray.data)); -} - void tst_QArrayData::simpleVector() { QArrayData data0 = { Q_REFCOUNT_INITIALIZE_STATIC, QArrayData::StaticDataFlags, 0, 0, 0 }; @@ -192,10 +166,10 @@ void tst_QArrayData::simpleVector() SimpleVector<int> v1; SimpleVector<int> v2(v1); - SimpleVector<int> v3(static_cast<QTypedArrayData<int> *>(&data0)); - SimpleVector<int> v4(static_cast<QTypedArrayData<int> *>(&data1.header)); - SimpleVector<int> v5(static_cast<QTypedArrayData<int> *>(&data0)); - SimpleVector<int> v6(static_cast<QTypedArrayData<int> *>(&data1.header)); + SimpleVector<int> v3(static_cast<QTypedArrayData<int> *>(&data0), 0, 0); + SimpleVector<int> v4(data1); + SimpleVector<int> v5(static_cast<QTypedArrayData<int> *>(&data0), 0, 0); + SimpleVector<int> v6(data1); SimpleVector<int> v7(10, 5); SimpleVector<int> v8(array, array + sizeof(array)/sizeof(*array)); @@ -457,9 +431,11 @@ void tst_QArrayData::simpleVectorReserve_data() static const QStaticArrayData<int, 15> array = { Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 15), { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } }; - QArrayDataPointerRef<int> p = { + const QArrayDataPointerRef<int> p = { static_cast<QTypedArrayData<int> *>( - const_cast<QArrayData *>(&array.header)) }; + const_cast<QArrayData *>(&array.header)), + const_cast<int *>(array.data), + sizeof(array.data) / sizeof(array.data[0]) }; QTest::newRow("static") << SimpleVector<int>(p) << size_t(0) << size_t(15); QTest::newRow("raw-data") << SimpleVector<int>::fromRawData(array.data, 15) << size_t(0) << size_t(15); @@ -542,7 +518,8 @@ void tst_QArrayData::allocate_data() { "void *", sizeof(void *), alignof(void *) } }; - QArrayData *shared_empty = QArrayData::allocate(0, alignof(QArrayData), 0); + QArrayData *shared_empty; + QArrayData::allocate(&shared_empty, 1, alignof(QArrayData), 0); QVERIFY(shared_empty); struct { @@ -580,18 +557,20 @@ void tst_QArrayData::allocate() size_t minAlignment = qMax(alignment, alignof(QArrayData)); // Shared Empty - QCOMPARE(QArrayData::allocate(objectSize, minAlignment, 0, - QArrayData::ArrayOptions(allocateOptions)), commonEmpty); + QArrayData *empty; + QCOMPARE((QArrayData::allocate(&empty, objectSize, minAlignment, 0, + QArrayData::ArrayOptions(allocateOptions)), empty), commonEmpty); Deallocator keeper(objectSize, minAlignment); keeper.headers.reserve(1024); for (int capacity = 1; capacity <= 1024; capacity <<= 1) { - QArrayData *data = QArrayData::allocate(objectSize, minAlignment, + QArrayData *data; + void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, QArrayData::ArrayOptions(allocateOptions)); + keeper.headers.append(data); - QCOMPARE(data->size, 0); if (allocateOptions & QArrayData::GrowsForward) QVERIFY(data->allocatedCapacity() > uint(capacity)); else @@ -600,7 +579,7 @@ void tst_QArrayData::allocate() // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. - ::memset(data->data(), 'A', objectSize * capacity); + ::memset(dataPointer, 'A', objectSize * capacity); } } @@ -621,22 +600,23 @@ void tst_QArrayData::reallocate() int capacity = 10; Deallocator keeper(objectSize, minAlignment); - QArrayData *data = QArrayData::allocate(objectSize, minAlignment, capacity, - QArrayData::ArrayOptions(allocateOptions) & ~QArrayData::GrowsForward); + QArrayData *data; + void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, + QArrayData::ArrayOptions(allocateOptions) & ~QArrayData::GrowsForward); keeper.headers.append(data); - memset(data->data(), 'A', objectSize * capacity); - data->size = capacity; + memset(dataPointer, 'A', objectSize * capacity); // now try to reallocate int newCapacity = 40; - data = QArrayData::reallocateUnaligned(data, objectSize, newCapacity, - QArrayData::ArrayOptions(allocateOptions)); + auto pair = QArrayData::reallocateUnaligned(data, dataPointer, objectSize, newCapacity, + QArrayData::ArrayOptions(allocateOptions)); + data = pair.first; + dataPointer = pair.second; QVERIFY(data); keeper.headers.clear(); keeper.headers.append(data); - QCOMPARE(data->size, capacity); if (allocateOptions & QArrayData::GrowsForward) QVERIFY(data->allocatedCapacity() > size_t(newCapacity)); else @@ -644,7 +624,7 @@ void tst_QArrayData::reallocate() QCOMPARE(!(data->flags & QArrayData::CapacityReserved), !isCapacityReserved); for (int i = 0; i < capacity; ++i) - QCOMPARE(static_cast<char *>(data->data())[i], 'A'); + QCOMPARE(static_cast<char *>(dataPointer)[i], 'A'); } class Unaligned @@ -674,89 +654,46 @@ void tst_QArrayData::alignment() keeper.headers.reserve(100); for (int i = 0; i < 100; ++i) { - QArrayData *data = QArrayData::allocate(sizeof(Unaligned), + QArrayData *data; + void *dataPointer = QArrayData::allocate(&data, sizeof(Unaligned), minAlignment, 8, QArrayData::DefaultAllocationFlags); keeper.headers.append(data); QVERIFY(data); - QCOMPARE(data->size, 0); QVERIFY(data->allocatedCapacity() >= uint(8)); // These conditions should hold as long as header and array are // allocated together - QVERIFY(data->offset >= qptrdiff(sizeof(QArrayData))); - QVERIFY(data->offset <= qptrdiff(sizeof(QArrayData) + qptrdiff offset = reinterpret_cast<char *>(dataPointer) - + reinterpret_cast<char *>(data); + QVERIFY(offset >= qptrdiff(sizeof(QArrayData))); + QVERIFY(offset <= qptrdiff(sizeof(QArrayData) + minAlignment - alignof(QArrayData))); // Data is aligned - QCOMPARE(quintptr(quintptr(data->data()) % alignment), quintptr(0u)); + QCOMPARE(quintptr(quintptr(dataPointer) % alignment), quintptr(0u)); // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. - ::memset(data->data(), 'A', sizeof(Unaligned) * 8); + ::memset(dataPointer, 'A', sizeof(Unaligned) * 8); } } void tst_QArrayData::typedData() { - QStaticArrayData<int, 10> data = { - Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } - }; - QCOMPARE(data.header.size, 10); - - { - QTypedArrayData<int> *array = - static_cast<QTypedArrayData<int> *>(&data.header); - QCOMPARE(array->data(), data.data); - - int j = 0; - for (QTypedArrayData<int>::iterator iter = array->begin(); - iter != array->end(); ++iter, ++j) - QCOMPARE((const int *)iter, data.data + j); - QCOMPARE(j, 10); - } - - { - const QTypedArrayData<int> *array = - static_cast<const QTypedArrayData<int> *>(&data.header); - - QCOMPARE(array->data(), data.data); - - int j = 0; - for (QTypedArrayData<int>::const_iterator iter = array->begin(); - iter != array->end(); ++iter, ++j) - QCOMPARE((const int *)iter, data.data + j); - QCOMPARE(j, 10); - } - - { - QTypedArrayData<int> *null = QTypedArrayData<int>::sharedNull(); - QTypedArrayData<int> *empty = QTypedArrayData<int>::allocate(0); - - QVERIFY(null != empty); - - QCOMPARE(null->size, 0); - QCOMPARE(empty->size, 0); - - QCOMPARE(null->begin(), null->end()); - QCOMPARE(empty->begin(), empty->end()); - } - - { Deallocator keeper(sizeof(char), alignof(QTypedArrayData<char>::AlignmentDummy)); - QArrayData *array = QTypedArrayData<char>::allocate(10); + QPair<QTypedArrayData<char> *, char *> pair = QTypedArrayData<char>::allocate(10); + QArrayData *array = pair.first; keeper.headers.append(array); QVERIFY(array); - QCOMPARE(array->size, 0); QCOMPARE(array->allocatedCapacity(), size_t(10)); // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. - ::memset(array->data(), 0, 10 * sizeof(char)); + ::memset(pair.second, 0, 10 * sizeof(char)); keeper.headers.clear(); QTypedArrayData<short>::deallocate(array); @@ -767,16 +704,16 @@ void tst_QArrayData::typedData() { Deallocator keeper(sizeof(short), alignof(QTypedArrayData<short>::AlignmentDummy)); - QArrayData *array = QTypedArrayData<short>::allocate(10); + QPair<QTypedArrayData<short> *, short *> pair = QTypedArrayData<short>::allocate(10); + QArrayData *array = pair.first; keeper.headers.append(array); QVERIFY(array); - QCOMPARE(array->size, 0); QCOMPARE(array->allocatedCapacity(), size_t(10)); // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. - ::memset(array->data(), 0, 10 * sizeof(short)); + ::memset(pair.second, 0, 10 * sizeof(short)); keeper.headers.clear(); QTypedArrayData<short>::deallocate(array); @@ -787,16 +724,16 @@ void tst_QArrayData::typedData() { Deallocator keeper(sizeof(double), alignof(QTypedArrayData<double>::AlignmentDummy)); - QArrayData *array = QTypedArrayData<double>::allocate(10); + QPair<QTypedArrayData<double> *, double *> pair = QTypedArrayData<double>::allocate(10); + QArrayData *array = pair.first; keeper.headers.append(array); QVERIFY(array); - QCOMPARE(array->size, 0); QCOMPARE(array->allocatedCapacity(), size_t(10)); // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. - ::memset(array->data(), 0, 10 * sizeof(double)); + ::memset(pair.second, 0, 10 * sizeof(double)); keeper.headers.clear(); QTypedArrayData<double>::deallocate(array); @@ -1292,17 +1229,17 @@ void tst_QArrayData::literals() { { QArrayDataPointer<char> d = Q_ARRAY_LITERAL(char, "ABCDEFGHIJ"); - QCOMPARE(d->size, 10 + 1); + QCOMPARE(d.size, 10u + 1u); for (int i = 0; i < 10; ++i) - QCOMPARE(d->data()[i], char('A' + i)); + QCOMPARE(d.data()[i], char('A' + i)); } { // wchar_t is not necessarily 2-bytes QArrayDataPointer<wchar_t> d = Q_ARRAY_LITERAL(wchar_t, L"ABCDEFGHIJ"); - QCOMPARE(d->size, 10 + 1); + QCOMPARE(d.size, 10u + 1u); for (int i = 0; i < 10; ++i) - QCOMPARE(d->data()[i], wchar_t('A' + i)); + QCOMPARE(d.data()[i], wchar_t('A' + i)); } { @@ -1340,26 +1277,26 @@ void tst_QArrayData::variadicLiterals() { QArrayDataPointer<int> d = Q_ARRAY_LITERAL(int, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); - QCOMPARE(d->size, 10); + QCOMPARE(d.size, 10u); for (int i = 0; i < 10; ++i) - QCOMPARE(d->data()[i], i); + QCOMPARE(d.data()[i], i); } { QArrayDataPointer<char> d = Q_ARRAY_LITERAL(char, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'); - QCOMPARE(d->size, 10); + QCOMPARE(d.size, 10u); for (int i = 0; i < 10; ++i) - QCOMPARE(d->data()[i], char('A' + i)); + QCOMPARE(d.data()[i], char('A' + i)); } { QArrayDataPointer<const char *> d = Q_ARRAY_LITERAL(const char *, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J"); - QCOMPARE(d->size, 10); + QCOMPARE(d.size, 10u); for (int i = 0; i < 10; ++i) { - QCOMPARE(d->data()[i][0], char('A' + i)); - QCOMPARE(d->data()[i][1], '\0'); + QCOMPARE(d.data()[i][0], char('A' + i)); + QCOMPARE(d.data()[i][1], '\0'); } } |