Start moving QArrayData's size and data pointer to the main class

This requires that the allocation functions return two pointers: the d
pointer and the pointer to the actual data.

Ported QArrayDataPointer & SimpleVector to the inlined size & data.

For now, the size and offset members are not yet removed from
QArrayData, to let QVector, QByteArray and QString compile unmodified.

Change-Id: I8489300976723d75b8fd5831427b1e2bba486196
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
bb10
Thiago Macieira 2012-06-14 15:05:34 +02:00 committed by Lars Knoll
parent f2569c0ff7
commit add048bc4e
9 changed files with 268 additions and 243 deletions

View File

@ -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 };

View File

@ -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 };

View File

@ -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,

View File

@ -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 {

View File

@ -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 &parameter_type;

View File

@ -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 *>(d);
return *static_cast<DataOps *>(this);
}
DataOps *operator->() const
DataOps *operator->()
{
Q_ASSERT(d);
return static_cast<DataOps *>(d);
return static_cast<DataOps *>(this);
}
const DataOps &operator*() const
{
Q_ASSERT(d);
return *static_cast<const DataOps *>(this);
}
const DataOps *operator->() const
{
Q_ASSERT(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);
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());
if (d->size)
copy->copyAppend(d->begin(), d->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>

View File

@ -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();

View File

@ -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)
{
}
bool empty() const { return d->size == 0; }
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 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;
}
}

View File

@ -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');
}
}