Implement QVector with QArrayData interface.
authorJędrzej Nowacki <jedrzej.nowacki@nokia.com>
Thu, 26 Apr 2012 10:06:17 +0000 (12:06 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 30 May 2012 15:07:27 +0000 (17:07 +0200)
Change-Id: I109f46892aed2f6024459812d24922b12358814d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
src/corelib/tools/qarraydata.h
src/corelib/tools/qvector.cpp
src/corelib/tools/qvector.h
src/gui/painting/qregion.cpp
tests/auto/corelib/tools/qvector/tst_qvector.cpp
tests/benchmarks/corelib/tools/qvector/outofline.cpp
tests/benchmarks/corelib/tools/qvector/qrawvector.h
tests/benchmarks/corelib/tools/qvector/qvector.pro

index b038e85..ae78fec 100644 (file)
@@ -179,6 +179,18 @@ struct QTypedArrayData
         Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
         return static_cast<QTypedArrayData *>(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 <class T, size_t N>
index 329727c..a19599e 100644 (file)
 
 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<QVectorData *>(alignment > alignmentThreshold() ? qMallocAligned(size, alignment) : ::malloc(size));
-}
-
-QVectorData *QVectorData::reallocate(QVectorData *x, int newsize, int oldsize, int alignment)
-{
-    if (alignment > alignmentThreshold())
-        return static_cast<QVectorData *>(qReallocAligned(x, newsize, oldsize, alignment));
-    return static_cast<QVectorData *>(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.
index 60cf12e..5b2cc11 100644 (file)
@@ -46,6 +46,7 @@
 #include <QtCore/qiterator.h>
 #include <QtCore/qlist.h>
 #include <QtCore/qrefcount.h>
+#include <QtCore/qarraydata.h>
 
 #include <iterator>
 #include <vector>
@@ -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<char *>(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 <typename T>
-struct QVectorTypedData : QVectorData
-{
-    T* begin() { return reinterpret_cast<T *>(this->data()); }
-    T* end() { return begin() + this->size; }
-
-    static QVectorTypedData *sharedNull() { return static_cast<QVectorTypedData *>(const_cast<QVectorData *>(&QVectorData::shared_null)); }
-};
-
 class QRegion;
 
 template <typename T>
 class QVector
 {
-    typedef QVectorTypedData<T> Data;
+    typedef QTypedArrayData<T> Data;
     Data *d;
 
 public:
     inline QVector() : d(Data::sharedNull()) { }
     explicit QVector(int size);
     QVector(int size, const T &t);
-    inline QVector(const QVector<T> &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<T> &v);
     inline ~QVector() { if (!d->ref.deref()) free(d); }
     QVector<T> &operator=(const QVector<T> &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<T> &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 <typename T>
+void QVector<T>::defaultConstruct(T *from, T *to)
+{
+    if (QTypeInfo<T>::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 <typename T>
+void QVector<T>::copyConstruct(T *srcFrom, T *srcTo, T *dstFrom)
+{
+    if (QTypeInfo<T>::isComplex) {
+        while (srcFrom != srcTo)
+            new (dstFrom++) T(*srcFrom++);
+    } else {
+        ::memcpy(dstFrom, srcFrom, (srcTo - srcFrom) * sizeof(T));
     }
-};
+}
+
+template <typename T>
+void QVector<T>::destruct(T *from, T *to)
+{
+    if (QTypeInfo<T>::isComplex) {
+        while (from != to) {
+            from++->~T();
+        }
+    }
+}
+
+template <typename T>
+inline QVector<T>::QVector(const QVector<T> &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 <typename T>
-void QVector<T>::detach_helper()
-{ realloc(d->size, int(d->alloc)); }
+void QVector<T>::detach()
+{
+    if (!isDetached()) {
+        if (d->alloc)
+            realloc(d->size, int(d->alloc));
+        else
+            d = Data::unsharableEmpty();
+    }
+    Q_ASSERT(isDetached());
+}
+
 template <typename T>
 void QVector<T>::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 <typename T>
 void QVector<T>::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 <typename T>
 inline void QVector<T>::clear()
 { *this = QVector<T>(); }
@@ -397,44 +444,29 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v)
 }
 
 template <typename T>
-inline typename QVector<T>::Data *QVector<T>::malloc(int aalloc)
-{
-    QVectorData *vectordata = QVectorData::allocate(offsetOfTypedData() + aalloc * sizeof(T), alignOfTypedData());
-    Q_CHECK_PTR(vectordata);
-    return static_cast<Data *>(vectordata);
-}
-
-template <typename T>
 QVector<T>::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<T>::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 <typename T>
 QVector<T>::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 <typename T>
 QVector<T>::QVector(std::initializer_list<T> args)
 {
     d = malloc(int(args.size()));
-    d->ref.initializeOwned();
+    // std::initializer_list<T>::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<T>::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<T>::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 <typename T>
 void QVector<T>::free(Data *x)
 {
-    if (QTypeInfo<T>::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 <typename T>
-void QVector<T>::realloc(int asize, int aalloc)
+void QVector<T>::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<T>::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<T>::isStatic) {
-            x = malloc(aalloc);
-            Q_CHECK_PTR(x);
-            x->size = 0;
-        } else if (!isDetached()) {
-            x = malloc(aalloc);
-            Q_CHECK_PTR(x);
-            if (QTypeInfo<T>::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<T>::isStatic || (isShared && QTypeInfo<T>::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<Data *>(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<T>::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<T>::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<typename T>
@@ -575,21 +601,16 @@ Q_OUTOFLINE_TEMPLATE T QVector<T>::value(int i, const T &defaultValue) const
 template <typename T>
 void QVector<T>::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<T>::isComplex)
-            new (d->end()) T(copy);
-        else
-            *d->end() = copy;
-    } else {
-        if (QTypeInfo<T>::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<T>::isComplex)
+        new (d->end()) T(copy);
+    else
+        *d->end() = copy;
     ++d->size;
 }
 
@@ -600,7 +621,7 @@ typename QVector<T>::iterator QVector<T>::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<T>::isStatic) {
             T *b = d->end();
             T *i = d->end() + n;
@@ -629,23 +650,37 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
 template <typename T>
 typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
 {
-    int f = int(abegin - d->begin());
-    int l = int(aend - d->begin());
-    int n = l - f;
-    detach();
-    if (QTypeInfo<T>::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<T>::isStatic) {
+            iterator moveBegin = abegin + itemsToErase;
+            iterator moveEnd = d->end();
+            while (moveBegin != moveEnd) {
+                if (QTypeInfo<T>::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 <typename T>
@@ -684,16 +719,18 @@ QVector<T> &QVector<T>::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<T>::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<T>::isComplex)
+                new (--w) T(*--i);
+            else
+                *--w = *--i;
+        }
+        d->size = newSize;
     }
-    d->size = newSize;
     return *this;
 }
 
index 8ecb122..db20d10 100644 (file)
@@ -4217,7 +4217,7 @@ QVector<QRect> 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<QRect>::Data::sharedNull())
             d->qt_rgn->rects.d->size = d->qt_rgn->numRects;
         return d->qt_rgn->rects;
     } else {
index 67ca547..56570b8 100644 (file)
 #include <QtTest/QtTest>
 #include <qvector.h>
 
+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<int>::isStatic);
+Q_STATIC_ASSERT(!QTypeInfo<int>::isComplex);
+Q_STATIC_ASSERT(!QTypeInfo<Movable>::isStatic);
+Q_STATIC_ASSERT(QTypeInfo<Movable>::isComplex);
+Q_STATIC_ASSERT(QTypeInfo<Custom>::isStatic);
+Q_STATIC_ASSERT(QTypeInfo<Custom>::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<typename T> void copyConstructor() const;
+    template<typename T> void add() const;
+    template<typename T> void append() const;
+    template<typename T> void capacity() const;
+    template<typename T> void clear() const;
+    template<typename T> void count() const;
+    template<typename T> void empty() const;
+    template<typename T> void eraseEmpty() const;
+    template<typename T> void eraseEmptyReserved() const;
+    template<typename T> void erase() const;
+    template<typename T> void eraseReserved() const;
+    template<typename T> void fill() const;
+    template<typename T> void fromList() const;
+    template<typename T> void prepend() const;
+    template<typename T> void remove() const;
+    template<typename T> void size() const;
+    template<typename T> void swap() const;
+    template<typename T> void initializeList();
+    template<typename T> void setSharable_data() const;
+    template<typename T> void setSharable() const;
+    template<typename T> void detach() const;
 };
 
-void tst_QVector::constructors() const
+template<typename T> struct SimpleValue
 {
-    // pre-reserve capacity
+    static T at(int index)
     {
-        QVector<int> myvec(5);
-
-        QVERIFY(myvec.capacity() == 5);
+        return Values[index % MaxIndex];
     }
+    static const uint MaxIndex = 6;
+    static const T Values[MaxIndex];
+};
 
+template<>
+const int SimpleValue<int>::Values[] = { 110, 105, 101, 114, 111, 98 };
+template<>
+const Movable SimpleValue<Movable>::Values[] = { 110, 105, 101, 114, 111, 98 };
+template<>
+const Custom SimpleValue<Custom>::Values[] = { 110, 105, 101, 114, 111, 98 };
+
+void tst_QVector::constructors_empty() const
+{
+    QVector<int> emptyInt;
+    QVector<Movable> emptyMovable;
+    QVector<Custom> emptyCustom;
+}
+
+void tst_QVector::constructors_emptyReserveZero() const
+{
+    QVector<int> emptyInt(0);
+    QVector<Movable> emptyMovable(0);
+    QVector<Custom> emptyCustom(0);
+}
+
+void tst_QVector::constructors_emptyReserve() const
+{
+    // pre-reserve capacity
+    QVector<int> myInt(5);
+    QVERIFY(myInt.capacity() == 5);
+    QVector<Movable> myMovable(5);
+    QVERIFY(myMovable.capacity() == 5);
+    QVector<Custom> myCustom(4);
+    QVERIFY(myCustom.capacity() == 4);
+}
+
+void tst_QVector::constructors_reserveAndInitialize() const
+{
     // default-initialise items
+
+    QVector<int> myInt(5, 42);
+    QVERIFY(myInt.capacity() == 5);
+    foreach (int meaningoflife, myInt) {
+        QCOMPARE(meaningoflife, 42);
+    }
+
+    QVector<QString> 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<Custom> myCustom(5, Custom('n'));
+    QVERIFY(myCustom.capacity() == 5);
+    // make sure all items are initialised ok
+    foreach (Custom meaningoflife, myCustom) {
+        QCOMPARE(meaningoflife.i, 'n');
+    }
+}
+
+template<typename T>
+void tst_QVector::copyConstructor() const
+{
+    T value1(SimpleValue<T>::at(0));
+    T value2(SimpleValue<T>::at(1));
+    T value3(SimpleValue<T>::at(2));
+    T value4(SimpleValue<T>::at(3));
     {
-        QVector<int> myvec(5, 42);
+        QVector<T> v1;
+        QVector<T> v2(v1);
+        QCOMPARE(v1, v2);
+    }
+    {
+        QVector<T> v1;
+        v1.setSharable(false);
+        QVector<T> v2(v1);
+        QVERIFY(!v1.isSharedWith(v2));
+        QCOMPARE(v1, v2);
+    }
+    {
+        QVector<T> v1;
+        v1 << value1 << value2 << value3 << value4;
+        QVector<T> v2(v1);
+        QCOMPARE(v1, v2);
+    }
+    {
+        QVector<T> v1;
+        v1 << value1 << value2 << value3 << value4;
+        v1.setSharable(false);
+        QVector<T> v2(v1);
+        QVERIFY(!v1.isSharedWith(v2));
+        QCOMPARE(v1, v2);
+    }
+}
 
-        QVERIFY(myvec.capacity() == 5);
+void tst_QVector::copyConstructorInt() const
+{
+    copyConstructor<int>();
+}
 
-        // 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<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::copyConstructorCustom() const
+{
+    const int instancesCount = Custom::counter;
+    copyConstructor<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
+void tst_QVector::add() const
+{
+    {
+        QVector<T> empty1;
+        QVector<T> empty2;
+        QVERIFY((empty1 + empty2).isEmpty());
+        empty1 += empty2;
+        QVERIFY(empty1.isEmpty());
+        QVERIFY(empty2.isEmpty());
     }
+    {
+        QVector<T> v(12);
+        QVector<T> empty;
+        QCOMPARE((v + empty), v);
+        v += empty;
+        QVERIFY(!v.isEmpty());
+        QCOMPARE(v.size(), 12);
+        QVERIFY(empty.isEmpty());
+    }
+    {
+        QVector<T> v1(12);
+        QVector<T> v2;
+        v2 += v1;
+        QVERIFY(!v1.isEmpty());
+        QCOMPARE(v1.size(), 12);
+        QVERIFY(!v2.isEmpty());
+        QCOMPARE(v2.size(), 12);
+    }
+}
+
+void tst_QVector::addInt() const
+{
+    add<int>();
+}
+
+void tst_QVector::addMovable() const
+{
+    const int instancesCount = Movable::counter;
+    add<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
 }
 
+void tst_QVector::addCustom() const
+{
+    const int instancesCount = Custom::counter;
+    add<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
 void tst_QVector::append() const
 {
-    QVector<int> myvec;
-    myvec.append(42);
-    myvec.append(43);
-    myvec.append(44);
+    {
+        QVector<T> myvec;
+        myvec.append(SimpleValue<T>::at(0));
+        QVERIFY(myvec.size() == 1);
+        myvec.append(SimpleValue<T>::at(1));
+        QVERIFY(myvec.size() == 2);
+        myvec.append(SimpleValue<T>::at(2));
+        QVERIFY(myvec.size() == 3);
 
-    QVERIFY(myvec.size() == 3);
-    QCOMPARE(myvec, QVector<int>() << 42 << 43 << 44);
+        QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(0)
+                                     << SimpleValue<T>::at(1)
+                                     << SimpleValue<T>::at(2));
+    }
+    {
+        QVector<T> v(2);
+        v.append(SimpleValue<T>::at(0));
+        QVERIFY(v.size() == 3);
+        QCOMPARE(v.at(v.size() - 1), SimpleValue<T>::at(0));
+    }
+    {
+        QVector<T> v(2);
+        v.reserve(12);
+        v.append(SimpleValue<T>::at(0));
+        QVERIFY(v.size() == 3);
+        QCOMPARE(v.at(v.size() - 1), SimpleValue<T>::at(0));
+    }
+    {
+        QVector<T> v(2);
+        v.reserve(12);
+        v.setSharable(false);
+        v.append(SimpleValue<T>::at(0));
+        QVERIFY(v.size() == 3);
+        QCOMPARE(v.last(), SimpleValue<T>::at(0));
+    }
+}
+
+void tst_QVector::appendInt() const
+{
+    append<int>();
+}
+
+void tst_QVector::appendMovable() const
+{
+    const int instancesCount = Movable::counter;
+    append<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::appendCustom() const
+{
+    const int instancesCount = Custom::counter;
+    append<Custom>();
+    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<typename T>
 void tst_QVector::capacity() const
 {
-    QVector<QString> myvec;
+    QVector<T> 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<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
     QVERIFY(myvec.capacity() >= 3);
 
     // make sure it grows ok
-    myvec << "aaa" << "bbb" << "ccc";
+    myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::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<int>();
+}
+
+void tst_QVector::capacityMovable() const
+{
+    const int instancesCount = Movable::counter;
+    capacity<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::capacityCustom() const
+{
+    const int instancesCount = Custom::counter;
+    capacity<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
 void tst_QVector::clear() const
 {
-    QVector<QString> myvec;
-    myvec << "aaa" << "bbb" << "ccc";
+    QVector<T> myvec;
+    myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::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<int>();
+}
+
+void tst_QVector::clearMovable() const
+{
+    const int instancesCount = Movable::counter;
+    clear<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::clearCustom() const
+{
+    const int instancesCount = Custom::counter;
+    clear<Custom>();
+    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<typename T>
 void tst_QVector::count() const
 {
     // total size
     {
         // zero size
-        QVector<int> myvec;
+        QVector<T> myvec;
         QVERIFY(myvec.count() == 0);
 
         // grow
-        myvec.append(42);
+        myvec.append(SimpleValue<T>::at(0));
         QVERIFY(myvec.count() == 1);
-        myvec.append(42);
+        myvec.append(SimpleValue<T>::at(1));
         QVERIFY(myvec.count() == 2);
 
         // shrink
@@ -240,23 +681,42 @@ void tst_QVector::count() const
 
     // count of items
     {
-        QVector<QString> myvec;
-        myvec << "aaa" << "bbb" << "ccc";
+        QVector<T> myvec;
+        myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
 
         // initial tests
-        QVERIFY(myvec.count(QLatin1String("aaa")) == 1);
-        QVERIFY(myvec.count(QLatin1String("pirates")) == 0);
+        QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1);
+        QVERIFY(myvec.count(SimpleValue<T>::at(3)) == 0);
 
         // grow
-        myvec.append(QLatin1String("aaa"));
-        QVERIFY(myvec.count(QLatin1String("aaa")) == 2);
+        myvec.append(SimpleValue<T>::at(0));
+        QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 2);
 
         // shrink
         myvec.remove(0);
-        QVERIFY(myvec.count(QLatin1String("aaa")) == 1);
+        QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1);
     }
 }
 
+void tst_QVector::countInt() const
+{
+    count<int>();
+}
+
+void tst_QVector::countMovable() const
+{
+    const int instancesCount = Movable::counter;
+    count<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::countCustom() const
+{
+    const int instancesCount = Custom::counter;
+    count<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
 void tst_QVector::data() const
 {
     QVector<int> myvec;
@@ -275,15 +735,16 @@ void tst_QVector::data() const
     QVERIFY(memcmp(myvec.data(), reinterpret_cast<int *>(&arr), sizeof(int) * 3) == 0);
 }
 
+template<typename T>
 void tst_QVector::empty() const
 {
-    QVector<int> myvec;
+    QVector<T> myvec;
 
     // starts empty
     QVERIFY(myvec.empty());
 
     // not empty
-    myvec.append(1);
+    myvec.append(SimpleValue<T>::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<int>();
+}
+
+void tst_QVector::emptyMovable() const
+{
+    const int instancesCount = Movable::counter;
+    empty<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::emptyCustom() const
+{
+    const int instancesCount = Custom::counter;
+    empty<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
 void tst_QVector::endsWith() const
 {
     QVector<int> myvec;
@@ -311,18 +791,244 @@ void tst_QVector::endsWith() const
     QVERIFY(myvec.endsWith(1));
 }
 
+template<typename T>
+void tst_QVector::eraseEmpty() const
+{
+    {
+        QVector<T> v;
+        v.erase(v.begin());
+        QCOMPARE(v.size(), 0);
+        v.erase(v.begin(), v.end());
+        QCOMPARE(v.size(), 0);
+    }
+    {
+        QVector<T> 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<int>();
+}
+
+void tst_QVector::eraseEmptyMovable() const
+{
+    const int instancesCount = Movable::counter;
+    eraseEmpty<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::eraseEmptyCustom() const
+{
+    const int instancesCount = Custom::counter;
+    eraseEmpty<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
+void tst_QVector::eraseEmptyReserved() const
+{
+    {
+        QVector<T> v;
+        v.reserve(10);
+        v.erase(v.begin());
+        QCOMPARE(v.size(), 0);
+        v.erase(v.begin(), v.end());
+        QCOMPARE(v.size(), 0);
+    }
+    {
+        QVector<T> 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<int>();
+}
+
+void tst_QVector::eraseEmptyReservedMovable() const
+{
+    const int instancesCount = Movable::counter;
+    eraseEmptyReserved<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::eraseEmptyReservedCustom() const
+{
+    const int instancesCount = Custom::counter;
+    eraseEmptyReserved<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
+void tst_QVector::erase() const
+{
+    {
+        QVector<T> v(12);
+        v.erase(v.begin());
+        QCOMPARE(v.size(), 11);
+        v.erase(v.begin(), v.end());
+        QCOMPARE(v.size(), 0);
+    }
+    {
+        QVector<T> v(12);
+        v.erase(v.begin() + 1);
+        QCOMPARE(v.size(), 11);
+        v.erase(v.begin() + 1, v.end());
+        QCOMPARE(v.size(), 1);
+    }
+    {
+        QVector<T> v(12);
+        v.erase(v.begin(), v.end() - 1);
+        QCOMPARE(v.size(), 1);
+    }
+    {
+        QVector<T> v(12);
+        v.erase(v.begin() + 5);
+        QCOMPARE(v.size(), 11);
+        v.erase(v.begin() + 1, v.end() - 1);
+        QCOMPARE(v.size(), 2);
+    }
+    {
+        QVector<T> 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<int>();
+}
+
+void tst_QVector::eraseMovable() const
+{
+    const int instancesCount = Movable::counter;
+    erase<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::eraseCustom() const
+{
+    const int instancesCount = Custom::counter;
+    erase<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T> void tst_QVector::eraseReserved() const
+{
+    {
+        QVector<T> v(12);
+        v.reserve(16);
+        v.erase(v.begin());
+        QCOMPARE(v.size(), 11);
+        v.erase(v.begin(), v.end());
+        QCOMPARE(v.size(), 0);
+    }
+    {
+        QVector<T> 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<T> v(12);
+        v.reserve(16);
+        v.erase(v.begin(), v.end() - 1);
+        QCOMPARE(v.size(), 1);
+    }
+    {
+        QVector<T> 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<T> 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<int>();
+}
+
+void tst_QVector::eraseReservedMovable() const
+{
+    const int instancesCount = Movable::counter;
+    eraseReserved<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::eraseReservedCustom() const
+{
+    const int instancesCount = Custom::counter;
+    eraseReserved<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
 void tst_QVector::fill() const
 {
-    QVector<int> myvec;
+    QVector<T> myvec;
 
     // resize
     myvec.resize(5);
-    myvec.fill(69);
-    QCOMPARE(myvec, QVector<int>() << 69 << 69 << 69 << 69 << 69);
+    myvec.fill(SimpleValue<T>::at(1));
+    QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(1) << SimpleValue<T>::at(1)
+                                 << SimpleValue<T>::at(1) << SimpleValue<T>::at(1)
+                                 << SimpleValue<T>::at(1));
 
     // make sure it can resize itself too
-    myvec.fill(42, 10);
-    QCOMPARE(myvec, QVector<int>() << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42 << 42);
+    myvec.fill(SimpleValue<T>::at(2), 10);
+    QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+                                 << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+                                 << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+                                 << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+                                 << SimpleValue<T>::at(2) << SimpleValue<T>::at(2));
+}
+
+void tst_QVector::fillInt() const
+{
+    fill<int>();
+}
+
+void tst_QVector::fillMovable() const
+{
+    const int instancesCount = Movable::counter;
+    fill<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::fillCustom() const
+{
+    const int instancesCount = Custom::counter;
+    fill<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
 }
 
 void tst_QVector::first() const
@@ -342,17 +1048,37 @@ void tst_QVector::first() const
     QCOMPARE(myvec.first(), 23);
 }
 
+template<typename T>
 void tst_QVector::fromList() const
 {
-    QList<QString> list;
-    list << "aaa" << "bbb" << "ninjas" << "pirates";
+    QList<T> list;
+    list << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3);
 
-    QVector<QString> myvec;
-    myvec = QVector<QString>::fromList(list);
+    QVector<T> myvec;
+    myvec = QVector<T>::fromList(list);
 
     // test it worked ok
-    QCOMPARE(myvec, QVector<QString>() << "aaa" << "bbb" << "ninjas" << "pirates");
-    QCOMPARE(list, QList<QString>() << "aaa" << "bbb" << "ninjas" << "pirates");
+    QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3));
+    QCOMPARE(list, QList<T>() << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3));
+}
+
+void tst_QVector::fromListInt() const
+{
+    fromList<int>();
+}
+
+void tst_QVector::fromListMovable() const
+{
+    const int instancesCount = Movable::counter;
+    fromList<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::fromListCustom() const
+{
+    const int instancesCount = Custom::counter;
+    fromList<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
 }
 
 void tst_QVector::fromStdVector() const
@@ -486,73 +1212,382 @@ void tst_QVector::mid() const
     QCOMPARE(list.mid(4), QVector<QString>() << "buck" << "hello" << "kitty");
 }
 
+template<typename T>
 void tst_QVector::prepend() const
 {
-    QVector<QString> myvec;
-    myvec << "A" << "B" << "C";
+    QVector<T> myvec;
+    T val1 = SimpleValue<T>::at(0);
+    T val2 = SimpleValue<T>::at(1);
+    T val3 = SimpleValue<T>::at(2);
+    T val4 = SimpleValue<T>::at(3);
+    T val5 = SimpleValue<T>::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<QString> myvec;
-    myvec << "A" << "B" << "C";
+    prepend<int>();
+}
+
+void tst_QVector::prependMovable() const
+{
+    const int instancesCount = Movable::counter;
+    prepend<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::prependCustom() const
+{
+    const int instancesCount = Custom::counter;
+    prepend<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
 
+template<typename T>
+void tst_QVector::remove() const
+{
+    QVector<T> myvec;
+    T val1 = SimpleValue<T>::at(1);
+    T val2 = SimpleValue<T>::at(2);
+    T val3 = SimpleValue<T>::at(3);
+    myvec << val1 << val2 << val3;
     // remove middle
     myvec.remove(1);
-    QCOMPARE(myvec, QVector<QString>() << "A" << "C");
+    QCOMPARE(myvec, QVector<T>() << val1 << val3);
 
     // remove rest
     myvec.remove(0, 2);
-    QCOMPARE(myvec, QVector<QString>());
+    QCOMPARE(myvec, QVector<T>());
 }
 
-// ::reserve() is really hard to think of tests for, so not doing it.
-// ::resize() is tested in ::capacity().
+void tst_QVector::removeInt() const
+{
+    remove<int>();
+}
 
-void tst_QVector::size() const
+void tst_QVector::removeMovable() const
 {
-    // total size
+    const int instancesCount = Movable::counter;
+    remove<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::removeCustom() const
+{
+    const int instancesCount = Custom::counter;
+    remove<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+void tst_QVector::resizePOD_data() const
+{
+    QTest::addColumn<QVector<int> >("vector");
+    QTest::addColumn<int>("size");
+
+    QVERIFY(!QTypeInfo<int>::isComplex);
+    QVERIFY(!QTypeInfo<int>::isStatic);
+
+    QVector<int> null;
+    QVector<int> empty(0, 5);
+    QVector<int> emptyReserved;
+    QVector<int> nonEmpty;
+    QVector<int> 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<int> nullNotShared;
+    QVector<int> emptyNotShared(0, 5);
+    QVector<int> emptyReservedNotShared;
+    QVector<int> nonEmptyNotShared;
+    QVector<int> 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<int>, 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<QVector<Movable> >("vector");
+    QTest::addColumn<int>("size");
+
+    QVERIFY(QTypeInfo<Movable>::isComplex);
+    QVERIFY(!QTypeInfo<Movable>::isStatic);
+
+    QVector<Movable> null;
+    QVector<Movable> empty(0, 'Q');
+    QVector<Movable> emptyReserved;
+    QVector<Movable> nonEmpty;
+    QVector<Movable> 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<Movable> nullNotShared;
+    QVector<Movable> emptyNotShared(0, 'Q');
+    QVector<Movable> emptyReservedNotShared;
+    QVector<Movable> nonEmptyNotShared;
+    QVector<Movable> 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<int> myvec;
-        QVERIFY(myvec.size() == 0);
+        QFETCH(QVector<Movable>, 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<QVector<Custom> >("vector");
+    QTest::addColumn<int>("size");
+
+    QVERIFY(QTypeInfo<Custom>::isComplex);
+    QVERIFY(QTypeInfo<Custom>::isStatic);
+
+    QVector<Custom> null;
+    QVector<Custom> empty(0, '0');
+    QVector<Custom> emptyReserved;
+    QVector<Custom> nonEmpty;
+    QVector<Custom> 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<Custom> nullNotShared;
+    QVector<Custom> emptyNotShared(0, '0');
+    QVector<Custom> emptyReservedNotShared;
+    QVector<Custom> nonEmptyNotShared;
+    QVector<Custom> 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<Custom>, 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<Custom> null;
+        QVector<Custom> empty(0, '0');
+        QVector<Custom> emptyReserved;
+        QVector<Custom> nonEmpty;
+        QVector<Custom> 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<typename T>
+void tst_QVector::size() const
+{
+    // zero size
+    QVector<T> myvec;
+    QVERIFY(myvec.size() == 0);
+
+    // grow
+    myvec.append(SimpleValue<T>::at(0));
+    QVERIFY(myvec.size() == 1);
+    myvec.append(SimpleValue<T>::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<int>();
+}
+
+void tst_QVector::sizeMovable() const
+{
+    const int instancesCount = Movable::counter;
+    size<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::sizeCustom() const
+{
+    const int instancesCount = Custom::counter;
+    size<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
 }
 
 // ::squeeze() is tested in ::capacity().
@@ -577,15 +1612,41 @@ void tst_QVector::startsWith() const
     QVERIFY(myvec.startsWith(1));
 }
 
+template<typename T>
 void tst_QVector::swap() const
 {
-    QVector<int> v1, v2;
-    v1 << 1 << 2 << 3;
-    v2 << 4 << 5 << 6;
+    QVector<T> v1, v2;
+    T val1 = SimpleValue<T>::at(0);
+    T val2 = SimpleValue<T>::at(1);
+    T val3 = SimpleValue<T>::at(2);
+    T val4 = SimpleValue<T>::at(3);
+    T val5 = SimpleValue<T>::at(4);
+    T val6 = SimpleValue<T>::at(5);
+    v1 << val1 << val2 << val3;
+    v2 << val4 << val5 << val6;
 
     v1.swap(v2);
-    QCOMPARE(v1,QVector<int>() << 4 << 5 << 6);
-    QCOMPARE(v2,QVector<int>() << 1 << 2 << 3);
+    QCOMPARE(v1,QVector<T>() << val4 << val5 << val6);
+    QCOMPARE(v2,QVector<T>() << val1 << val2 << val3);
+}
+
+void tst_QVector::swapInt() const
+{
+    swap<int>();
+}
+
+void tst_QVector::swapMovable() const
+{
+    const int instancesCount = Movable::counter;
+    swap<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::swapCustom() const
+{
+    const int instancesCount = Custom::counter;
+    swap<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
 }
 
 void tst_QVector::toList() const
@@ -923,20 +1984,45 @@ void tst_QVector::reallocAfterCopy()
     QCOMPARE(v2.size(), result4);
 }
 
+template<typename T>
 void tst_QVector::initializeList()
 {
 #ifdef Q_COMPILER_INITIALIZER_LISTS
-    QVector<int> v1{2,3,4};
-    QCOMPARE(v1, QVector<int>() << 2 << 3 << 4);
-    QCOMPARE(v1, (QVector<int>{2,3,4}));
-
-    QVector<QVector<int>> v2{ v1, {1}, QVector<int>(), {2,3,4}  };
-    QVector<QVector<int>> v3;
-    v3 << v1 << (QVector<int>() << 1) << QVector<int>() << v1;
+    T val1(SimpleValue<T>::at(1));
+    T val2(SimpleValue<T>::at(2));
+    T val3(SimpleValue<T>::at(3));
+    T val4(SimpleValue<T>::at(4));
+
+    QVector<T> v1 {val1, val2, val3};
+    QCOMPARE(v1, QVector<T>() << val1 << val2 << val3);
+    QCOMPARE(v1, (QVector<T> {val1, val2, val3}));
+
+    QVector<QVector<T>> v2{ v1, {val4}, QVector<T>(), {val1, val2, val3} };
+    QVector<QVector<T>> v3;
+    v3 << v1 << (QVector<T>() << val4) << QVector<T>() << v1;
     QCOMPARE(v3, v2);
 #endif
 }
 
+void tst_QVector::initializeListInt()
+{
+    initializeList<int>();
+}
+
+void tst_QVector::initializeListMovable()
+{
+    const int instancesCount = Movable::counter;
+    initializeList<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::initializeListCustom()
+{
+    const int instancesCount = Custom::counter;
+    initializeList<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
 void tst_QVector::const_shared_null()
 {
     QVector<int> v1;
@@ -950,24 +2036,25 @@ void tst_QVector::const_shared_null()
 
 Q_DECLARE_METATYPE(QVector<int>);
 
-void tst_QVector::setSharable_data()
+template<typename T>
+void tst_QVector::setSharable_data() const
 {
-    QTest::addColumn<QVector<int> >("vector");
+    QTest::addColumn<QVector<T> >("vector");
     QTest::addColumn<int>("size");
     QTest::addColumn<int>("capacity");
     QTest::addColumn<bool>("isCapacityReserved");
 
-    QVector<int> null;
-    QVector<int> empty(0, 5);
-    QVector<int> emptyReserved;
-    QVector<int> nonEmpty;
-    QVector<int> nonEmptyReserved;
+    QVector<T> null;
+    QVector<T> empty(0, SimpleValue<T>::at(1));
+    QVector<T> emptyReserved;
+    QVector<T> nonEmpty;
+    QVector<T> nonEmptyReserved;
 
     emptyReserved.reserve(10);
     nonEmptyReserved.reserve(15);
 
-    nonEmpty << 0 << 1 << 2 << 3 << 4;
-    nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6;
+    nonEmpty << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3) << SimpleValue<T>::at(4);
+    nonEmptyReserved << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3) << SimpleValue<T>::at(4) << SimpleValue<T>::at(5) << SimpleValue<T>::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<int>, vector);
+    setSharable_data<int>();
+}
+
+void tst_QVector::setSharableMovable_data()
+{
+    setSharable_data<Movable>();
+}
+
+void tst_QVector::setSharableCustom_data()
+{
+    setSharable_data<Custom>();
+}
+
+template<typename T>
+void tst_QVector::setSharable() const
+{
+    QFETCH(QVector<T>, vector);
     QFETCH(int, size);
     QFETCH(int, capacity);
     QFETCH(bool, isCapacityReserved);
@@ -998,19 +2101,19 @@ void tst_QVector::setSharable()
                     .arg(capacity)));
 
     {
-        QVector<int> copy(vector);
+        QVector<T> copy(vector);
 
         QVERIFY(!copy.isDetached());
         QVERIFY(copy.isSharedWith(vector));
     }
 
     vector.setSharable(false);
-    QVERIFY(vector.isDetached() || vector.isSharedWith(QVector<int>()));
+    QVERIFY(vector.isDetached() || vector.isSharedWith(QVector<T>()));
 
     {
-        QVector<int> copy(vector);
+        QVector<T> copy(vector);
 
-        QVERIFY(copy.isDetached() || copy.isSharedWith(QVector<int>()));
+        QVERIFY(copy.isDetached() || copy.isEmpty() || copy.isSharedWith(QVector<T>()));
         QCOMPARE(copy.size(), size);
         if (isCapacityReserved)
             QVERIFY2(copy.capacity() >= capacity,
@@ -1023,14 +2126,14 @@ void tst_QVector::setSharable()
     vector.setSharable(true);
 
     {
-        QVector<int> copy(vector);
+        QVector<T> 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<T>::at(i));
 
     QCOMPARE(vector.size(), size);
     if (isCapacityReserved)
@@ -1040,5 +2143,140 @@ void tst_QVector::setSharable()
                     .arg(capacity)));
 }
 
+void tst_QVector::setSharableInt()
+{
+    setSharable<int>();
+}
+
+void tst_QVector::setSharableMovable()
+{
+    const int instancesCount = Movable::counter;
+    setSharable<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::setSharableCustom()
+{
+    const int instancesCount = Custom::counter;
+    setSharable<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
+template<typename T>
+void tst_QVector::detach() const
+{
+    {
+        // detach an empty vector
+        QVector<T> v;
+        v.detach();
+        QVERIFY(v.isDetached());
+        QCOMPARE(v.size(), 0);
+        QCOMPARE(v.capacity(), 0);
+    }
+    {
+        // detach an empty referenced vector
+        QVector<T> v;
+        QVector<T> 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<T> v(31);
+        QVector<T> ref(v);
+        QVERIFY(!v.isDetached());
+        v.detach();
+        QVERIFY(v.isDetached());
+        QCOMPARE(v.size(), 31);
+        QCOMPARE(v.capacity(), 31);
+    }
+    {
+        // detach a not empty vector
+        QVector<T> 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<T> v(3);
+        v.reserve(8);
+        QVector<T> 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<T> 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<T> v(7, SimpleValue<T>::at(1));
+        QVector<T> 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<T>::at(1));
+    }
+    {
+        // detach a not empty, initialized vector
+        QVector<T> v(7, SimpleValue<T>::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<T>::at(2));
+    }
+    {
+        // detach a not empty, initialized vector with preallocated space
+        QVector<T> v(7, SimpleValue<T>::at(3));
+        v.reserve(31);
+        QVector<T> 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<T>::at(3));
+    }
+}
+
+void tst_QVector::detachInt() const
+{
+    detach<int>();
+}
+
+void tst_QVector::detachMovable() const
+{
+    const int instancesCount = Movable::counter;
+    detach<Movable>();
+    QCOMPARE(instancesCount, Movable::counter);
+}
+
+void tst_QVector::detachCustom() const
+{
+    const int instancesCount = Custom::counter;
+    detach<Custom>();
+    QCOMPARE(instancesCount, Custom::counter);
+}
+
 QTEST_APPLESS_MAIN(tst_QVector)
 #include "tst_qvector.moc"
index bf92978..1388128 100644 (file)
@@ -79,3 +79,36 @@ std::vector<double> 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<QVectorData *>(alignment > alignmentThreshold() ? qMallocAligned(size, alignment) : ::malloc(size));
+}
+
+QVectorData *QVectorData::reallocate(QVectorData *x, int newsize, int oldsize, int alignment)
+{
+    if (alignment > alignmentThreshold())
+        return static_cast<QVectorData *>(qReallocAligned(x, newsize, oldsize, alignment));
+    return static_cast<QVectorData *>(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;
+}
index 18d9847..7d80c12 100644 (file)
@@ -47,6 +47,7 @@
 #include <QtCore/qatomic.h>
 #include <QtCore/qalgorithms.h>
 #include <QtCore/qlist.h>
+#include <QtCore/private/qtools_p.h>
 
 #include <iterator>
 #include <vector>
@@ -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<char *>(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 <typename T>
+struct QVectorTypedData : QVectorData
+{
+    T* begin() { return reinterpret_cast<T *>(this->data()); }
+    T* end() { return begin() + this->size; }
+
+    static QVectorTypedData *sharedNull() { return static_cast<QVectorTypedData *>(const_cast<QVectorData *>(&QVectorData::shared_null)); }
+};
 
 template <typename T>
 class QRawVector
index e24b162..24a65d8 100644 (file)
@@ -1,5 +1,5 @@
 TARGET = tst_bench_vector
-QT = core testlib
+QT = core testlib core-private
 INCLUDEPATH += .
 SOURCES += main.cpp outofline.cpp 
 CONFIG += release