Change QVector's in-memory data layout

The new layout matches that of QByteArrayData and QStringData, except
for offset which is measured from the beginning of QVectorData, whereas
in those classes it (still?) references the end of the header data.

The new layout uses an extra member for storing an offset into the data,
which will allow introducing QVector::fromRawData, similar to the same
functionality already existing in QString and QByteArray.

By not using an actual array to index array members, we also steer clear
of GCC bug #43247:

    http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43247

Change-Id: I408915aacadf616b4633bbbf5cae1fc19e415087
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
João Abecasis 2012-02-17 12:10:03 +01:00 committed by Qt by Nokia
parent a5233b6b22
commit a1621d235d
2 changed files with 129 additions and 137 deletions

View File

@ -65,16 +65,13 @@ QT_BEGIN_NAMESPACE
struct Q_CORE_EXPORT QVectorData struct Q_CORE_EXPORT QVectorData
{ {
QtPrivate::RefCount ref; QtPrivate::RefCount ref;
int alloc;
int size; int size;
#if defined(Q_PROCESSOR_SPARC) && defined(Q_CC_GNU) && defined(__LP64__) && defined(QT_BOOTSTRAPPED) uint alloc : 31;
// workaround for bug in gcc 3.4.2 uint capacityReserved : 1;
uint capacity;
uint reserved; qptrdiff offset;
#else
uint capacity : 1; void* data() { return reinterpret_cast<char *>(this) + this->offset; }
uint reserved : 31;
#endif
static const QVectorData shared_null; static const QVectorData shared_null;
static QVectorData *allocate(int size, int alignment); static QVectorData *allocate(int size, int alignment);
@ -84,12 +81,12 @@ struct Q_CORE_EXPORT QVectorData
}; };
template <typename T> template <typename T>
struct QVectorTypedData : private QVectorData struct QVectorTypedData : QVectorData
{ // private inheritance as we must not access QVectorData member thought QVectorTypedData {
// as this would break strict aliasing rules. (in the case of shared_null) T* begin() { return reinterpret_cast<T *>(this->data()); }
T array[1]; T* end() { return begin() + this->size; }
static inline void free(QVectorTypedData<T> *x, int alignment) { QVectorData::free(static_cast<QVectorData *>(x), alignment); } static QVectorTypedData *sharedNull() { return static_cast<QVectorTypedData *>(const_cast<QVectorData *>(&QVectorData::shared_null)); }
}; };
class QRegion; class QRegion;
@ -98,19 +95,10 @@ template <typename T>
class QVector class QVector
{ {
typedef QVectorTypedData<T> Data; typedef QVectorTypedData<T> Data;
union { Data *d;
QVectorData *d;
#if defined(Q_CC_SUN) && (__SUNPRO_CC <= 0x550)
QVectorTypedData<T> *p;
#else
Data *p;
#endif
};
public: public:
// ### Qt 5: Consider making QVector non-shared to get at least one inline QVector() : d(Data::sharedNull()) { }
// "really fast" container. See tests/benchmarks/corelib/tools/qvector/
inline QVector() : d(const_cast<QVectorData *>(&QVectorData::shared_null)) { }
explicit QVector(int size); explicit QVector(int size);
QVector(int size, const T &t); QVector(int size, const T &t);
inline QVector(const QVector<T> &v) inline QVector(const QVector<T> &v)
@ -118,19 +106,19 @@ public:
if (v.d->ref.ref()) { if (v.d->ref.ref()) {
d = v.d; d = v.d;
} else { } else {
d = const_cast<QVectorData *>(&QVectorData::shared_null); d = Data::sharedNull();
realloc(0, v.d->alloc); realloc(0, v.d->alloc);
qCopy(v.p->array, v.p->array + v.d->size, p->array); qCopy(v.d->begin(), v.d->end(), d->begin());
d->size = v.d->size; d->size = v.d->size;
d->capacity = v.d->capacity; d->capacityReserved = v.d->capacityReserved;
} }
} }
inline ~QVector() { if (!d->ref.deref()) free(p); } inline ~QVector() { if (!d->ref.deref()) free(d); }
QVector<T> &operator=(const QVector<T> &v); QVector<T> &operator=(const QVector<T> &v);
#ifdef Q_COMPILER_RVALUE_REFS #ifdef Q_COMPILER_RVALUE_REFS
inline QVector<T> operator=(QVector<T> &&other) inline QVector<T> operator=(QVector<T> &&other)
{ qSwap(p, other.p); return *this; } { qSwap(d, other.d); return *this; }
#endif #endif
inline void swap(QVector<T> &other) { qSwap(d, other.d); } inline void swap(QVector<T> &other) { qSwap(d, other.d); }
#ifdef Q_COMPILER_INITIALIZER_LISTS #ifdef Q_COMPILER_INITIALIZER_LISTS
@ -147,7 +135,7 @@ public:
inline int capacity() const { return d->alloc; } inline int capacity() const { return d->alloc; }
void reserve(int size); void reserve(int size);
inline void squeeze() { realloc(d->size, d->size); d->capacity = 0; } inline void squeeze() { realloc(d->size, d->size); d->capacityReserved = 0; }
inline void detach() { if (!isDetached()) detach_helper(); } inline void detach() { if (!isDetached()) detach_helper(); }
inline bool isDetached() const { return !d->ref.isShared(); } inline bool isDetached() const { return !d->ref.isShared(); }
@ -157,15 +145,15 @@ public:
return; return;
if (!sharable) if (!sharable)
detach(); detach();
if (d != &QVectorData::shared_null) if (d != Data::sharedNull())
d->ref.setSharable(sharable); d->ref.setSharable(sharable);
} }
inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; } inline bool isSharedWith(const QVector<T> &other) const { return d == other.d; }
inline T *data() { detach(); return p->array; } inline T *data() { detach(); return d->begin(); }
inline const T *data() const { return p->array; } inline const T *data() const { return d->begin(); }
inline const T *constData() const { return p->array; } inline const T *constData() const { return d->begin(); }
void clear(); void clear();
const T &at(int i) const; const T &at(int i) const;
@ -258,12 +246,12 @@ public:
typedef T* iterator; typedef T* iterator;
typedef const T* const_iterator; typedef const T* const_iterator;
#endif #endif
inline iterator begin() { detach(); return p->array; } inline iterator begin() { detach(); return d->begin(); }
inline const_iterator begin() const { return p->array; } inline const_iterator begin() const { return d->begin(); }
inline const_iterator constBegin() const { return p->array; } inline const_iterator constBegin() const { return d->begin(); }
inline iterator end() { detach(); return p->array + d->size; } inline iterator end() { detach(); return d->end(); }
inline const_iterator end() const { return p->array + d->size; } inline const_iterator end() const { return d->end(); }
inline const_iterator constEnd() const { return p->array + d->size; } inline const_iterator constEnd() const { return d->end(); }
iterator insert(iterator before, int n, const T &x); iterator insert(iterator before, int n, const T &x);
inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); } inline iterator insert(iterator before, const T &x) { return insert(before, 1, x); }
iterator erase(iterator begin, iterator end); iterator erase(iterator begin, iterator end);
@ -328,19 +316,21 @@ private:
friend class QRegion; // Optimization for QRegion::rects() friend class QRegion; // Optimization for QRegion::rects()
void detach_helper(); void detach_helper();
QVectorData *malloc(int alloc); Data *malloc(int alloc);
void realloc(int size, int alloc); void realloc(int size, int alloc);
void free(Data *d); void free(Data *d);
class AlignmentDummy { QVectorData header; T array[1]; };
static Q_DECL_CONSTEXPR int offsetOfTypedData() static Q_DECL_CONSTEXPR int offsetOfTypedData()
{ {
// (non-POD)-safe offsetof(Data, array) // (non-POD)-safe offsetof(AlignmentDummy, array)
return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1); return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1);
} }
static Q_DECL_CONSTEXPR int alignOfTypedData() static Q_DECL_CONSTEXPR int alignOfTypedData()
{ {
#ifdef Q_ALIGNOF #ifdef Q_ALIGNOF
return Q_ALIGNOF(Data); return Q_ALIGNOF(AlignmentDummy);
#else #else
return sizeof(void *); return sizeof(void *);
#endif #endif
@ -352,10 +342,10 @@ void QVector<T>::detach_helper()
{ realloc(d->size, d->alloc); } { realloc(d->size, d->alloc); }
template <typename T> template <typename T>
void QVector<T>::reserve(int asize) void QVector<T>::reserve(int asize)
{ if (asize > d->alloc) realloc(d->size, asize); if (isDetached()) d->capacity = 1; } { if (asize > d->alloc) realloc(d->size, asize); if (isDetached()) d->capacityReserved = 1; }
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->capacityReserved && asize < d->size && asize < (d->alloc >> 1))) ?
QVectorData::grow(offsetOfTypedData(), asize, sizeof(T)) QVectorData::grow(offsetOfTypedData(), asize, sizeof(T))
: d->alloc); } : d->alloc); }
template <typename T> template <typename T>
@ -364,11 +354,11 @@ inline void QVector<T>::clear()
template <typename T> template <typename T>
inline const T &QVector<T>::at(int i) const inline const T &QVector<T>::at(int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range"); { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::at", "index out of range");
return p->array[i]; } return d->begin()[i]; }
template <typename T> template <typename T>
inline const T &QVector<T>::operator[](int i) const inline const T &QVector<T>::operator[](int i) const
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
return p->array[i]; } return d->begin()[i]; }
template <typename T> template <typename T>
inline T &QVector<T>::operator[](int i) inline T &QVector<T>::operator[](int i)
{ Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range"); { Q_ASSERT_X(i >= 0 && i < d->size, "QVector<T>::operator[]", "index out of range");
@ -412,11 +402,11 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v)
} }
template <typename T> template <typename T>
inline QVectorData *QVector<T>::malloc(int aalloc) inline typename QVector<T>::Data *QVector<T>::malloc(int aalloc)
{ {
QVectorData *vectordata = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData()); QVectorData *vectordata = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(vectordata); Q_CHECK_PTR(vectordata);
return vectordata; return static_cast<Data *>(vectordata);
} }
template <typename T> template <typename T>
@ -425,14 +415,15 @@ QVector<T>::QVector(int asize)
d = malloc(asize); d = malloc(asize);
d->ref.initializeOwned(); d->ref.initializeOwned();
d->alloc = d->size = asize; d->alloc = d->size = asize;
d->capacity = false; d->capacityReserved = false;
d->offset = offsetOfTypedData();
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
T* b = p->array; T* b = d->begin();
T* i = p->array + d->size; T* i = d->end();
while (i != b) while (i != b)
new (--i) T; new (--i) T;
} else { } else {
qMemSet(p->array, 0, asize * sizeof(T)); qMemSet(d->begin(), 0, asize * sizeof(T));
} }
} }
@ -442,9 +433,10 @@ QVector<T>::QVector(int asize, const T &t)
d = malloc(asize); d = malloc(asize);
d->ref.initializeOwned(); d->ref.initializeOwned();
d->alloc = d->size = asize; d->alloc = d->size = asize;
d->capacity = false; d->capacityReserved = false;
T* i = p->array + d->size; d->offset = offsetOfTypedData();
while (i != p->array) T* i = d->end();
while (i != d->begin())
new (--i) T(t); new (--i) T(t);
} }
@ -455,11 +447,11 @@ QVector<T>::QVector(std::initializer_list<T> args)
d = malloc(int(args.size())); d = malloc(int(args.size()));
d->ref.initializeOwned(); d->ref.initializeOwned();
d->alloc = d->size = int(args.size()); d->alloc = d->size = int(args.size());
d->capacity = false; d->capacityReserved = false;
T* i = p->array + d->size; d->offset = offsetOfTypedData();
T* i = d->end();
auto it = args.end(); auto it = args.end();
while (i != p->array) while (i != d->begin())
new (--i) T(*(--it));
} }
#endif #endif
@ -467,14 +459,12 @@ template <typename T>
void QVector<T>::free(Data *x) void QVector<T>::free(Data *x)
{ {
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
T* b = x->array; T* b = x->begin();
union { QVectorData *d; Data *p; } u; T* i = b + x->size;
u.p = x;
T* i = b + u.d->size;
while (i-- != b) while (i-- != b)
i->~T(); i->~T();
} }
x->free(x, alignOfTypedData()); Data::free(x, alignOfTypedData());
} }
template <typename T> template <typename T>
@ -483,14 +473,13 @@ void QVector<T>::realloc(int asize, int aalloc)
Q_ASSERT(asize <= aalloc); Q_ASSERT(asize <= aalloc);
T *pOld; T *pOld;
T *pNew; T *pNew;
union { QVectorData *d; Data *p; } x; Data *x = d;
x.d = d;
if (QTypeInfo<T>::isComplex && asize < d->size && isDetached()) { if (QTypeInfo<T>::isComplex && asize < d->size && isDetached()) {
// call the destructor on all objects that need to be // call the destructor on all objects that need to be
// destroyed when shrinking // destroyed when shrinking
pOld = p->array + d->size; pOld = d->begin() + d->size;
pNew = p->array + asize; pNew = d->begin() + asize;
while (asize < d->size) { while (asize < d->size) {
(--pOld)->~T(); (--pOld)->~T();
d->size--; d->size--;
@ -500,66 +489,66 @@ void QVector<T>::realloc(int asize, int aalloc)
if (aalloc != d->alloc || !isDetached()) { if (aalloc != d->alloc || !isDetached()) {
// (re)allocate memory // (re)allocate memory
if (QTypeInfo<T>::isStatic) { if (QTypeInfo<T>::isStatic) {
x.d = malloc(aalloc); x = malloc(aalloc);
Q_CHECK_PTR(x.p); Q_CHECK_PTR(x);
x.d->size = 0; x->size = 0;
} else if (!isDetached()) { } else if (!isDetached()) {
x.d = malloc(aalloc); x = malloc(aalloc);
Q_CHECK_PTR(x.p); Q_CHECK_PTR(x);
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
x.d->size = 0; x->size = 0;
} else { } else {
::memcpy(x.p, p, offsetOfTypedData() + qMin(aalloc, d->alloc) * sizeof(T)); ::memcpy(x, d, offsetOfTypedData() + qMin(uint(aalloc), d->alloc) * sizeof(T));
x.d->size = d->size; x->size = d->size;
} }
} else { } else {
QT_TRY { QT_TRY {
QVectorData *mem = QVectorData::reallocate(d, offsetOfTypedData() + aalloc * sizeof(T), QVectorData *mem = QVectorData::reallocate(d, offsetOfTypedData() + aalloc * sizeof(T),
offsetOfTypedData() + d->alloc * sizeof(T), alignOfTypedData()); offsetOfTypedData() + d->alloc * sizeof(T), alignOfTypedData());
Q_CHECK_PTR(mem); Q_CHECK_PTR(mem);
x.d = d = mem; x = d = static_cast<Data *>(mem);
x.d->size = d->size; x->size = d->size;
} QT_CATCH (const std::bad_alloc &) { } QT_CATCH (const std::bad_alloc &) {
if (aalloc > d->alloc) // ignore the error in case we are just shrinking. if (aalloc > d->alloc) // ignore the error in case we are just shrinking.
QT_RETHROW; QT_RETHROW;
} }
} }
x.d->ref.initializeOwned(); x->ref.initializeOwned();
x.d->alloc = aalloc; x->alloc = aalloc;
x.d->capacity = d->capacity; x->capacityReserved = d->capacityReserved;
x.d->reserved = 0; x->offset = offsetOfTypedData();
} }
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
QT_TRY { QT_TRY {
pOld = p->array + x.d->size; pOld = d->begin() + x->size;
pNew = x.p->array + x.d->size; pNew = x->begin() + x->size;
// copy objects from the old array into the new array // copy objects from the old array into the new array
const int toMove = qMin(asize, d->size); const int toMove = qMin(asize, d->size);
while (x.d->size < toMove) { while (x->size < toMove) {
new (pNew++) T(*pOld++); new (pNew++) T(*pOld++);
x.d->size++; x->size++;
} }
// construct all new objects when growing // construct all new objects when growing
while (x.d->size < asize) { while (x->size < asize) {
new (pNew++) T; new (pNew++) T;
x.d->size++; x->size++;
} }
} QT_CATCH (...) { } QT_CATCH (...) {
free(x.p); free(x);
QT_RETHROW; QT_RETHROW;
} }
} else if (asize > x.d->size) { } else if (asize > x->size) {
// initialize newly allocated memory to 0 // initialize newly allocated memory to 0
qMemSet(x.p->array + x.d->size, 0, (asize - x.d->size) * sizeof(T)); qMemSet(x->end(), 0, (asize - x->size) * sizeof(T));
} }
x.d->size = asize; x->size = asize;
if (d != x.d) { if (d != x) {
if (!d->ref.deref()) if (!d->ref.deref())
free(p); free(d);
d = x.d; d = x;
} }
} }
@ -569,12 +558,12 @@ Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i) const
if (i < 0 || i >= d->size) { if (i < 0 || i >= d->size) {
return T(); return T();
} }
return p->array[i]; return d->begin()[i];
} }
template<typename T> template<typename T>
Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
{ {
return ((i < 0 || i >= d->size) ? defaultValue : p->array[i]); return ((i < 0 || i >= d->size) ? defaultValue : d->begin()[i]);
} }
template <typename T> template <typename T>
@ -586,14 +575,14 @@ void QVector<T>::append(const T &t)
QVectorData::grow(offsetOfTypedData(), 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 (d->end()) T(copy);
else else
p->array[d->size] = copy; *d->end() = copy;
} else { } else {
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (p->array + d->size) T(t); new (d->end()) T(t);
else else
p->array[d->size] = t; *d->end() = t;
} }
++d->size; ++d->size;
} }
@ -601,26 +590,26 @@ void QVector<T>::append(const T &t)
template <typename T> template <typename T>
typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t) typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, const T &t)
{ {
int offset = int(before - p->array); int offset = int(before - d->begin());
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(offsetOfTypedData(), 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 = d->end();
T *i = p->array + d->size + n; T *i = d->end() + n;
while (i != b) while (i != b)
new (--i) T; new (--i) T;
i = p->array + d->size; i = d->end();
T *j = i + n; T *j = i + n;
b = p->array + offset; b = d->begin() + offset;
while (i != b) while (i != b)
*--j = *--i; *--j = *--i;
i = b+n; i = b+n;
while (i != b) while (i != b)
*--i = copy; *--i = copy;
} else { } else {
T *b = p->array + offset; T *b = d->begin() + offset;
T *i = b + n; T *i = b + n;
memmove(i, b, (d->size - offset) * sizeof(T)); memmove(i, b, (d->size - offset) * sizeof(T));
while (i != b) while (i != b)
@ -628,29 +617,29 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
} }
d->size += n; d->size += n;
} }
return p->array + offset; return d->begin() + offset;
} }
template <typename T> template <typename T>
typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
{ {
int f = int(abegin - p->array); int f = int(abegin - d->begin());
int l = int(aend - p->array); int l = int(aend - d->begin());
int n = l - f; int n = l - f;
detach(); detach();
if (QTypeInfo<T>::isComplex) { if (QTypeInfo<T>::isComplex) {
qCopy(p->array+l, p->array+d->size, p->array+f); qCopy(d->begin()+l, d->end(), d->begin()+f);
T *i = p->array+d->size; T *i = d->end();
T* b = p->array+d->size-n; T* b = d->end()-n;
while (i != b) { while (i != b) {
--i; --i;
i->~T(); i->~T();
} }
} else { } else {
memmove(p->array + f, p->array + l, (d->size-l)*sizeof(T)); memmove(d->begin() + f, d->begin() + l, (d->size-l)*sizeof(T));
} }
d->size -= n; d->size -= n;
return p->array + f; return d->begin() + f;
} }
template <typename T> template <typename T>
@ -660,9 +649,9 @@ bool QVector<T>::operator==(const QVector<T> &v) const
return false; return false;
if (d == v.d) if (d == v.d)
return true; return true;
T* b = p->array; T* b = d->begin();
T* i = b + d->size; T* i = b + d->size;
T* j = v.p->array + d->size; T* j = v.d->end();
while (i != b) while (i != b)
if (!(*--i == *--j)) if (!(*--i == *--j))
return false; return false;
@ -675,8 +664,8 @@ QVector<T> &QVector<T>::fill(const T &from, int asize)
const T copy(from); const T copy(from);
resize(asize < 0 ? d->size : asize); resize(asize < 0 ? d->size : asize);
if (d->size) { if (d->size) {
T *i = p->array + d->size; T *i = d->end();
T *b = p->array; T *b = d->begin();
while (i != b) while (i != b)
*--i = copy; *--i = copy;
} }
@ -689,9 +678,9 @@ QVector<T> &QVector<T>::operator+=(const QVector &l)
int newSize = d->size + l.d->size; int newSize = d->size + l.d->size;
realloc(d->size, newSize); realloc(d->size, newSize);
T *w = p->array + newSize; T *w = d->begin() + newSize;
T *i = l.p->array + l.d->size; T *i = l.d->end();
T *b = l.p->array; T *b = l.d->begin();
while (i != b) { while (i != b) {
if (QTypeInfo<T>::isComplex) if (QTypeInfo<T>::isComplex)
new (--w) T(*--i); new (--w) T(*--i);
@ -708,11 +697,11 @@ int QVector<T>::indexOf(const T &t, int from) const
if (from < 0) if (from < 0)
from = qMax(from + d->size, 0); from = qMax(from + d->size, 0);
if (from < d->size) { if (from < d->size) {
T* n = p->array + from - 1; T* n = d->begin() + from - 1;
T* e = p->array + d->size; T* e = d->end();
while (++n != e) while (++n != e)
if (*n == t) if (*n == t)
return n - p->array; return n - d->begin();
} }
return -1; return -1;
} }
@ -725,8 +714,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
else if (from >= d->size) else if (from >= d->size)
from = d->size-1; from = d->size-1;
if (from >= 0) { if (from >= 0) {
T* b = p->array; T* b = d->begin();
T* n = p->array + from + 1; T* n = d->begin() + from + 1;
while (n != b) { while (n != b) {
if (*--n == t) if (*--n == t)
return n - b; return n - b;
@ -738,8 +727,8 @@ int QVector<T>::lastIndexOf(const T &t, int from) const
template <typename T> template <typename T>
bool QVector<T>::contains(const T &t) const bool QVector<T>::contains(const T &t) const
{ {
T* b = p->array; T* b = d->begin();
T* i = p->array + d->size; T* i = d->end();
while (i != b) while (i != b)
if (*--i == t) if (*--i == t)
return true; return true;
@ -750,8 +739,8 @@ template <typename T>
int QVector<T>::count(const T &t) const int QVector<T>::count(const T &t) const
{ {
int c = 0; int c = 0;
T* b = p->array; T* b = d->begin();
T* i = p->array + d->size; T* i = d->end();
while (i != b) while (i != b)
if (*--i == t) if (*--i == t)
++c; ++c;

View File

@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE
template <typename T> template <typename T>
class QRawVector class QRawVector
{ {
struct Data : QVectorData { T array[1]; }; typedef QVectorTypedData<T> Data;
T *m_begin; T *m_begin;
int m_size; int m_size;
@ -265,15 +265,17 @@ private:
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);
class AlignmentDummy { QVectorData header; T array[1]; };
static Q_DECL_CONSTEXPR int offsetOfTypedData() static Q_DECL_CONSTEXPR int offsetOfTypedData()
{ {
// (non-POD)-safe offsetof(Data, array) // (non-POD)-safe offsetof(AlignmentDummy, array)
return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1); return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1);
} }
static Q_DECL_CONSTEXPR int alignOfTypedData() static Q_DECL_CONSTEXPR int alignOfTypedData()
{ {
#ifdef Q_ALIGNOF #ifdef Q_ALIGNOF
return Q_ALIGNOF(Data); return Q_ALIGNOF(AlignmentDummy);
#else #else
return sizeof(void *); return sizeof(void *);
#endif #endif
@ -286,7 +288,8 @@ public:
d->ref.initializeOwned(); d->ref.initializeOwned();
d->alloc = m_alloc; d->alloc = m_alloc;
d->size = m_size; d->size = m_size;
d->capacity = 0; d->capacityReserved = 0;
d->offset = offsetOfTypedData();
QVector<T> v; QVector<T> v;
*reinterpret_cast<QVectorData **>(&v) = d; *reinterpret_cast<QVectorData **>(&v) = d;