Have QVectorData::grow, take size of header w/ padding

This includes padding necessary to align the data array, but excludes the first
element as was done before. Size of header is the interesting piece of
information, anyway.

This simplifies calculations in a couple of places, harmonizes code with the
QRawVector fork and paves the way for further changes in QVector, namely the
memory layout.

When Q_ALIGNOF is not available, default to pointer-size alignment. This
should be honoured by malloc and won't trigger use of more expensive
aligned allocation.

Change-Id: I504022ac7595f69089cafd96e47a91b874d5771e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
João Abecasis 2012-02-17 11:23:41 +01:00 committed by Qt by Nokia
parent ec5eb45cd3
commit ebeebe2126
3 changed files with 38 additions and 43 deletions

View File

@ -76,9 +76,9 @@ void QVectorData::free(QVectorData *x, int alignment)
::free(x); ::free(x);
} }
int QVectorData::grow(int sizeofTypedData, int size, int sizeofT) int QVectorData::grow(int sizeOfHeader, int size, int sizeOfT)
{ {
return qAllocMore(size * sizeofT, sizeofTypedData - sizeofT) / sizeofT; return qAllocMore(size * sizeOfT, sizeOfHeader) / sizeOfT;
} }
/*! /*!

View File

@ -80,7 +80,7 @@ struct Q_CORE_EXPORT QVectorData
static QVectorData *allocate(int size, int alignment); static QVectorData *allocate(int size, int alignment);
static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment); static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment);
static void free(QVectorData *data, int alignment); static void free(QVectorData *data, int alignment);
static int grow(int sizeofTypedData, int size, int sizeofT); static int grow(int sizeOfHeader, int size, int sizeOfT);
}; };
template <typename T> template <typename T>
@ -331,17 +331,18 @@ private:
QVectorData *malloc(int alloc); QVectorData *malloc(int alloc);
void realloc(int size, int alloc); void realloc(int size, int alloc);
void free(Data *d); void free(Data *d);
int sizeOfTypedData() {
// this is more or less the same as sizeof(Data), except that it doesn't static Q_DECL_CONSTEXPR int offsetOfTypedData()
// count the padding at the end {
return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); // (non-POD)-safe offsetof(Data, array)
return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1);
} }
inline int alignOfTypedData() const static Q_DECL_CONSTEXPR int alignOfTypedData()
{ {
#ifdef Q_ALIGNOF #ifdef Q_ALIGNOF
return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); return Q_ALIGNOF(Data);
#else #else
return 0; return sizeof(void *);
#endif #endif
} }
}; };
@ -355,7 +356,7 @@ void QVector<T>::reserve(int asize)
template <typename T> template <typename T>
void QVector<T>::resize(int asize) void QVector<T>::resize(int asize)
{ realloc(asize, (asize > d->alloc || (!d->capacity && asize < d->size && asize < (d->alloc >> 1))) ? { realloc(asize, (asize > d->alloc || (!d->capacity && asize < d->size && asize < (d->alloc >> 1))) ?
QVectorData::grow(sizeOfTypedData(), asize, sizeof(T)) QVectorData::grow(offsetOfTypedData(), asize, sizeof(T))
: d->alloc); } : d->alloc); }
template <typename T> template <typename T>
inline void QVector<T>::clear() inline void QVector<T>::clear()
@ -413,7 +414,7 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v)
template <typename T> template <typename T>
inline QVectorData *QVector<T>::malloc(int aalloc) inline QVectorData *QVector<T>::malloc(int aalloc)
{ {
QVectorData *vectordata = QVectorData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); QVectorData *vectordata = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(vectordata); Q_CHECK_PTR(vectordata);
return vectordata; return vectordata;
} }
@ -508,13 +509,13 @@ void QVector<T>::realloc(int asize, int aalloc)
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
x.d->size = 0; x.d->size = 0;
} else { } else {
::memcpy(x.p, p, sizeOfTypedData() + (qMin(aalloc, d->alloc) - 1) * sizeof(T)); ::memcpy(x.p, p, offsetOfTypedData() + qMin(aalloc, d->alloc) * sizeof(T));
x.d->size = d->size; x.d->size = d->size;
} }
} else { } else {
QT_TRY { QT_TRY {
QVectorData *mem = QVectorData::reallocate(d, sizeOfTypedData() + (aalloc - 1) * sizeof(T), QVectorData *mem = QVectorData::reallocate(d, offsetOfTypedData() + aalloc * sizeof(T),
sizeOfTypedData() + (d->alloc - 1) * sizeof(T), alignOfTypedData()); offsetOfTypedData() + d->alloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(mem); Q_CHECK_PTR(mem);
x.d = d = mem; x.d = d = mem;
x.d->size = d->size; x.d->size = d->size;
@ -582,7 +583,7 @@ void QVector<T>::append(const T &t)
if (!isDetached() || d->size + 1 > d->alloc) { if (!isDetached() || d->size + 1 > d->alloc) {
const T copy(t); const T copy(t);
realloc(d->size, (d->size + 1 > d->alloc) ? realloc(d->size, (d->size + 1 > d->alloc) ?
QVectorData::grow(sizeOfTypedData(), d->size + 1, sizeof(T)) QVectorData::grow(offsetOfTypedData(), d->size + 1, sizeof(T))
: d->alloc); : d->alloc);
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (p->array + d->size) T(copy); new (p->array + d->size) T(copy);
@ -604,7 +605,7 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
if (n != 0) { if (n != 0) {
const T copy(t); const T copy(t);
if (!isDetached() || d->size + n > d->alloc) if (!isDetached() || d->size + n > d->alloc)
realloc(d->size, QVectorData::grow(sizeOfTypedData(), d->size + n, sizeof(T))); realloc(d->size, QVectorData::grow(offsetOfTypedData(), d->size + n, sizeof(T)));
if (QTypeInfo<T>::isStatic) { if (QTypeInfo<T>::isStatic) {
T *b = p->array + d->size; T *b = p->array + d->size;
T *i = p->array + d->size + n; T *i = p->array + d->size + n;

View File

@ -73,17 +73,11 @@ class QRawVector
int m_alloc; int m_alloc;
public: public:
//static Data dummy; static Data *toBase(T *begin)
//int headerOffset() { return (char*)&dummy.array - (char*)&dummy; } { return (Data*)((char*)begin - offsetOfTypedData()); }
inline int headerOffset() const { static T *fromBase(void *d)
// gcc complains about: return offsetof(Data, array); and also { return (T*)((char*)d + offsetOfTypedData()); }
// does not like '0' in the expression below.
return (char *)&(((Data *)(1))->array) - (char *)1;
}
inline Data *toBase(T *begin) const
{ return (Data*)((char*)begin - headerOffset()); }
inline T *fromBase(void *d) const
{ return (T*)((char*)d + headerOffset()); }
inline QRawVector() inline QRawVector()
{ m_begin = fromBase(0); m_alloc = m_size = 0; realloc(m_size, m_alloc, true); } { m_begin = fromBase(0); m_alloc = m_size = 0; realloc(m_size, m_alloc, true); }
explicit QRawVector(int size); explicit QRawVector(int size);
@ -270,17 +264,18 @@ private:
T *allocate(int alloc); T *allocate(int alloc);
void realloc(int size, int alloc, bool ref); void realloc(int size, int alloc, bool ref);
void free(T *begin, int size); void free(T *begin, int size);
int sizeOfTypedData() {
// this is more or less the same as sizeof(Data), except that it doesn't static Q_DECL_CONSTEXPR int offsetOfTypedData()
// count the padding at the end {
return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); // (non-POD)-safe offsetof(Data, array)
return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1);
} }
static inline int alignOfTypedData() static Q_DECL_CONSTEXPR int alignOfTypedData()
{ {
#ifdef Q_ALIGNOF #ifdef Q_ALIGNOF
return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); return Q_ALIGNOF(Data);
#else #else
return 0; return sizeof(void *);
#endif #endif
} }
@ -308,7 +303,7 @@ void QRawVector<T>::reserve(int asize)
template <typename T> template <typename T>
void QRawVector<T>::resize(int asize) void QRawVector<T>::resize(int asize)
{ realloc(asize, (asize > m_alloc || (asize < m_size && asize < (m_alloc >> 1))) { realloc(asize, (asize > m_alloc || (asize < m_size && asize < (m_alloc >> 1)))
? QVectorData::grow(sizeOfTypedData(), asize, sizeof(T)) ? QVectorData::grow(offsetOfTypedData(), asize, sizeof(T))
: m_alloc, false); } : m_alloc, false); }
template <typename T> template <typename T>
inline void QRawVector<T>::clear() inline void QRawVector<T>::clear()
@ -369,7 +364,7 @@ QRawVector<T> &QRawVector<T>::operator=(const QRawVector<T> &v)
template <typename T> template <typename T>
inline T *QRawVector<T>::allocate(int aalloc) inline T *QRawVector<T>::allocate(int aalloc)
{ {
QVectorData *d = QVectorData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); QVectorData *d = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(d); Q_CHECK_PTR(d);
return fromBase(d); return fromBase(d);
} }
@ -445,10 +440,9 @@ void QRawVector<T>::realloc(int asize, int aalloc, bool ref)
changed = true; changed = true;
} else { } else {
QT_TRY { QT_TRY {
QVectorData *mem = QVectorData::reallocate( QVectorData *mem = QVectorData::reallocate(toBase(m_begin),
toBase(m_begin), sizeOfTypedData() + (aalloc - 1) * sizeof(T), offsetOfTypedData() + aalloc * sizeof(T),
sizeOfTypedData() offsetOfTypedData() + xalloc * sizeof(T), alignOfTypedData());
+ (xalloc - 1) * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(mem); Q_CHECK_PTR(mem);
xbegin = fromBase(mem); xbegin = fromBase(mem);
xsize = m_size; xsize = m_size;
@ -510,7 +504,7 @@ void QRawVector<T>::append(const T &t)
{ {
if (m_size + 1 > m_alloc) { if (m_size + 1 > m_alloc) {
const T copy(t); const T copy(t);
realloc(m_size, QVectorData::grow(sizeOfTypedData(), m_size + 1, sizeof(T)), false); realloc(m_size, QVectorData::grow(offsetOfTypedData(), m_size + 1, sizeof(T)), false);
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (m_begin + m_size) T(copy); new (m_begin + m_size) T(copy);
else else
@ -531,7 +525,7 @@ typename QRawVector<T>::iterator QRawVector<T>::insert(iterator before, size_typ
if (n != 0) { if (n != 0) {
const T copy(t); const T copy(t);
if (m_size + n > m_alloc) if (m_size + n > m_alloc)
realloc(m_size, QVectorData::grow(sizeOfTypedData(), m_size + n, sizeof(T)), false); realloc(m_size, QVectorData::grow(offsetOfTypedData(), m_size + n, sizeof(T)), false);
if (QTypeInfo<T>::isStatic) { if (QTypeInfo<T>::isStatic) {
T *b = m_begin + m_size; T *b = m_begin + m_size;
T *i = m_begin + m_size + n; T *i = m_begin + m_size + n;