From d17cf14185eb84863549e0119c8b7bd20db78580 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C4=99drzej=20Nowacki?= Date: Thu, 26 Apr 2012 12:06:17 +0200 Subject: [PATCH] Implement QVector with QArrayData interface. Change-Id: I109f46892aed2f6024459812d24922b12358814d Reviewed-by: Thiago Macieira --- src/corelib/tools/qarraydata.h | 12 + src/corelib/tools/qvector.cpp | 34 - src/corelib/tools/qvector.h | 483 ++++--- src/gui/painting/qregion.cpp | 2 +- tests/auto/corelib/tools/qvector/tst_qvector.cpp | 1486 ++++++++++++++++++-- .../benchmarks/corelib/tools/qvector/outofline.cpp | 33 + .../benchmarks/corelib/tools/qvector/qrawvector.h | 26 + tests/benchmarks/corelib/tools/qvector/qvector.pro | 2 +- 8 files changed, 1695 insertions(+), 383 deletions(-) diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index b038e85..ae78fec 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -179,6 +179,18 @@ struct QTypedArrayData Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); return static_cast(QArrayData::sharedNull()); } + + static QTypedArrayData *sharedEmpty() + { + Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); + return allocate(/* capacity */ 0); + } + + static QTypedArrayData *unsharableEmpty() + { + Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); + return allocate(/* capacity */ 0, Unsharable); + } }; template diff --git a/src/corelib/tools/qvector.cpp b/src/corelib/tools/qvector.cpp index 329727c..a19599e 100644 --- a/src/corelib/tools/qvector.cpp +++ b/src/corelib/tools/qvector.cpp @@ -47,40 +47,6 @@ QT_BEGIN_NAMESPACE -static inline int alignmentThreshold() -{ - // malloc on 32-bit platforms should return pointers that are 8-byte aligned or more - // while on 64-bit platforms they should be 16-byte aligned or more - return 2 * sizeof(void*); -} - -const QVectorData QVectorData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, false, 0 }; - -QVectorData *QVectorData::allocate(int size, int alignment) -{ - return static_cast(alignment > alignmentThreshold() ? qMallocAligned(size, alignment) : ::malloc(size)); -} - -QVectorData *QVectorData::reallocate(QVectorData *x, int newsize, int oldsize, int alignment) -{ - if (alignment > alignmentThreshold()) - return static_cast(qReallocAligned(x, newsize, oldsize, alignment)); - return static_cast(realloc(x, newsize)); -} - -void QVectorData::free(QVectorData *x, int alignment) -{ - if (alignment > alignmentThreshold()) - qFreeAligned(x); - else - ::free(x); -} - -int QVectorData::grow(int sizeOfHeader, int size, int sizeOfT) -{ - return qAllocMore(size * sizeOfT, sizeOfHeader) / sizeOfT; -} - /*! \class QVector \brief The QVector class is a template class that provides a dynamic array. diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 60cf12e..5b2cc11 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -59,59 +60,19 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE - -struct Q_CORE_EXPORT QVectorData -{ - QtPrivate::RefCount ref; - int size; - uint alloc : 31; - uint capacityReserved : 1; - - qptrdiff offset; - - void* data() { return reinterpret_cast(this) + this->offset; } - - static const QVectorData shared_null; - static QVectorData *allocate(int size, int alignment); - static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment); - static void free(QVectorData *data, int alignment); - static int grow(int sizeOfHeader, int size, int sizeOfT); -}; - -template -struct QVectorTypedData : QVectorData -{ - T* begin() { return reinterpret_cast(this->data()); } - T* end() { return begin() + this->size; } - - static QVectorTypedData *sharedNull() { return static_cast(const_cast(&QVectorData::shared_null)); } -}; - class QRegion; template class QVector { - typedef QVectorTypedData Data; + typedef QTypedArrayData Data; Data *d; public: inline QVector() : d(Data::sharedNull()) { } explicit QVector(int size); QVector(int size, const T &t); - inline QVector(const QVector &v) - { - if (v.d->ref.ref()) { - d = v.d; - } else { - d = Data::sharedNull(); - realloc(0, int(v.d->alloc)); - qCopy(v.d->begin(), v.d->end(), d->begin()); - d->size = v.d->size; - d->capacityReserved = v.d->capacityReserved; - } - } - + inline QVector(const QVector &v); inline ~QVector() { if (!d->ref.deref()) free(d); } QVector &operator=(const QVector &v); #ifdef Q_COMPILER_RVALUE_REFS @@ -134,9 +95,17 @@ public: inline int capacity() const { return int(d->alloc); } void reserve(int size); - inline void squeeze() { realloc(d->size, d->size); d->capacityReserved = 0; } + inline void squeeze() + { + realloc(d->size, d->size); + if (d->capacityReserved) { + // capacity reserved in a read only memory would be useless + // this checks avoid writing to such memory. + d->capacityReserved = 0; + } + } - inline void detach() { if (!isDetached()) detach_helper(); } + inline void detach(); inline bool isDetached() const { return !d->ref.isShared(); } inline void setSharable(bool sharable) { @@ -144,8 +113,14 @@ public: return; if (!sharable) detach(); - if (d != Data::sharedNull()) + + if (d == Data::unsharableEmpty()) { + if (sharable) + d = Data::sharedNull(); + } else { d->ref.setSharable(sharable); + } + Q_ASSERT(d->ref.isSharable() == sharable); } inline bool isSharedWith(const QVector &other) const { return d == other.d; } @@ -314,35 +289,107 @@ public: private: friend class QRegion; // Optimization for QRegion::rects() - void detach_helper(); - Data *malloc(int alloc); - void realloc(int size, int alloc); + void realloc(const int size, const int alloc, QArrayData::AllocationOptions options = QArrayData::Default); void free(Data *d); + void defaultConstruct(T *from, T *to); + void copyConstruct(T *srcFrom, T *srcTo, T *dstFrom); + void destruct(T *from, T *to); - class AlignmentDummy { QVectorData header; T array[1]; }; + class AlignmentDummy { Data header; T array[1]; }; +}; - static Q_DECL_CONSTEXPR int offsetOfTypedData() - { - // (non-POD)-safe offsetof(AlignmentDummy, array) - return (sizeof(QVectorData) + (alignOfTypedData() - 1)) & ~(alignOfTypedData() - 1); +template +void QVector::defaultConstruct(T *from, T *to) +{ + if (QTypeInfo::isComplex) { + while (from != to) { + new (from++) T(); + } + } else { + ::memset(from, 0, (to - from) * sizeof(T)); } - static Q_DECL_CONSTEXPR int alignOfTypedData() - { - return Q_ALIGNOF(AlignmentDummy); +} + +template +void QVector::copyConstruct(T *srcFrom, T *srcTo, T *dstFrom) +{ + if (QTypeInfo::isComplex) { + while (srcFrom != srcTo) + new (dstFrom++) T(*srcFrom++); + } else { + ::memcpy(dstFrom, srcFrom, (srcTo - srcFrom) * sizeof(T)); } -}; +} + +template +void QVector::destruct(T *from, T *to) +{ + if (QTypeInfo::isComplex) { + while (from != to) { + from++->~T(); + } + } +} + +template +inline QVector::QVector(const QVector &v) +{ + if (v.d->ref.ref()) { + d = v.d; + } else { + if (v.d->capacityReserved) { + d = Data::allocate(v.d->alloc); + d->capacityReserved = true; + } else { + d = Data::allocate(v.d->size); + } + if (d->alloc) { + copyConstruct(v.d->begin(), v.d->end(), d->begin()); + d->size = v.d->size; + } + } +} template -void QVector::detach_helper() -{ realloc(d->size, int(d->alloc)); } +void QVector::detach() +{ + if (!isDetached()) { + if (d->alloc) + realloc(d->size, int(d->alloc)); + else + d = Data::unsharableEmpty(); + } + Q_ASSERT(isDetached()); +} + template void QVector::reserve(int asize) -{ if (asize > int(d->alloc)) realloc(d->size, asize); if (isDetached()) d->capacityReserved = 1; } +{ + if (asize > int(d->alloc)) + realloc(d->size, asize); + if (isDetached()) + d->capacityReserved = 1; + Q_ASSERT(capacity() >= asize); +} + template void QVector::resize(int asize) -{ realloc(asize, (asize > int(d->alloc) || (!d->capacityReserved && asize < d->size && asize < int(d->alloc >> 1))) ? - QVectorData::grow(offsetOfTypedData(), asize, sizeof(T)) - : int(d->alloc)); } +{ + int newAlloc; + const int oldAlloc = int(d->alloc); + QArrayData::AllocationOptions opt; + + if (asize > oldAlloc) { // there is not enough space + newAlloc = asize; + opt = QArrayData::Grow; + } else if (!d->capacityReserved && asize < d->size && asize < (oldAlloc >> 1)) { // we want to shrink + newAlloc = asize; + opt = QArrayData::Grow; + } else { + newAlloc = oldAlloc; + } + realloc(asize, newAlloc, opt); +} template inline void QVector::clear() { *this = QVector(); } @@ -397,44 +444,29 @@ QVector &QVector::operator=(const QVector &v) } template -inline typename QVector::Data *QVector::malloc(int aalloc) -{ - QVectorData *vectordata = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData()); - Q_CHECK_PTR(vectordata); - return static_cast(vectordata); -} - -template QVector::QVector(int asize) { - d = malloc(asize); - d->ref.initializeOwned(); - d->size = asize; - d->alloc = uint(d->size); - d->capacityReserved = false; - d->offset = offsetOfTypedData(); - if (QTypeInfo::isComplex) { - T* b = d->begin(); - T* i = d->end(); - while (i != b) - new (--i) T; + if (Q_LIKELY(asize)) { + d = Data::allocate(asize); + d->size = asize; + defaultConstruct(d->begin(), d->end()); } else { - memset(d->begin(), 0, asize * sizeof(T)); + d = Data::sharedNull(); } } template QVector::QVector(int asize, const T &t) { - d = malloc(asize); - d->ref.initializeOwned(); - d->size = asize; - d->alloc = uint(d->size); - d->capacityReserved = false; - d->offset = offsetOfTypedData(); - T* i = d->end(); - while (i != d->begin()) - new (--i) T(t); + if (asize) { + d = Data::allocate(asize); + d->size = asize; + T* i = d->end(); + while (i != d->begin()) + new (--i) T(t); + } else { + d = Data::sharedNull(); + } } #ifdef Q_COMPILER_INITIALIZER_LISTS @@ -442,120 +474,114 @@ template QVector::QVector(std::initializer_list args) { d = malloc(int(args.size())); - d->ref.initializeOwned(); + // std::initializer_list::iterator is guaranteed to be + // const T* ([support.initlist]/1), so can be memcpy'ed away from by copyConstruct + copyConstruct(args.begin(), args.end(), d->begin()); d->size = int(args.size()); - d->alloc = uint(d->size); - d->capacityReserved = false; - d->offset = offsetOfTypedData(); - if (QTypeInfo::isComplex) { - T* b = d->begin(); - T* i = d->end(); - const T* s = args.end(); - while (i != b) - new(--i) T(*--s); - } else { - // std::initializer_list::iterator is guaranteed to be - // const T* ([support.initlist]/1), so can be memcpy'ed away from: - ::memcpy(d->begin(), args.begin(), args.size() * sizeof(T)); - } } #endif template void QVector::free(Data *x) { - if (QTypeInfo::isComplex) { - T* b = x->begin(); - T* i = b + x->size; - while (i-- != b) - i->~T(); - } - Data::free(x, alignOfTypedData()); + destruct(x->begin(), x->end()); + Data::deallocate(x); } template -void QVector::realloc(int asize, int aalloc) +void QVector::realloc(const int asize, const int aalloc, QArrayData::AllocationOptions options) { - Q_ASSERT(asize <= aalloc); - T *pOld; - T *pNew; + Q_ASSERT(asize >= 0 && asize <= aalloc); Data *x = d; - if (QTypeInfo::isComplex && asize < d->size && isDetached()) { - // call the destructor on all objects that need to be - // destroyed when shrinking - pOld = d->begin() + d->size; - pNew = d->begin() + asize; - while (asize < d->size) { - (--pOld)->~T(); - d->size--; - } - } - - if (aalloc != int(d->alloc) || !isDetached()) { - // (re)allocate memory - if (QTypeInfo::isStatic) { - x = malloc(aalloc); - Q_CHECK_PTR(x); - x->size = 0; - } else if (!isDetached()) { - x = malloc(aalloc); - Q_CHECK_PTR(x); - if (QTypeInfo::isComplex) { - x->size = 0; - } else { - ::memcpy(x, d, offsetOfTypedData() + qMin(uint(aalloc), d->alloc) * sizeof(T)); - x->size = d->size; + const bool isShared = d->ref.isShared(); +#ifndef QT_NO_DEBUG + bool moved = false; + int oldSize = d->size; +#endif + if (aalloc != 0) { + if (aalloc != int(d->alloc) || isShared) { + QT_TRY { + // allocate memory + x = Data::allocate(aalloc, options); + Q_CHECK_PTR(x); + // aalloc is bigger then 0 so it is not [un]sharedEmpty + Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable)); + Q_ASSERT(!x->ref.isStatic()); + x->size = asize; + + T *srcBegin = d->begin(); + T *srcEnd = asize > d->size ? d->end() : d->begin() + asize; + T *dst = x->begin(); + + if (QTypeInfo::isStatic || (isShared && QTypeInfo::isComplex)) { + // we can not move the data, we need to copy construct it + while (srcBegin != srcEnd) { + new (dst++) T(*srcBegin++); + } + } else { + ::memcpy(dst, srcBegin, (srcEnd - srcBegin) * sizeof(T)); + dst += srcEnd - srcBegin; + + // destruct unused / not moved data + if (asize < d->size) + destruct(d->begin() + asize, d->end()); +#ifndef QT_NO_DEBUG + moved = true; +#endif + } + + if (asize > d->size) { + // construct all new objects when growing + QT_TRY { + defaultConstruct(dst, x->end()); + } QT_CATCH (...) { + // destruct already copied objects + destruct(x->begin(), dst); + QT_RETHROW; + } + } + } QT_CATCH (...) { + Data::deallocate(x); + QT_RETHROW; } + x->capacityReserved = d->capacityReserved; } else { - QT_TRY { - QVectorData *mem = QVectorData::reallocate(d, offsetOfTypedData() + aalloc * sizeof(T), - offsetOfTypedData() + d->alloc * sizeof(T), alignOfTypedData()); - Q_CHECK_PTR(mem); - x = d = static_cast(mem); - x->size = d->size; - } QT_CATCH (const std::bad_alloc &) { - if (aalloc > int(d->alloc)) // ignore the error in case we are just shrinking. - QT_RETHROW; + Q_ASSERT(d->alloc == aalloc); // resize, without changing allocation size + Q_ASSERT(isDetached()); // can be done only on detached d + Q_ASSERT(x == d); // in this case we do not need to allocate anything + if (asize <= d->size) { + destruct(x->begin() + asize, x->end()); // from future end to current end + } else { + defaultConstruct(x->end(), x->begin() + asize); // from current end to future end } + x->size = asize; } - x->ref.initializeOwned(); - x->alloc = uint(aalloc); - x->capacityReserved = d->capacityReserved; - x->offset = offsetOfTypedData(); + } else { + x = Data::sharedNull(); } - - if (QTypeInfo::isComplex) { - QT_TRY { - pOld = d->begin() + x->size; - pNew = x->begin() + x->size; - // copy objects from the old array into the new array - const int toMove = qMin(asize, d->size); - while (x->size < toMove) { - new (pNew++) T(*pOld++); - x->size++; - } - // construct all new objects when growing - while (x->size < asize) { - new (pNew++) T; - x->size++; + if (d != x) { + if (!d->ref.deref()) { + Q_ASSERT(!isShared); + Q_ASSERT(d->size == oldSize); + if (QTypeInfo::isStatic || !aalloc) { + // data was copy constructed, we need to call destructors + // or if !alloc we did nothing to the old 'd'. + Q_ASSERT(!moved); + free(d); + } else { + Data::deallocate(d); } - } QT_CATCH (...) { - free(x); - QT_RETHROW; } - - } else if (asize > x->size) { - // initialize newly allocated memory to 0 - memset(x->end(), 0, (asize - x->size) * sizeof(T)); - } - x->size = asize; - - if (d != x) { - if (!d->ref.deref()) - free(d); d = x; } + + Q_ASSERT(d->data()); + Q_ASSERT(d->size <= d->alloc); + Q_ASSERT(d != Data::unsharableEmpty()); + Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull()); + Q_ASSERT(d->alloc >= aalloc); + Q_ASSERT(d->size == asize); } template @@ -575,21 +601,16 @@ Q_OUTOFLINE_TEMPLATE T QVector::value(int i, const T &defaultValue) const template void QVector::append(const T &t) { - if (!isDetached() || d->size + 1 > int(d->alloc)) { - const T copy(t); - realloc(d->size, (d->size + 1 > int(d->alloc)) ? - QVectorData::grow(offsetOfTypedData(), d->size + 1, sizeof(T)) - : int(d->alloc)); - if (QTypeInfo::isComplex) - new (d->end()) T(copy); - else - *d->end() = copy; - } else { - if (QTypeInfo::isComplex) - new (d->end()) T(t); - else - *d->end() = t; + const T copy(t); + const bool isTooSmall = uint(d->size + 1) > d->alloc; + if (!isDetached() || isTooSmall) { + QArrayData::AllocationOptions opt(isTooSmall ? QArrayData::Grow : QArrayData::Default); + realloc(d->size, isTooSmall ? d->size + 1 : d->alloc, opt); } + if (QTypeInfo::isComplex) + new (d->end()) T(copy); + else + *d->end() = copy; ++d->size; } @@ -600,7 +621,7 @@ typename QVector::iterator QVector::insert(iterator before, size_type n, c if (n != 0) { const T copy(t); if (!isDetached() || d->size + n > int(d->alloc)) - realloc(d->size, QVectorData::grow(offsetOfTypedData(), d->size + n, sizeof(T))); + realloc(d->size, d->size + n, QArrayData::Grow); if (QTypeInfo::isStatic) { T *b = d->end(); T *i = d->end() + n; @@ -629,23 +650,37 @@ typename QVector::iterator QVector::insert(iterator before, size_type n, c template typename QVector::iterator QVector::erase(iterator abegin, iterator aend) { - int f = int(abegin - d->begin()); - int l = int(aend - d->begin()); - int n = l - f; - detach(); - if (QTypeInfo::isComplex) { - qCopy(d->begin()+l, d->end(), d->begin()+f); - T *i = d->end(); - T* b = d->end()-n; - while (i != b) { - --i; - i->~T(); + abegin = qMax(abegin, d->begin()); + aend = qMin(aend, d->end()); + + Q_ASSERT(abegin <= aend); + + const int itemsToErase = aend - abegin; + const int itemsUntouched = abegin - d->begin(); + + // FIXME we could do a proper realloc, which copy constructs only needed data. + // FIXME we ara about to delete data maybe it is good time to shrink? + if (d->alloc) { + detach(); + if (QTypeInfo::isStatic) { + iterator moveBegin = abegin + itemsToErase; + iterator moveEnd = d->end(); + while (moveBegin != moveEnd) { + if (QTypeInfo::isComplex) + abegin->~T(); + new (abegin++) T(*moveBegin++); + } + if (abegin < d->end()) { + // destroy rest of instances + destruct(abegin, d->end()); + } + } else { + destruct(abegin, aend); + memmove(abegin, aend, (d->size - itemsToErase - itemsUntouched) * sizeof(T)); } - } else { - memmove(d->begin() + f, d->begin() + l, (d->size-l)*sizeof(T)); + d->size -= itemsToErase; } - d->size -= n; - return d->begin() + f; + return d->begin() + itemsUntouched; } template @@ -684,16 +719,18 @@ QVector &QVector::operator+=(const QVector &l) int newSize = d->size + l.d->size; realloc(d->size, newSize); - T *w = d->begin() + newSize; - T *i = l.d->end(); - T *b = l.d->begin(); - while (i != b) { - if (QTypeInfo::isComplex) - new (--w) T(*--i); - else - *--w = *--i; + if (d->alloc) { + T *w = d->begin() + newSize; + T *i = l.d->end(); + T *b = l.d->begin(); + while (i != b) { + if (QTypeInfo::isComplex) + new (--w) T(*--i); + else + *--w = *--i; + } + d->size = newSize; } - d->size = newSize; return *this; } diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 8ecb122..db20d10 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -4217,7 +4217,7 @@ QVector QRegion::rects() const if (d->qt_rgn) { d->qt_rgn->vectorize(); // hw: modify the vector size directly to avoid reallocation - if (d->qt_rgn->rects.d != &QVectorData::shared_null) + if (d->qt_rgn->rects.d != QVector::Data::sharedNull()) d->qt_rgn->rects.d->size = d->qt_rgn->numRects; return d->qt_rgn->rects; } else { diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp index 67ca547..56570b8 100644 --- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp +++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp @@ -42,24 +42,181 @@ #include #include +struct Movable { + Movable(char input = 'j') + : i(input) + , state(Constructed) + { + ++counter; + } + Movable(const Movable &other) + : i(other.i) + , state(Constructed) + { + check(other.state, Constructed); + ++counter; + } + + ~Movable() + { + check(state, Constructed); + i = 0; + --counter; + state = Destructed; + } + + bool operator ==(const Movable &other) const + { + check(state, Constructed); + check(other.state, Constructed); + return i == other.i; + } + + Movable &operator=(const Movable &other) + { + check(state, Constructed); + check(other.state, Constructed); + i = other.i; + return *this; + } + char i; + static int counter; +private: + enum State { Constructed = 106, Destructed = 110 }; + State state; + + static void check(const State state1, const State state2) + { + QCOMPARE(state1, state2); + } +}; + +int Movable::counter = 0; +QT_BEGIN_NAMESPACE +Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE); +QT_END_NAMESPACE +Q_DECLARE_METATYPE(Movable); + +struct Custom { + Custom(char input = 'j') + : i(input) + , that(this) + , state(Constructed) + { + ++counter; + } + Custom(const Custom &other) + : that(this) + , state(Constructed) + { + check(&other); + ++counter; + this->i = other.i; + } + ~Custom() + { + check(this); + i = 0; + --counter; + state = Destructed; + } + + bool operator ==(const Custom &other) const + { + check(&other); + check(this); + return i == other.i; + } + + Custom &operator=(const Custom &other) + { + check(&other); + check(this); + i = other.i; + return *this; + } + static int counter; + + char i; // used to identify orgin of an instance +private: + Custom *that; // used to check if an instance was moved + + enum State { Constructed = 106, Destructed = 110 }; + State state; + + static void check(const Custom *c) + { + // check if c object has been moved + QCOMPARE(c, c->that); + QCOMPARE(c->state, Constructed); + } +}; +int Custom::counter = 0; + +Q_DECLARE_METATYPE(Custom); + +// tests depends on the fact that: +Q_STATIC_ASSERT(!QTypeInfo::isStatic); +Q_STATIC_ASSERT(!QTypeInfo::isComplex); +Q_STATIC_ASSERT(!QTypeInfo::isStatic); +Q_STATIC_ASSERT(QTypeInfo::isComplex); +Q_STATIC_ASSERT(QTypeInfo::isStatic); +Q_STATIC_ASSERT(QTypeInfo::isComplex); + + class tst_QVector : public QObject { Q_OBJECT private slots: - void constructors() const; - void append() const; + void constructors_empty() const; + void constructors_emptyReserveZero() const; + void constructors_emptyReserve() const; + void constructors_reserveAndInitialize() const; + void copyConstructorInt() const; + void copyConstructorMovable() const; + void copyConstructorCustom() const; + void addInt() const; + void addMovable() const; + void addCustom() const; + void appendInt() const; + void appendMovable() const; + void appendCustom() const; void at() const; - void capacity() const; - void clear() const; + void capacityInt() const; + void capacityMovable() const; + void capacityCustom() const; + void clearInt() const; + void clearMovable() const; + void clearCustom() const; void constData() const; void contains() const; - void count() const; + void countInt() const; + void countMovable() const; + void countCustom() const; void data() const; - void empty() const; + void emptyInt() const; + void emptyMovable() const; + void emptyCustom() const; void endsWith() const; - void fill() const; + void eraseEmptyInt() const; + void eraseEmptyMovable() const; + void eraseEmptyCustom() const; + void eraseEmptyReservedInt() const; + void eraseEmptyReservedMovable() const; + void eraseEmptyReservedCustom() const; + void eraseInt() const; + void eraseMovable() const; + void eraseCustom() const; + void eraseReservedInt() const; + void eraseReservedMovable() const; + void eraseReservedCustom() const; + void fillInt() const; + void fillMovable() const; + void fillCustom() const; void first() const; - void fromList() const; + void fromListInt() const; + void fromListMovable() const; + void fromListCustom() const; void fromStdVector() const; void indexOf() const; void insert() const; @@ -67,11 +224,26 @@ private slots: void last() const; void lastIndexOf() const; void mid() const; - void prepend() const; - void remove() const; - void size() const; + void prependInt() const; + void prependMovable() const; + void prependCustom() const; + void removeInt() const; + void removeMovable() const; + void removeCustom() const; + void resizePOD_data() const; + void resizePOD() const; + void resizeComplexMovable_data() const; + void resizeComplexMovable() const; + void resizeComplex_data() const; + void resizeComplex() const; + void resizeCtorAndDtor() const; + void sizeInt() const; + void sizeMovable() const; + void sizeCustom() const; void startsWith() const; - void swap() const; + void swapInt() const; + void swapMovable() const; + void swapCustom() const; void toList() const; void toStdVector() const; void value() const; @@ -82,44 +254,272 @@ private slots: void reserve(); void reallocAfterCopy_data(); void reallocAfterCopy(); - void initializeList(); + void initializeListInt(); + void initializeListMovable(); + void initializeListCustom(); void const_shared_null(); - void setSharable_data(); - void setSharable(); + void setSharableInt_data(); + void setSharableInt(); + void setSharableMovable_data(); + void setSharableMovable(); + void setSharableCustom_data(); + void setSharableCustom(); + + void detachInt() const; + void detachMovable() const; + void detachCustom() const; +private: + template void copyConstructor() const; + template void add() const; + template void append() const; + template void capacity() const; + template void clear() const; + template void count() const; + template void empty() const; + template void eraseEmpty() const; + template void eraseEmptyReserved() const; + template void erase() const; + template void eraseReserved() const; + template void fill() const; + template void fromList() const; + template void prepend() const; + template void remove() const; + template void size() const; + template void swap() const; + template void initializeList(); + template void setSharable_data() const; + template void setSharable() const; + template void detach() const; }; -void tst_QVector::constructors() const +template struct SimpleValue { - // pre-reserve capacity + static T at(int index) { - QVector myvec(5); - - QVERIFY(myvec.capacity() == 5); + return Values[index % MaxIndex]; } + static const uint MaxIndex = 6; + static const T Values[MaxIndex]; +}; +template<> +const int SimpleValue::Values[] = { 110, 105, 101, 114, 111, 98 }; +template<> +const Movable SimpleValue::Values[] = { 110, 105, 101, 114, 111, 98 }; +template<> +const Custom SimpleValue::Values[] = { 110, 105, 101, 114, 111, 98 }; + +void tst_QVector::constructors_empty() const +{ + QVector emptyInt; + QVector emptyMovable; + QVector emptyCustom; +} + +void tst_QVector::constructors_emptyReserveZero() const +{ + QVector emptyInt(0); + QVector emptyMovable(0); + QVector emptyCustom(0); +} + +void tst_QVector::constructors_emptyReserve() const +{ + // pre-reserve capacity + QVector myInt(5); + QVERIFY(myInt.capacity() == 5); + QVector myMovable(5); + QVERIFY(myMovable.capacity() == 5); + QVector myCustom(4); + QVERIFY(myCustom.capacity() == 4); +} + +void tst_QVector::constructors_reserveAndInitialize() const +{ // default-initialise items + + QVector myInt(5, 42); + QVERIFY(myInt.capacity() == 5); + foreach (int meaningoflife, myInt) { + QCOMPARE(meaningoflife, 42); + } + + QVector myString(5, QString::fromLatin1("c++")); + QVERIFY(myString.capacity() == 5); + // make sure all items are initialised ok + foreach (QString meaningoflife, myString) { + QCOMPARE(meaningoflife, QString::fromLatin1("c++")); + } + + QVector myCustom(5, Custom('n')); + QVERIFY(myCustom.capacity() == 5); + // make sure all items are initialised ok + foreach (Custom meaningoflife, myCustom) { + QCOMPARE(meaningoflife.i, 'n'); + } +} + +template +void tst_QVector::copyConstructor() const +{ + T value1(SimpleValue::at(0)); + T value2(SimpleValue::at(1)); + T value3(SimpleValue::at(2)); + T value4(SimpleValue::at(3)); { - QVector myvec(5, 42); + QVector v1; + QVector v2(v1); + QCOMPARE(v1, v2); + } + { + QVector v1; + v1.setSharable(false); + QVector v2(v1); + QVERIFY(!v1.isSharedWith(v2)); + QCOMPARE(v1, v2); + } + { + QVector v1; + v1 << value1 << value2 << value3 << value4; + QVector v2(v1); + QCOMPARE(v1, v2); + } + { + QVector v1; + v1 << value1 << value2 << value3 << value4; + v1.setSharable(false); + QVector v2(v1); + QVERIFY(!v1.isSharedWith(v2)); + QCOMPARE(v1, v2); + } +} - QVERIFY(myvec.capacity() == 5); +void tst_QVector::copyConstructorInt() const +{ + copyConstructor(); +} - // make sure all items are initialised ok - foreach (int meaningoflife, myvec) { - QCOMPARE(meaningoflife, 42); - } +void tst_QVector::copyConstructorMovable() const +{ + const int instancesCount = Movable::counter; + copyConstructor(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::copyConstructorCustom() const +{ + const int instancesCount = Custom::counter; + copyConstructor(); + QCOMPARE(instancesCount, Custom::counter); +} + +template +void tst_QVector::add() const +{ + { + QVector empty1; + QVector empty2; + QVERIFY((empty1 + empty2).isEmpty()); + empty1 += empty2; + QVERIFY(empty1.isEmpty()); + QVERIFY(empty2.isEmpty()); } + { + QVector v(12); + QVector empty; + QCOMPARE((v + empty), v); + v += empty; + QVERIFY(!v.isEmpty()); + QCOMPARE(v.size(), 12); + QVERIFY(empty.isEmpty()); + } + { + QVector v1(12); + QVector v2; + v2 += v1; + QVERIFY(!v1.isEmpty()); + QCOMPARE(v1.size(), 12); + QVERIFY(!v2.isEmpty()); + QCOMPARE(v2.size(), 12); + } +} + +void tst_QVector::addInt() const +{ + add(); +} + +void tst_QVector::addMovable() const +{ + const int instancesCount = Movable::counter; + add(); + QCOMPARE(instancesCount, Movable::counter); } +void tst_QVector::addCustom() const +{ + const int instancesCount = Custom::counter; + add(); + QCOMPARE(instancesCount, Custom::counter); +} + +template void tst_QVector::append() const { - QVector myvec; - myvec.append(42); - myvec.append(43); - myvec.append(44); + { + QVector myvec; + myvec.append(SimpleValue::at(0)); + QVERIFY(myvec.size() == 1); + myvec.append(SimpleValue::at(1)); + QVERIFY(myvec.size() == 2); + myvec.append(SimpleValue::at(2)); + QVERIFY(myvec.size() == 3); - QVERIFY(myvec.size() == 3); - QCOMPARE(myvec, QVector() << 42 << 43 << 44); + QCOMPARE(myvec, QVector() << SimpleValue::at(0) + << SimpleValue::at(1) + << SimpleValue::at(2)); + } + { + QVector v(2); + v.append(SimpleValue::at(0)); + QVERIFY(v.size() == 3); + QCOMPARE(v.at(v.size() - 1), SimpleValue::at(0)); + } + { + QVector v(2); + v.reserve(12); + v.append(SimpleValue::at(0)); + QVERIFY(v.size() == 3); + QCOMPARE(v.at(v.size() - 1), SimpleValue::at(0)); + } + { + QVector v(2); + v.reserve(12); + v.setSharable(false); + v.append(SimpleValue::at(0)); + QVERIFY(v.size() == 3); + QCOMPARE(v.last(), SimpleValue::at(0)); + } +} + +void tst_QVector::appendInt() const +{ + append(); +} + +void tst_QVector::appendMovable() const +{ + const int instancesCount = Movable::counter; + append(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::appendCustom() const +{ + const int instancesCount = Custom::counter; + append(); + QCOMPARE(instancesCount, Custom::counter); } void tst_QVector::at() const @@ -148,20 +548,21 @@ void tst_QVector::at() const QCOMPARE(myvec.at(2), QLatin1String("hello")); } +template void tst_QVector::capacity() const { - QVector myvec; + QVector myvec; // TODO: is this guaranteed? seems a safe assumption, but I suppose preallocation of a // few items isn't an entirely unforseeable possibility. QVERIFY(myvec.capacity() == 0); // test it gets a size - myvec << "aaa" << "bbb" << "ccc"; + myvec << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2); QVERIFY(myvec.capacity() >= 3); // make sure it grows ok - myvec << "aaa" << "bbb" << "ccc"; + myvec << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2); QVERIFY(myvec.capacity() >= 6); // let's try squeeze a bit @@ -182,10 +583,30 @@ void tst_QVector::capacity() const QVERIFY(myvec.capacity() == 0); } +void tst_QVector::capacityInt() const +{ + capacity(); +} + +void tst_QVector::capacityMovable() const +{ + const int instancesCount = Movable::counter; + capacity(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::capacityCustom() const +{ + const int instancesCount = Custom::counter; + capacity(); + QCOMPARE(instancesCount, Custom::counter); +} + +template void tst_QVector::clear() const { - QVector myvec; - myvec << "aaa" << "bbb" << "ccc"; + QVector myvec; + myvec << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2); QVERIFY(myvec.size() == 3); myvec.clear(); @@ -193,6 +614,25 @@ void tst_QVector::clear() const QVERIFY(myvec.capacity() == 0); } +void tst_QVector::clearInt() const +{ + clear(); +} + +void tst_QVector::clearMovable() const +{ + const int instancesCount = Movable::counter; + clear(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::clearCustom() const +{ + const int instancesCount = Custom::counter; + clear(); + QCOMPARE(instancesCount, Custom::counter); +} + void tst_QVector::constData() const { int arr[] = { 42, 43, 44 }; @@ -217,18 +657,19 @@ void tst_QVector::contains() const QVERIFY(myvec.contains(QLatin1String("I don't exist"))); } +template void tst_QVector::count() const { // total size { // zero size - QVector myvec; + QVector myvec; QVERIFY(myvec.count() == 0); // grow - myvec.append(42); + myvec.append(SimpleValue::at(0)); QVERIFY(myvec.count() == 1); - myvec.append(42); + myvec.append(SimpleValue::at(1)); QVERIFY(myvec.count() == 2); // shrink @@ -240,23 +681,42 @@ void tst_QVector::count() const // count of items { - QVector myvec; - myvec << "aaa" << "bbb" << "ccc"; + QVector myvec; + myvec << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2); // initial tests - QVERIFY(myvec.count(QLatin1String("aaa")) == 1); - QVERIFY(myvec.count(QLatin1String("pirates")) == 0); + QVERIFY(myvec.count(SimpleValue::at(0)) == 1); + QVERIFY(myvec.count(SimpleValue::at(3)) == 0); // grow - myvec.append(QLatin1String("aaa")); - QVERIFY(myvec.count(QLatin1String("aaa")) == 2); + myvec.append(SimpleValue::at(0)); + QVERIFY(myvec.count(SimpleValue::at(0)) == 2); // shrink myvec.remove(0); - QVERIFY(myvec.count(QLatin1String("aaa")) == 1); + QVERIFY(myvec.count(SimpleValue::at(0)) == 1); } } +void tst_QVector::countInt() const +{ + count(); +} + +void tst_QVector::countMovable() const +{ + const int instancesCount = Movable::counter; + count(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::countCustom() const +{ + const int instancesCount = Custom::counter; + count(); + QCOMPARE(instancesCount, Custom::counter); +} + void tst_QVector::data() const { QVector myvec; @@ -275,15 +735,16 @@ void tst_QVector::data() const QVERIFY(memcmp(myvec.data(), reinterpret_cast(&arr), sizeof(int) * 3) == 0); } +template void tst_QVector::empty() const { - QVector myvec; + QVector myvec; // starts empty QVERIFY(myvec.empty()); // not empty - myvec.append(1); + myvec.append(SimpleValue::at(2)); QVERIFY(!myvec.empty()); // empty again @@ -291,6 +752,25 @@ void tst_QVector::empty() const QVERIFY(myvec.empty()); } +void tst_QVector::emptyInt() const +{ + empty(); +} + +void tst_QVector::emptyMovable() const +{ + const int instancesCount = Movable::counter; + empty(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::emptyCustom() const +{ + const int instancesCount = Custom::counter; + empty(); + QCOMPARE(instancesCount, Custom::counter); +} + void tst_QVector::endsWith() const { QVector myvec; @@ -311,18 +791,244 @@ void tst_QVector::endsWith() const QVERIFY(myvec.endsWith(1)); } +template +void tst_QVector::eraseEmpty() const +{ + { + QVector v; + v.erase(v.begin()); + QCOMPARE(v.size(), 0); + v.erase(v.begin(), v.end()); + QCOMPARE(v.size(), 0); + } + { + QVector v; + v.setSharable(false); + v.erase(v.begin()); + QCOMPARE(v.size(), 0); + v.erase(v.begin(), v.end()); + QCOMPARE(v.size(), 0); + } +} + +void tst_QVector::eraseEmptyInt() const +{ + eraseEmpty(); +} + +void tst_QVector::eraseEmptyMovable() const +{ + const int instancesCount = Movable::counter; + eraseEmpty(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::eraseEmptyCustom() const +{ + const int instancesCount = Custom::counter; + eraseEmpty(); + QCOMPARE(instancesCount, Custom::counter); +} + +template +void tst_QVector::eraseEmptyReserved() const +{ + { + QVector v; + v.reserve(10); + v.erase(v.begin()); + QCOMPARE(v.size(), 0); + v.erase(v.begin(), v.end()); + QCOMPARE(v.size(), 0); + } + { + QVector v; + v.reserve(10); + v.setSharable(false); + v.erase(v.begin()); + QCOMPARE(v.size(), 0); + v.erase(v.begin(), v.end()); + QCOMPARE(v.size(), 0); + } +} + +void tst_QVector::eraseEmptyReservedInt() const +{ + eraseEmptyReserved(); +} + +void tst_QVector::eraseEmptyReservedMovable() const +{ + const int instancesCount = Movable::counter; + eraseEmptyReserved(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::eraseEmptyReservedCustom() const +{ + const int instancesCount = Custom::counter; + eraseEmptyReserved(); + QCOMPARE(instancesCount, Custom::counter); +} + +template +void tst_QVector::erase() const +{ + { + QVector v(12); + v.erase(v.begin()); + QCOMPARE(v.size(), 11); + v.erase(v.begin(), v.end()); + QCOMPARE(v.size(), 0); + } + { + QVector v(12); + v.erase(v.begin() + 1); + QCOMPARE(v.size(), 11); + v.erase(v.begin() + 1, v.end()); + QCOMPARE(v.size(), 1); + } + { + QVector v(12); + v.erase(v.begin(), v.end() - 1); + QCOMPARE(v.size(), 1); + } + { + QVector v(12); + v.erase(v.begin() + 5); + QCOMPARE(v.size(), 11); + v.erase(v.begin() + 1, v.end() - 1); + QCOMPARE(v.size(), 2); + } + { + QVector v(10); + v.setSharable(false); + v.erase(v.begin() + 3); + QCOMPARE(v.size(), 9); + v.erase(v.begin(), v.end() - 1); + QCOMPARE(v.size(), 1); + } +} + +void tst_QVector::eraseInt() const +{ + erase(); +} + +void tst_QVector::eraseMovable() const +{ + const int instancesCount = Movable::counter; + erase(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::eraseCustom() const +{ + const int instancesCount = Custom::counter; + erase(); + QCOMPARE(instancesCount, Custom::counter); +} + +template void tst_QVector::eraseReserved() const +{ + { + QVector v(12); + v.reserve(16); + v.erase(v.begin()); + QCOMPARE(v.size(), 11); + v.erase(v.begin(), v.end()); + QCOMPARE(v.size(), 0); + } + { + QVector v(12); + v.reserve(16); + v.erase(v.begin() + 1); + QCOMPARE(v.size(), 11); + v.erase(v.begin() + 1, v.end()); + QCOMPARE(v.size(), 1); + } + { + QVector v(12); + v.reserve(16); + v.erase(v.begin(), v.end() - 1); + QCOMPARE(v.size(), 1); + } + { + QVector v(12); + v.reserve(16); + v.erase(v.begin() + 5); + QCOMPARE(v.size(), 11); + v.erase(v.begin() + 1, v.end() - 1); + QCOMPARE(v.size(), 2); + } + { + QVector v(10); + v.reserve(16); + v.setSharable(false); + v.erase(v.begin() + 3); + QCOMPARE(v.size(), 9); + v.erase(v.begin(), v.end() - 1); + QCOMPARE(v.size(), 1); + } +} + +void tst_QVector::eraseReservedInt() const +{ + eraseReserved(); +} + +void tst_QVector::eraseReservedMovable() const +{ + const int instancesCount = Movable::counter; + eraseReserved(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::eraseReservedCustom() const +{ + const int instancesCount = Custom::counter; + eraseReserved(); + QCOMPARE(instancesCount, Custom::counter); +} + +template void tst_QVector::fill() const { - QVector myvec; + QVector myvec; // resize myvec.resize(5); - myvec.fill(69); - QCOMPARE(myvec, QVector() << 69 << 69 << 69 << 69 << 69); + myvec.fill(SimpleValue::at(1)); + QCOMPARE(myvec, QVector() << SimpleValue::at(1) << SimpleValue::at(1) + << SimpleValue::at(1) << SimpleValue::at(1) + << SimpleValue::at(1)); // make sure it can resize itself too - myvec.fill(42, 10); - QCOMPARE(myvec, QVector() << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42); + myvec.fill(SimpleValue::at(2), 10); + QCOMPARE(myvec, QVector() << SimpleValue::at(2) << SimpleValue::at(2) + << SimpleValue::at(2) << SimpleValue::at(2) + << SimpleValue::at(2) << SimpleValue::at(2) + << SimpleValue::at(2) << SimpleValue::at(2) + << SimpleValue::at(2) << SimpleValue::at(2)); +} + +void tst_QVector::fillInt() const +{ + fill(); +} + +void tst_QVector::fillMovable() const +{ + const int instancesCount = Movable::counter; + fill(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::fillCustom() const +{ + const int instancesCount = Custom::counter; + fill(); + QCOMPARE(instancesCount, Custom::counter); } void tst_QVector::first() const @@ -342,17 +1048,37 @@ void tst_QVector::first() const QCOMPARE(myvec.first(), 23); } +template void tst_QVector::fromList() const { - QList list; - list << "aaa" << "bbb" << "ninjas" << "pirates"; + QList list; + list << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2) << SimpleValue::at(3); - QVector myvec; - myvec = QVector::fromList(list); + QVector myvec; + myvec = QVector::fromList(list); // test it worked ok - QCOMPARE(myvec, QVector() << "aaa" << "bbb" << "ninjas" << "pirates"); - QCOMPARE(list, QList() << "aaa" << "bbb" << "ninjas" << "pirates"); + QCOMPARE(myvec, QVector() << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2) << SimpleValue::at(3)); + QCOMPARE(list, QList() << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2) << SimpleValue::at(3)); +} + +void tst_QVector::fromListInt() const +{ + fromList(); +} + +void tst_QVector::fromListMovable() const +{ + const int instancesCount = Movable::counter; + fromList(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::fromListCustom() const +{ + const int instancesCount = Custom::counter; + fromList(); + QCOMPARE(instancesCount, Custom::counter); } void tst_QVector::fromStdVector() const @@ -486,73 +1212,382 @@ void tst_QVector::mid() const QCOMPARE(list.mid(4), QVector() << "buck" << "hello" << "kitty"); } +template void tst_QVector::prepend() const { - QVector myvec; - myvec << "A" << "B" << "C"; + QVector myvec; + T val1 = SimpleValue::at(0); + T val2 = SimpleValue::at(1); + T val3 = SimpleValue::at(2); + T val4 = SimpleValue::at(3); + T val5 = SimpleValue::at(4); + myvec << val1 << val2 << val3; // starts ok QVERIFY(myvec.size() == 3); - QCOMPARE(myvec.at(0), QLatin1String("A")); + QCOMPARE(myvec.at(0), val1); // add something - myvec.prepend(QLatin1String("X")); - QCOMPARE(myvec.at(0), QLatin1String("X")); - QCOMPARE(myvec.at(1), QLatin1String("A")); + myvec.prepend(val4); + QCOMPARE(myvec.at(0), val4); + QCOMPARE(myvec.at(1), val1); QVERIFY(myvec.size() == 4); // something else - myvec.prepend(QLatin1String("Z")); - QCOMPARE(myvec.at(0), QLatin1String("Z")); - QCOMPARE(myvec.at(1), QLatin1String("X")); - QCOMPARE(myvec.at(2), QLatin1String("A")); + myvec.prepend(val5); + QCOMPARE(myvec.at(0), val5); + QCOMPARE(myvec.at(1), val4); + QCOMPARE(myvec.at(2), val1); QVERIFY(myvec.size() == 5); - // clear and append to an empty vector + // clear and prepend to an empty vector myvec.clear(); QVERIFY(myvec.size() == 0); - myvec.prepend(QLatin1String("ninjas")); + myvec.prepend(val5); QVERIFY(myvec.size() == 1); - QCOMPARE(myvec.at(0), QLatin1String("ninjas")); + QCOMPARE(myvec.at(0), val5); } -void tst_QVector::remove() const +void tst_QVector::prependInt() const { - QVector myvec; - myvec << "A" << "B" << "C"; + prepend(); +} + +void tst_QVector::prependMovable() const +{ + const int instancesCount = Movable::counter; + prepend(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::prependCustom() const +{ + const int instancesCount = Custom::counter; + prepend(); + QCOMPARE(instancesCount, Custom::counter); +} +template +void tst_QVector::remove() const +{ + QVector myvec; + T val1 = SimpleValue::at(1); + T val2 = SimpleValue::at(2); + T val3 = SimpleValue::at(3); + myvec << val1 << val2 << val3; // remove middle myvec.remove(1); - QCOMPARE(myvec, QVector() << "A" << "C"); + QCOMPARE(myvec, QVector() << val1 << val3); // remove rest myvec.remove(0, 2); - QCOMPARE(myvec, QVector()); + QCOMPARE(myvec, QVector()); } -// ::reserve() is really hard to think of tests for, so not doing it. -// ::resize() is tested in ::capacity(). +void tst_QVector::removeInt() const +{ + remove(); +} -void tst_QVector::size() const +void tst_QVector::removeMovable() const { - // total size + const int instancesCount = Movable::counter; + remove(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::removeCustom() const +{ + const int instancesCount = Custom::counter; + remove(); + QCOMPARE(instancesCount, Custom::counter); +} + +void tst_QVector::resizePOD_data() const +{ + QTest::addColumn >("vector"); + QTest::addColumn("size"); + + QVERIFY(!QTypeInfo::isComplex); + QVERIFY(!QTypeInfo::isStatic); + + QVector null; + QVector empty(0, 5); + QVector emptyReserved; + QVector nonEmpty; + QVector nonEmptyReserved; + + emptyReserved.reserve(10); + nonEmptyReserved.reserve(15); + nonEmpty << 0 << 1 << 2 << 3 << 4; + nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6; + QVERIFY(emptyReserved.capacity() >= 10); + QVERIFY(nonEmptyReserved.capacity() >= 15); + + QVector nullNotShared; + QVector emptyNotShared(0, 5); + QVector emptyReservedNotShared; + QVector nonEmptyNotShared; + QVector nonEmptyReservedNotShared; + + emptyReservedNotShared.reserve(10); + nonEmptyReservedNotShared.reserve(15); + nonEmptyNotShared << 0 << 1 << 2 << 3 << 4; + nonEmptyReservedNotShared << 0 << 1 << 2 << 3 << 4 << 5 << 6; + QVERIFY(emptyReservedNotShared.capacity() >= 10); + QVERIFY(nonEmptyReservedNotShared.capacity() >= 15); + + emptyNotShared.setSharable(false); + emptyReservedNotShared.setSharable(false); + nonEmptyNotShared.setSharable(false); + nonEmptyReservedNotShared.setSharable(false); + + QTest::newRow("null") << null << 10; + QTest::newRow("empty") << empty << 10; + QTest::newRow("emptyReserved") << emptyReserved << 10; + QTest::newRow("nonEmpty") << nonEmpty << 10; + QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; + QTest::newRow("nullNotShared") << nullNotShared << 10; + QTest::newRow("emptyNotShared") << emptyNotShared << 10; + QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; + QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; + QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; +} + +void tst_QVector::resizePOD() const +{ + QFETCH(QVector, vector); + QFETCH(int, size); + + const int oldSize = vector.size(); + + vector.resize(size); + QCOMPARE(vector.size(), size); + QVERIFY(vector.capacity() >= size); + for (int i = oldSize; i < size; ++i) + QVERIFY(vector[i] == 0); // check initialization + + const int capacity = vector.capacity(); + + vector.resize(0); + QCOMPARE(vector.size(), 0); + QVERIFY(vector.capacity() <= capacity); +} + +void tst_QVector::resizeComplexMovable_data() const +{ + QTest::addColumn >("vector"); + QTest::addColumn("size"); + + QVERIFY(QTypeInfo::isComplex); + QVERIFY(!QTypeInfo::isStatic); + + QVector null; + QVector empty(0, 'Q'); + QVector emptyReserved; + QVector nonEmpty; + QVector nonEmptyReserved; + + emptyReserved.reserve(10); + nonEmptyReserved.reserve(15); + nonEmpty << '0' << '1' << '2' << '3' << '4'; + nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6'; + QVERIFY(emptyReserved.capacity() >= 10); + QVERIFY(nonEmptyReserved.capacity() >= 15); + + QVector nullNotShared; + QVector emptyNotShared(0, 'Q'); + QVector emptyReservedNotShared; + QVector nonEmptyNotShared; + QVector nonEmptyReservedNotShared; + + emptyReservedNotShared.reserve(10); + nonEmptyReservedNotShared.reserve(15); + nonEmptyNotShared << '0' << '1' << '2' << '3' << '4'; + nonEmptyReservedNotShared << '0' << '1' << '2' << '3' << '4' << '5' << '6'; + QVERIFY(emptyReservedNotShared.capacity() >= 10); + QVERIFY(nonEmptyReservedNotShared.capacity() >= 15); + + emptyNotShared.setSharable(false); + emptyReservedNotShared.setSharable(false); + nonEmptyNotShared.setSharable(false); + nonEmptyReservedNotShared.setSharable(false); + + QTest::newRow("null") << null << 10; + QTest::newRow("empty") << empty << 10; + QTest::newRow("emptyReserved") << emptyReserved << 10; + QTest::newRow("nonEmpty") << nonEmpty << 10; + QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; + QTest::newRow("nullNotShared") << nullNotShared << 10; + QTest::newRow("emptyNotShared") << emptyNotShared << 10; + QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; + QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; + QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; +} + +void tst_QVector::resizeComplexMovable() const +{ + const int items = Movable::counter; { - // zero size - QVector myvec; - QVERIFY(myvec.size() == 0); + QFETCH(QVector, vector); + QFETCH(int, size); - // grow - myvec.append(42); - QVERIFY(myvec.size() == 1); - myvec.append(42); - QVERIFY(myvec.size() == 2); + const int oldSize = vector.size(); - // shrink - myvec.remove(0); - QVERIFY(myvec.size() == 1); - myvec.remove(0); - QVERIFY(myvec.size() == 0); + vector.resize(size); + QCOMPARE(vector.size(), size); + QVERIFY(vector.capacity() >= size); + for (int i = oldSize; i < size; ++i) + QVERIFY(vector[i] == 'j'); // check initialization + + const int capacity = vector.capacity(); + + vector.resize(0); + QCOMPARE(vector.size(), 0); + QVERIFY(vector.capacity() <= capacity); + } + QCOMPARE(items, Movable::counter); +} + +void tst_QVector::resizeComplex_data() const +{ + QTest::addColumn >("vector"); + QTest::addColumn("size"); + + QVERIFY(QTypeInfo::isComplex); + QVERIFY(QTypeInfo::isStatic); + + QVector null; + QVector empty(0, '0'); + QVector emptyReserved; + QVector nonEmpty; + QVector nonEmptyReserved; + + emptyReserved.reserve(10); + nonEmptyReserved.reserve(15); + nonEmpty << '0' << '1' << '2' << '3' << '4'; + nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6'; + QVERIFY(emptyReserved.capacity() >= 10); + QVERIFY(nonEmptyReserved.capacity() >= 15); + + QVector nullNotShared; + QVector emptyNotShared(0, '0'); + QVector emptyReservedNotShared; + QVector nonEmptyNotShared; + QVector nonEmptyReservedNotShared; + + emptyReservedNotShared.reserve(10); + nonEmptyReservedNotShared.reserve(15); + nonEmptyNotShared << '0' << '1' << '2' << '3' << '4'; + nonEmptyReservedNotShared << '0' << '1' << '2' << '3' << '4' << '5' << '6'; + QVERIFY(emptyReservedNotShared.capacity() >= 10); + QVERIFY(nonEmptyReservedNotShared.capacity() >= 15); + + emptyNotShared.setSharable(false); + emptyReservedNotShared.setSharable(false); + nonEmptyNotShared.setSharable(false); + nonEmptyReservedNotShared.setSharable(false); + + QTest::newRow("null") << null << 10; + QTest::newRow("empty") << empty << 10; + QTest::newRow("emptyReserved") << emptyReserved << 10; + QTest::newRow("nonEmpty") << nonEmpty << 10; + QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; + QTest::newRow("nullNotShared") << nullNotShared << 10; + QTest::newRow("emptyNotShared") << emptyNotShared << 10; + QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; + QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; + QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; +} + +void tst_QVector::resizeComplex() const +{ + const int items = Custom::counter; + { + QFETCH(QVector, vector); + QFETCH(int, size); + + int oldSize = vector.size(); + vector.resize(size); + QCOMPARE(vector.size(), size); + QVERIFY(vector.capacity() >= size); + for (int i = oldSize; i < size; ++i) + QVERIFY(vector[i].i == 'j'); // check default initialization + + const int capacity = vector.capacity(); + + vector.resize(0); + QCOMPARE(vector.size(), 0); + QVERIFY(vector.isEmpty()); + QVERIFY(vector.capacity() <= capacity); } + QCOMPARE(Custom::counter, items); +} + +void tst_QVector::resizeCtorAndDtor() const +{ + const int items = Custom::counter; + { + QVector null; + QVector empty(0, '0'); + QVector emptyReserved; + QVector nonEmpty; + QVector nonEmptyReserved; + + emptyReserved.reserve(10); + nonEmptyReserved.reserve(15); + nonEmpty << '0' << '1' << '2' << '3' << '4'; + nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6'; + QVERIFY(emptyReserved.capacity() >= 10); + QVERIFY(nonEmptyReserved.capacity() >= 15); + + // start playing with vectors + null.resize(21); + nonEmpty.resize(2); + emptyReserved.resize(0); + nonEmpty.resize(0); + nonEmptyReserved.resize(2); + } + QCOMPARE(Custom::counter, items); +} + +template +void tst_QVector::size() const +{ + // zero size + QVector myvec; + QVERIFY(myvec.size() == 0); + + // grow + myvec.append(SimpleValue::at(0)); + QVERIFY(myvec.size() == 1); + myvec.append(SimpleValue::at(1)); + QVERIFY(myvec.size() == 2); + + // shrink + myvec.remove(0); + QVERIFY(myvec.size() == 1); + myvec.remove(0); + QVERIFY(myvec.size() == 0); +} + +void tst_QVector::sizeInt() const +{ + size(); +} + +void tst_QVector::sizeMovable() const +{ + const int instancesCount = Movable::counter; + size(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::sizeCustom() const +{ + const int instancesCount = Custom::counter; + size(); + QCOMPARE(instancesCount, Custom::counter); } // ::squeeze() is tested in ::capacity(). @@ -577,15 +1612,41 @@ void tst_QVector::startsWith() const QVERIFY(myvec.startsWith(1)); } +template void tst_QVector::swap() const { - QVector v1, v2; - v1 << 1 << 2 << 3; - v2 << 4 << 5 << 6; + QVector v1, v2; + T val1 = SimpleValue::at(0); + T val2 = SimpleValue::at(1); + T val3 = SimpleValue::at(2); + T val4 = SimpleValue::at(3); + T val5 = SimpleValue::at(4); + T val6 = SimpleValue::at(5); + v1 << val1 << val2 << val3; + v2 << val4 << val5 << val6; v1.swap(v2); - QCOMPARE(v1,QVector() << 4 << 5 << 6); - QCOMPARE(v2,QVector() << 1 << 2 << 3); + QCOMPARE(v1,QVector() << val4 << val5 << val6); + QCOMPARE(v2,QVector() << val1 << val2 << val3); +} + +void tst_QVector::swapInt() const +{ + swap(); +} + +void tst_QVector::swapMovable() const +{ + const int instancesCount = Movable::counter; + swap(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::swapCustom() const +{ + const int instancesCount = Custom::counter; + swap(); + QCOMPARE(instancesCount, Custom::counter); } void tst_QVector::toList() const @@ -923,20 +1984,45 @@ void tst_QVector::reallocAfterCopy() QCOMPARE(v2.size(), result4); } +template void tst_QVector::initializeList() { #ifdef Q_COMPILER_INITIALIZER_LISTS - QVector v1{2,3,4}; - QCOMPARE(v1, QVector() << 2 << 3 << 4); - QCOMPARE(v1, (QVector{2,3,4})); - - QVector> v2{ v1, {1}, QVector(), {2,3,4} }; - QVector> v3; - v3 << v1 << (QVector() << 1) << QVector() << v1; + T val1(SimpleValue::at(1)); + T val2(SimpleValue::at(2)); + T val3(SimpleValue::at(3)); + T val4(SimpleValue::at(4)); + + QVector v1 {val1, val2, val3}; + QCOMPARE(v1, QVector() << val1 << val2 << val3); + QCOMPARE(v1, (QVector {val1, val2, val3})); + + QVector> v2{ v1, {val4}, QVector(), {val1, val2, val3} }; + QVector> v3; + v3 << v1 << (QVector() << val4) << QVector() << v1; QCOMPARE(v3, v2); #endif } +void tst_QVector::initializeListInt() +{ + initializeList(); +} + +void tst_QVector::initializeListMovable() +{ + const int instancesCount = Movable::counter; + initializeList(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::initializeListCustom() +{ + const int instancesCount = Custom::counter; + initializeList(); + QCOMPARE(instancesCount, Custom::counter); +} + void tst_QVector::const_shared_null() { QVector v1; @@ -950,24 +2036,25 @@ void tst_QVector::const_shared_null() Q_DECLARE_METATYPE(QVector); -void tst_QVector::setSharable_data() +template +void tst_QVector::setSharable_data() const { - QTest::addColumn >("vector"); + QTest::addColumn >("vector"); QTest::addColumn("size"); QTest::addColumn("capacity"); QTest::addColumn("isCapacityReserved"); - QVector null; - QVector empty(0, 5); - QVector emptyReserved; - QVector nonEmpty; - QVector nonEmptyReserved; + QVector null; + QVector empty(0, SimpleValue::at(1)); + QVector emptyReserved; + QVector nonEmpty; + QVector nonEmptyReserved; emptyReserved.reserve(10); nonEmptyReserved.reserve(15); - nonEmpty << 0 << 1 << 2 << 3 << 4; - nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6; + nonEmpty << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2) << SimpleValue::at(3) << SimpleValue::at(4); + nonEmptyReserved << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2) << SimpleValue::at(3) << SimpleValue::at(4) << SimpleValue::at(5) << SimpleValue::at(6); QVERIFY(emptyReserved.capacity() >= 10); QVERIFY(nonEmptyReserved.capacity() >= 15); @@ -979,9 +2066,25 @@ void tst_QVector::setSharable_data() QTest::newRow("non-empty, Reserved") << nonEmptyReserved << 7 << 15 << true; } -void tst_QVector::setSharable() +void tst_QVector::setSharableInt_data() { - QFETCH(QVector, vector); + setSharable_data(); +} + +void tst_QVector::setSharableMovable_data() +{ + setSharable_data(); +} + +void tst_QVector::setSharableCustom_data() +{ + setSharable_data(); +} + +template +void tst_QVector::setSharable() const +{ + QFETCH(QVector, vector); QFETCH(int, size); QFETCH(int, capacity); QFETCH(bool, isCapacityReserved); @@ -998,19 +2101,19 @@ void tst_QVector::setSharable() .arg(capacity))); { - QVector copy(vector); + QVector copy(vector); QVERIFY(!copy.isDetached()); QVERIFY(copy.isSharedWith(vector)); } vector.setSharable(false); - QVERIFY(vector.isDetached() || vector.isSharedWith(QVector())); + QVERIFY(vector.isDetached() || vector.isSharedWith(QVector())); { - QVector copy(vector); + QVector copy(vector); - QVERIFY(copy.isDetached() || copy.isSharedWith(QVector())); + QVERIFY(copy.isDetached() || copy.isEmpty() || copy.isSharedWith(QVector())); QCOMPARE(copy.size(), size); if (isCapacityReserved) QVERIFY2(copy.capacity() >= capacity, @@ -1023,14 +2126,14 @@ void tst_QVector::setSharable() vector.setSharable(true); { - QVector copy(vector); + QVector copy(vector); QVERIFY(!copy.isDetached()); QVERIFY(copy.isSharedWith(vector)); } for (int i = 0; i < vector.size(); ++i) - QCOMPARE(vector[i], i); + QCOMPARE(vector[i], SimpleValue::at(i)); QCOMPARE(vector.size(), size); if (isCapacityReserved) @@ -1040,5 +2143,140 @@ void tst_QVector::setSharable() .arg(capacity))); } +void tst_QVector::setSharableInt() +{ + setSharable(); +} + +void tst_QVector::setSharableMovable() +{ + const int instancesCount = Movable::counter; + setSharable(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::setSharableCustom() +{ + const int instancesCount = Custom::counter; + setSharable(); + QCOMPARE(instancesCount, Custom::counter); +} + +template +void tst_QVector::detach() const +{ + { + // detach an empty vector + QVector v; + v.detach(); + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 0); + QCOMPARE(v.capacity(), 0); + } + { + // detach an empty referenced vector + QVector v; + QVector ref(v); + QVERIFY(!v.isDetached()); + v.detach(); + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 0); + QCOMPARE(v.capacity(), 0); + } + { + // detach a not empty referenced vector + QVector v(31); + QVector ref(v); + QVERIFY(!v.isDetached()); + v.detach(); + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 31); + QCOMPARE(v.capacity(), 31); + } + { + // detach a not empty vector + QVector v(31); + QVERIFY(v.isDetached()); + v.detach(); // detaching a detached vector + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 31); + QCOMPARE(v.capacity(), 31); + } + { + // detach a not empty vector with preallocated space + QVector v(3); + v.reserve(8); + QVector ref(v); + QVERIFY(!v.isDetached()); + v.detach(); + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 3); + QCOMPARE(v.capacity(), 8); + } + { + // detach a not empty vector with preallocated space + QVector v(3); + v.reserve(8); + QVERIFY(v.isDetached()); + v.detach(); // detaching a detached vector + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 3); + QCOMPARE(v.capacity(), 8); + } + { + // detach a not empty, initialized vector + QVector v(7, SimpleValue::at(1)); + QVector ref(v); + QVERIFY(!v.isDetached()); + v.detach(); + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 7); + for (int i = 0; i < v.size(); ++i) + QCOMPARE(v[i], SimpleValue::at(1)); + } + { + // detach a not empty, initialized vector + QVector v(7, SimpleValue::at(2)); + QVERIFY(v.isDetached()); + v.detach(); // detaching a detached vector + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 7); + for (int i = 0; i < v.size(); ++i) + QCOMPARE(v[i], SimpleValue::at(2)); + } + { + // detach a not empty, initialized vector with preallocated space + QVector v(7, SimpleValue::at(3)); + v.reserve(31); + QVector ref(v); + QVERIFY(!v.isDetached()); + v.detach(); + QVERIFY(v.isDetached()); + QCOMPARE(v.size(), 7); + QCOMPARE(v.capacity(), 31); + for (int i = 0; i < v.size(); ++i) + QCOMPARE(v[i], SimpleValue::at(3)); + } +} + +void tst_QVector::detachInt() const +{ + detach(); +} + +void tst_QVector::detachMovable() const +{ + const int instancesCount = Movable::counter; + detach(); + QCOMPARE(instancesCount, Movable::counter); +} + +void tst_QVector::detachCustom() const +{ + const int instancesCount = Custom::counter; + detach(); + QCOMPARE(instancesCount, Custom::counter); +} + QTEST_APPLESS_MAIN(tst_QVector) #include "tst_qvector.moc" diff --git a/tests/benchmarks/corelib/tools/qvector/outofline.cpp b/tests/benchmarks/corelib/tools/qvector/outofline.cpp index bf92978..1388128 100644 --- a/tests/benchmarks/corelib/tools/qvector/outofline.cpp +++ b/tests/benchmarks/corelib/tools/qvector/outofline.cpp @@ -79,3 +79,36 @@ std::vector stdvector_fill_and_return_helper() return v; } +const QVectorData QVectorData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, false, 0 }; + +static inline int alignmentThreshold() +{ + // malloc on 32-bit platforms should return pointers that are 8-byte aligned or more + // while on 64-bit platforms they should be 16-byte aligned or more + return 2 * sizeof(void*); +} + +QVectorData *QVectorData::allocate(int size, int alignment) +{ + return static_cast(alignment > alignmentThreshold() ? qMallocAligned(size, alignment) : ::malloc(size)); +} + +QVectorData *QVectorData::reallocate(QVectorData *x, int newsize, int oldsize, int alignment) +{ + if (alignment > alignmentThreshold()) + return static_cast(qReallocAligned(x, newsize, oldsize, alignment)); + return static_cast(realloc(x, newsize)); +} + +void QVectorData::free(QVectorData *x, int alignment) +{ + if (alignment > alignmentThreshold()) + qFreeAligned(x); + else + ::free(x); +} + +int QVectorData::grow(int sizeOfHeader, int size, int sizeOfT) +{ + return qAllocMore(size * sizeOfT, sizeOfHeader) / sizeOfT; +} diff --git a/tests/benchmarks/corelib/tools/qvector/qrawvector.h b/tests/benchmarks/corelib/tools/qvector/qrawvector.h index 18d9847..7d80c12 100644 --- a/tests/benchmarks/corelib/tools/qvector/qrawvector.h +++ b/tests/benchmarks/corelib/tools/qvector/qrawvector.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -59,7 +60,32 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +struct QVectorData +{ + QtPrivate::RefCount ref; + int size; + uint alloc : 31; + uint capacityReserved : 1; + + qptrdiff offset; + + void* data() { return reinterpret_cast(this) + this->offset; } + + static const QVectorData shared_null; + static QVectorData *allocate(int size, int alignment); + static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment); + static void free(QVectorData *data, int alignment); + static int grow(int sizeOfHeader, int size, int sizeOfT); +}; +template +struct QVectorTypedData : QVectorData +{ + T* begin() { return reinterpret_cast(this->data()); } + T* end() { return begin() + this->size; } + + static QVectorTypedData *sharedNull() { return static_cast(const_cast(&QVectorData::shared_null)); } +}; template class QRawVector diff --git a/tests/benchmarks/corelib/tools/qvector/qvector.pro b/tests/benchmarks/corelib/tools/qvector/qvector.pro index e24b162..24a65d8 100644 --- a/tests/benchmarks/corelib/tools/qvector/qvector.pro +++ b/tests/benchmarks/corelib/tools/qvector/qvector.pro @@ -1,5 +1,5 @@ TARGET = tst_bench_vector -QT = core testlib +QT = core testlib core-private INCLUDEPATH += . SOURCES += main.cpp outofline.cpp CONFIG += release -- 2.7.4