| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include <QtTest/QtTest> |
| #include <QAtomicInt> |
| #include <QThread> |
| #include <QSemaphore> |
| #include <qvector.h> |
| |
| struct Movable { |
| Movable(char input = 'j') |
| : i(input) |
| , that(this) |
| , state(Constructed) |
| { |
| counter.fetchAndAddRelaxed(1); |
| } |
| Movable(const Movable &other) |
| : i(other.i) |
| , that(this) |
| , state(Constructed) |
| { |
| check(other.state, Constructed); |
| counter.fetchAndAddRelaxed(1); |
| } |
| Movable(Movable &&other) |
| : i(other.i) |
| , that(other.that) |
| , state(Constructed) |
| { |
| check(other.state, Constructed); |
| counter.fetchAndAddRelaxed(1); |
| other.that = nullptr; |
| } |
| |
| ~Movable() |
| { |
| check(state, Constructed); |
| i = 0; |
| counter.fetchAndAddRelaxed(-1); |
| 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; |
| that = this; |
| return *this; |
| } |
| Movable &operator=(Movable &&other) |
| { |
| check(state, Constructed); |
| check(other.state, Constructed); |
| i = other.i; |
| that = other.that; |
| other.that = nullptr; |
| return *this; |
| } |
| bool wasConstructedAt(const Movable *other) const |
| { |
| return that == other; |
| } |
| char i; |
| static QAtomicInt counter; |
| private: |
| Movable *that; // used to check if an instance was moved |
| |
| enum State { Constructed = 106, Destructed = 110 }; |
| State state; |
| |
| static void check(const State state1, const State state2) |
| { |
| QCOMPARE(state1, state2); |
| } |
| }; |
| |
| inline uint qHash(const Movable &key, uint seed = 0) { return qHash(key.i, seed); } |
| |
| QAtomicInt 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.fetchAndAddRelaxed(1); |
| } |
| Custom(const Custom &other) |
| : that(this) |
| , state(Constructed) |
| { |
| check(&other); |
| counter.fetchAndAddRelaxed(1); |
| this->i = other.i; |
| } |
| ~Custom() |
| { |
| check(this); |
| i = 0; |
| counter.fetchAndAddRelaxed(-1); |
| state = Destructed; |
| } |
| |
| bool operator ==(const Custom &other) const |
| { |
| check(&other); |
| check(this); |
| return i == other.i; |
| } |
| |
| 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 QAtomicInt 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); |
| } |
| }; |
| QAtomicInt Custom::counter = 0; |
| |
| inline uint qHash(const Custom &key, uint seed = 0) { return qHash(key.i, seed); } |
| |
| 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_empty() const; |
| void constructors_emptyReserveZero() const; |
| void constructors_emptyReserve() const; |
| void constructors_reserveAndInitialize() const; |
| void copyConstructorInt() const; |
| void copyConstructorMovable() const; |
| void copyConstructorCustom() const; |
| void assignmentInt() const; |
| void assignmentMovable() const; |
| void assignmentCustom() const; |
| void assignFromInitializerListInt() const; |
| void assignFromInitializerListMovable() const; |
| void assignFromInitializerListCustom() const; |
| void addInt() const; |
| void addMovable() const; |
| void addCustom() const; |
| void appendInt() const; |
| void appendMovable() const; |
| void appendCustom() const; |
| void appendRvalue() const; |
| void at() const; |
| void capacityInt() const; |
| void capacityMovable() const; |
| void capacityCustom() const; |
| void clearInt() const; |
| void clearMovable() const; |
| void clearCustom() const; |
| void constData() const; |
| void constFirst() const; |
| void constLast() const; |
| void contains() const; |
| void countInt() const; |
| void countMovable() const; |
| void countCustom() const; |
| void cpp17ctad() const; |
| void data() const; |
| void emptyInt() const; |
| void emptyMovable() const; |
| void emptyCustom() const; |
| void endsWith() const; |
| void eraseEmptyInt() const; |
| void eraseEmptyMovable() const; |
| void eraseEmptyCustom() const; |
| void eraseEmptyReservedInt() const; |
| void eraseEmptyReservedMovable() const; |
| void eraseEmptyReservedCustom() const; |
| void eraseInt() const; |
| void eraseIntShared() const; |
| void eraseMovable() const; |
| void eraseMovableShared() const; |
| void eraseCustom() const; |
| void eraseCustomShared() const; |
| void eraseReservedInt() const; |
| void eraseReservedMovable() const; |
| void eraseReservedCustom() const; |
| void fillInt() const; |
| void fillMovable() const; |
| void fillCustom() const; |
| void fillDetaches() const; |
| void first() const; |
| void fromListInt() const; |
| void fromListMovable() const; |
| void fromListCustom() const; |
| void indexOf() const; |
| void insertInt() const; |
| void insertMovable() const; |
| void insertCustom() const; |
| void isEmpty() const; |
| void last() const; |
| void lastIndexOf() const; |
| void mid() const; |
| void moveInt() const; |
| void moveMovable() const; |
| void moveCustom() const; |
| void prependInt() const; |
| void prependMovable() const; |
| void prependCustom() const; |
| void qhashInt() const { qhash<int>(); } |
| void qhashMovable() const { qhash<Movable>(); } |
| void qhashCustom() const { qhash<Custom>(); } |
| void removeAllWithAlias() const; |
| void removeInt() const; |
| void removeMovable() const; |
| void removeCustom() const; |
| void removeFirstLast() 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 reverseIterators() const; |
| void sizeInt() const; |
| void sizeMovable() const; |
| void sizeCustom() const; |
| void startsWith() const; |
| void swapInt() const; |
| void swapMovable() const; |
| void swapCustom() const; |
| void toList() const; |
| #if QT_VERSION < QT_VERSION_CHECK(6,0,0) |
| void fromStdVector() const; |
| void toStdVector() const; |
| #endif |
| void value() const; |
| |
| void testOperators() const; |
| |
| void reserve(); |
| void reserveZero(); |
| void reallocAfterCopy_data(); |
| void reallocAfterCopy(); |
| void initializeListInt(); |
| void initializeListMovable(); |
| void initializeListCustom(); |
| |
| void const_shared_null(); |
| #if 1 |
| // ### Qt6 remove this section |
| void setSharableInt_data(); |
| void setSharableInt(); |
| void setSharableMovable_data(); |
| void setSharableMovable(); |
| void setSharableCustom_data(); |
| void setSharableCustom(); |
| #endif |
| |
| void detachInt() const; |
| void detachMovable() const; |
| void detachCustom() const; |
| void detachThreadSafetyInt() const; |
| void detachThreadSafetyMovable() const; |
| void detachThreadSafetyCustom() const; |
| |
| void insertMove() const; |
| |
| void swapItemsAt() const; |
| |
| private: |
| template<typename T> void copyConstructor() const; |
| template<typename T> void add() const; |
| template<typename T> void append() const; |
| template<typename T> void assignFromInitializerList() 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(bool shared) const; |
| template<typename T> void eraseReserved() const; |
| template<typename T> void fill() const; |
| template<typename T> void fromList() const; |
| template<typename T> void insert() const; |
| template<typename T> void qhash() const; |
| template<typename T> void move() 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; |
| template<typename T> void detachThreadSafety() const; |
| }; |
| |
| |
| template<typename T> struct SimpleValue |
| { |
| static T at(int index) |
| { |
| return Values[index % MaxIndex]; |
| } |
| |
| static QVector<T> vector(int size) |
| { |
| QVector<T> ret; |
| for (int i = 0; i < size; i++) |
| ret.append(at(i)); |
| return ret; |
| } |
| |
| 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 }; |
| |
| // Make some macros for the tests to use in order to be slightly more readable... |
| #define T_FOO SimpleValue<T>::at(0) |
| #define T_BAR SimpleValue<T>::at(1) |
| #define T_BAZ SimpleValue<T>::at(2) |
| #define T_CAT SimpleValue<T>::at(3) |
| #define T_DOG SimpleValue<T>::at(4) |
| #define T_BLAH SimpleValue<T>::at(5) |
| |
| 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<T> v1; |
| QVector<T> v2(v1); |
| QCOMPARE(v1, v2); |
| } |
| { |
| QVector<T> v1; |
| v1 << value1 << value2 << value3 << value4; |
| QVector<T> v2(v1); |
| QCOMPARE(v1, v2); |
| } |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| { |
| 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; |
| v1.setSharable(false); |
| QVector<T> v2(v1); |
| QVERIFY(!v1.isSharedWith(v2)); |
| QCOMPARE(v1, v2); |
| } |
| #endif |
| } |
| |
| void tst_QVector::copyConstructorInt() const |
| { |
| copyConstructor<int>(); |
| } |
| |
| void tst_QVector::copyConstructorMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| copyConstructor<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::copyConstructorCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| copyConstructor<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template <class T> |
| static inline void testAssignment() |
| { |
| QVector<T> v1(5); |
| QCOMPARE(v1.size(), 5); |
| QVERIFY(v1.isDetached()); |
| |
| QVector<T> v2(7); |
| QCOMPARE(v2.size(), 7); |
| QVERIFY(v2.isDetached()); |
| |
| QVERIFY(!v1.isSharedWith(v2)); |
| |
| v1 = v2; |
| |
| QVERIFY(!v1.isDetached()); |
| QVERIFY(!v2.isDetached()); |
| QVERIFY(v1.isSharedWith(v2)); |
| |
| const void *const data1 = v1.constData(); |
| const void *const data2 = v2.constData(); |
| |
| QCOMPARE(data1, data2); |
| |
| v1.clear(); |
| |
| QVERIFY(v2.isDetached()); |
| QVERIFY(!v1.isSharedWith(v2)); |
| QCOMPARE((void *)v2.constData(), data2); |
| } |
| |
| void tst_QVector::assignmentInt() const |
| { |
| testAssignment<int>(); |
| } |
| |
| void tst_QVector::assignmentMovable() const |
| { |
| testAssignment<Movable>(); |
| } |
| |
| void tst_QVector::assignmentCustom() const |
| { |
| testAssignment<Custom>(); |
| } |
| |
| template<typename T> |
| void tst_QVector::assignFromInitializerList() const |
| { |
| T val1(SimpleValue<T>::at(1)); |
| T val2(SimpleValue<T>::at(2)); |
| T val3(SimpleValue<T>::at(3)); |
| |
| QVector<T> v1 = {val1, val2, val3}; |
| QCOMPARE(v1, QVector<T>() << val1 << val2 << val3); |
| QCOMPARE(v1, (QVector<T> {val1, val2, val3})); |
| |
| v1 = {}; |
| QCOMPARE(v1.size(), 0); |
| } |
| |
| void tst_QVector::assignFromInitializerListInt() const |
| { |
| assignFromInitializerList<int>(); |
| } |
| |
| void tst_QVector::assignFromInitializerListMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| assignFromInitializerList<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::assignFromInitializerListCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| assignFromInitializerList<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| 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.loadAcquire(); |
| add<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::addCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| add<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template<typename T> |
| void tst_QVector::append() const |
| { |
| { |
| 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); |
| |
| 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)); |
| } |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| { |
| 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)); |
| } |
| #endif |
| { |
| QVector<int> v; |
| v << 1 << 2 << 3; |
| QVector<int> x; |
| x << 4 << 5 << 6; |
| v.append(x); |
| |
| QVector<int> combined; |
| combined << 1 << 2 << 3 << 4 << 5 << 6; |
| |
| QCOMPARE(v, combined); |
| } |
| } |
| |
| void tst_QVector::appendInt() const |
| { |
| append<int>(); |
| } |
| |
| void tst_QVector::appendMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| append<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::appendCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| append<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::appendRvalue() const |
| { |
| QVector<QString> v; |
| v.append("hello"); |
| QString world = "world"; |
| v.append(std::move(world)); |
| QVERIFY(world.isEmpty()); |
| QCOMPARE(v.front(), QString("hello")); |
| QCOMPARE(v.back(), QString("world")); |
| } |
| |
| void tst_QVector::at() const |
| { |
| QVector<QString> myvec; |
| myvec << "foo" << "bar" << "baz"; |
| |
| QVERIFY(myvec.size() == 3); |
| QCOMPARE(myvec.at(0), QLatin1String("foo")); |
| QCOMPARE(myvec.at(1), QLatin1String("bar")); |
| QCOMPARE(myvec.at(2), QLatin1String("baz")); |
| |
| // append an item |
| myvec << "hello"; |
| QVERIFY(myvec.size() == 4); |
| QCOMPARE(myvec.at(0), QLatin1String("foo")); |
| QCOMPARE(myvec.at(1), QLatin1String("bar")); |
| QCOMPARE(myvec.at(2), QLatin1String("baz")); |
| QCOMPARE(myvec.at(3), QLatin1String("hello")); |
| |
| // remove an item |
| myvec.remove(1); |
| QVERIFY(myvec.size() == 3); |
| QCOMPARE(myvec.at(0), QLatin1String("foo")); |
| QCOMPARE(myvec.at(1), QLatin1String("baz")); |
| QCOMPARE(myvec.at(2), QLatin1String("hello")); |
| } |
| |
| template<typename T> |
| void tst_QVector::capacity() const |
| { |
| 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 << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2); |
| QVERIFY(myvec.capacity() >= 3); |
| |
| // make sure it grows ok |
| myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2); |
| QVERIFY(myvec.capacity() >= 6); |
| // let's try squeeze a bit |
| myvec.remove(3); |
| myvec.remove(3); |
| myvec.remove(3); |
| // TODO: is this a safe assumption? presumably it won't release memory until shrink(), but can we asser that is true? |
| QVERIFY(myvec.capacity() >= 6); |
| myvec.squeeze(); |
| QVERIFY(myvec.capacity() >= 3); |
| |
| myvec.remove(0); |
| myvec.remove(0); |
| myvec.remove(0); |
| // TODO: as above note |
| QVERIFY(myvec.capacity() >= 3); |
| myvec.squeeze(); |
| QVERIFY(myvec.capacity() == 0); |
| } |
| |
| void tst_QVector::capacityInt() const |
| { |
| capacity<int>(); |
| } |
| |
| void tst_QVector::capacityMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| capacity<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::capacityCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| capacity<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template<typename T> |
| void tst_QVector::clear() const |
| { |
| QVector<T> myvec; |
| myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2); |
| |
| const auto oldCapacity = myvec.capacity(); |
| QCOMPARE(myvec.size(), 3); |
| myvec.clear(); |
| QCOMPARE(myvec.size(), 0); |
| QCOMPARE(myvec.capacity(), oldCapacity); |
| } |
| |
| void tst_QVector::clearInt() const |
| { |
| clear<int>(); |
| } |
| |
| void tst_QVector::clearMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| clear<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::clearCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| clear<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::constData() const |
| { |
| int arr[] = { 42, 43, 44 }; |
| QVector<int> myvec; |
| myvec << 42 << 43 << 44; |
| |
| QVERIFY(memcmp(myvec.constData(), reinterpret_cast<const int *>(&arr), sizeof(int) * 3) == 0); |
| } |
| |
| void tst_QVector::contains() const |
| { |
| QVector<QString> myvec; |
| myvec << "aaa" << "bbb" << "ccc"; |
| |
| QVERIFY(myvec.contains(QLatin1String("aaa"))); |
| QVERIFY(myvec.contains(QLatin1String("bbb"))); |
| QVERIFY(myvec.contains(QLatin1String("ccc"))); |
| QVERIFY(!myvec.contains(QLatin1String("I don't exist"))); |
| |
| // add it and make sure it does :) |
| myvec.append(QLatin1String("I don't exist")); |
| QVERIFY(myvec.contains(QLatin1String("I don't exist"))); |
| } |
| |
| template<typename T> |
| void tst_QVector::count() const |
| { |
| // total size |
| { |
| // zero size |
| QVector<T> myvec; |
| QVERIFY(myvec.count() == 0); |
| |
| // grow |
| myvec.append(SimpleValue<T>::at(0)); |
| QVERIFY(myvec.count() == 1); |
| myvec.append(SimpleValue<T>::at(1)); |
| QVERIFY(myvec.count() == 2); |
| |
| // shrink |
| myvec.remove(0); |
| QVERIFY(myvec.count() == 1); |
| myvec.remove(0); |
| QVERIFY(myvec.count() == 0); |
| } |
| |
| // count of items |
| { |
| QVector<T> myvec; |
| myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2); |
| |
| // initial tests |
| QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1); |
| QVERIFY(myvec.count(SimpleValue<T>::at(3)) == 0); |
| |
| // grow |
| myvec.append(SimpleValue<T>::at(0)); |
| QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 2); |
| |
| // shrink |
| myvec.remove(0); |
| 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.loadAcquire(); |
| count<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::countCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| count<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::cpp17ctad() const |
| { |
| #ifdef __cpp_deduction_guides |
| #define QVERIFY_IS_VECTOR_OF(obj, Type) \ |
| QVERIFY2((std::is_same<decltype(obj), QVector<Type>>::value), \ |
| QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>())) |
| #define CHECK(Type, One, Two, Three) \ |
| do { \ |
| const Type v[] = {One, Two, Three}; \ |
| QVector v1 = {One, Two, Three}; \ |
| QVERIFY_IS_VECTOR_OF(v1, Type); \ |
| QVector v2(v1.begin(), v1.end()); \ |
| QVERIFY_IS_VECTOR_OF(v2, Type); \ |
| QVector v3(std::begin(v), std::end(v)); \ |
| QVERIFY_IS_VECTOR_OF(v3, Type); \ |
| } while (false) \ |
| /*end*/ |
| CHECK(int, 1, 2, 3); |
| CHECK(double, 1.0, 2.0, 3.0); |
| CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); |
| #undef QVERIFY_IS_VECTOR_OF |
| #undef CHECK |
| #else |
| QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); |
| #endif |
| } |
| |
| void tst_QVector::data() const |
| { |
| QVector<int> myvec; |
| myvec << 42 << 43 << 44; |
| |
| // make sure it starts off ok |
| QCOMPARE(*(myvec.data() + 1), 43); |
| |
| // alter it |
| *(myvec.data() + 1) = 69; |
| |
| // check it altered |
| QCOMPARE(*(myvec.data() + 1), 69); |
| |
| int arr[] = { 42, 69, 44 }; |
| QVERIFY(memcmp(myvec.data(), reinterpret_cast<int *>(&arr), sizeof(int) * 3) == 0); |
| } |
| |
| template<typename T> |
| void tst_QVector::empty() const |
| { |
| QVector<T> myvec; |
| |
| // starts empty |
| QVERIFY(myvec.empty()); |
| |
| // not empty |
| myvec.append(SimpleValue<T>::at(2)); |
| QVERIFY(!myvec.empty()); |
| |
| // empty again |
| myvec.remove(0); |
| QVERIFY(myvec.empty()); |
| } |
| |
| void tst_QVector::emptyInt() const |
| { |
| empty<int>(); |
| } |
| |
| void tst_QVector::emptyMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| empty<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::emptyCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| empty<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::endsWith() const |
| { |
| QVector<int> myvec; |
| |
| // empty vector |
| QVERIFY(!myvec.endsWith(1)); |
| |
| // add the one, should work |
| myvec.append(1); |
| QVERIFY(myvec.endsWith(1)); |
| |
| // add something else, fails now |
| myvec.append(3); |
| QVERIFY(!myvec.endsWith(1)); |
| |
| // remove it again :) |
| myvec.remove(1); |
| QVERIFY(myvec.endsWith(1)); |
| } |
| |
| template<typename T> |
| void tst_QVector::eraseEmpty() const |
| { |
| { |
| QVector<T> v; |
| v.erase(v.begin(), v.end()); |
| QCOMPARE(v.size(), 0); |
| } |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| { |
| QVector<T> v; |
| v.setSharable(false); |
| v.erase(v.begin(), v.end()); |
| QCOMPARE(v.size(), 0); |
| } |
| #endif |
| } |
| |
| void tst_QVector::eraseEmptyInt() const |
| { |
| eraseEmpty<int>(); |
| } |
| |
| void tst_QVector::eraseEmptyMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| eraseEmpty<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::eraseEmptyCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| eraseEmpty<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template<typename T> |
| void tst_QVector::eraseEmptyReserved() const |
| { |
| { |
| QVector<T> v; |
| v.reserve(10); |
| v.erase(v.begin(), v.end()); |
| QCOMPARE(v.size(), 0); |
| } |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| { |
| QVector<T> v; |
| v.reserve(10); |
| v.setSharable(false); |
| v.erase(v.begin(), v.end()); |
| QCOMPARE(v.size(), 0); |
| } |
| #endif |
| } |
| |
| void tst_QVector::eraseEmptyReservedInt() const |
| { |
| eraseEmptyReserved<int>(); |
| } |
| |
| void tst_QVector::eraseEmptyReservedMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| eraseEmptyReserved<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::eraseEmptyReservedCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| eraseEmptyReserved<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template<typename T> |
| struct SharedVectorChecker |
| { |
| SharedVectorChecker(const QVector<T> &original, bool doCopyVector) |
| : originalSize(-1), |
| copy(0) |
| { |
| if (doCopyVector) { |
| originalSize = original.size(); |
| copy = new QVector<T>(original); |
| // this is unlikely to fail, but if the check in the destructor fails it's good to know that |
| // we were still alright here. |
| QCOMPARE(originalSize, copy->size()); |
| } |
| } |
| |
| ~SharedVectorChecker() |
| { |
| if (copy) |
| QCOMPARE(copy->size(), originalSize); |
| delete copy; |
| } |
| |
| int originalSize; |
| QVector<T> *copy; |
| }; |
| |
| template<typename T> |
| void tst_QVector::erase(bool shared) const |
| { |
| // note: remove() is actually more efficient, and more dangerous, because it uses the non-detaching |
| // begin() / end() internally. you can also use constBegin() and constEnd() with erase(), but only |
| // using reinterpret_cast... because both iterator types are really just pointers. |
| // so we use a mix of erase() and remove() to cover more cases. |
| { |
| QVector<T> v = SimpleValue<T>::vector(12); |
| SharedVectorChecker<T> svc(v, shared); |
| v.erase(v.begin()); |
| QCOMPARE(v.size(), 11); |
| for (int i = 0; i < 11; i++) |
| QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1)); |
| v.erase(v.begin(), v.end()); |
| QCOMPARE(v.size(), 0); |
| if (shared) |
| QCOMPARE(SimpleValue<T>::vector(12), *svc.copy); |
| } |
| { |
| QVector<T> v = SimpleValue<T>::vector(12); |
| SharedVectorChecker<T> svc(v, shared); |
| v.remove(1); |
| QCOMPARE(v.size(), 11); |
| QCOMPARE(v.at(0), SimpleValue<T>::at(0)); |
| for (int i = 1; i < 11; i++) |
| QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1)); |
| v.erase(v.begin() + 1, v.end()); |
| QCOMPARE(v.size(), 1); |
| QCOMPARE(v.at(0), SimpleValue<T>::at(0)); |
| if (shared) |
| QCOMPARE(SimpleValue<T>::vector(12), *svc.copy); |
| } |
| { |
| QVector<T> v = SimpleValue<T>::vector(12); |
| SharedVectorChecker<T> svc(v, shared); |
| v.erase(v.begin(), v.end() - 1); |
| QCOMPARE(v.size(), 1); |
| QCOMPARE(v.at(0), SimpleValue<T>::at(11)); |
| if (shared) |
| QCOMPARE(SimpleValue<T>::vector(12), *svc.copy); |
| } |
| { |
| QVector<T> v = SimpleValue<T>::vector(12); |
| SharedVectorChecker<T> svc(v, shared); |
| v.remove(5); |
| QCOMPARE(v.size(), 11); |
| for (int i = 0; i < 5; i++) |
| QCOMPARE(v.at(i), SimpleValue<T>::at(i)); |
| for (int i = 5; i < 11; i++) |
| QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1)); |
| v.erase(v.begin() + 1, v.end() - 1); |
| QCOMPARE(v.at(0), SimpleValue<T>::at(0)); |
| QCOMPARE(v.at(1), SimpleValue<T>::at(11)); |
| QCOMPARE(v.size(), 2); |
| if (shared) |
| QCOMPARE(SimpleValue<T>::vector(12), *svc.copy); |
| } |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| { |
| QVector<T> v = SimpleValue<T>::vector(10); |
| SharedVectorChecker<T> svc(v, shared); |
| v.setSharable(false); |
| SharedVectorChecker<T> svc2(v, shared); |
| v.erase(v.begin() + 3); |
| QCOMPARE(v.size(), 9); |
| v.erase(v.begin(), v.end() - 1); |
| QCOMPARE(v.size(), 1); |
| if (shared) |
| QCOMPARE(SimpleValue<T>::vector(10), *svc.copy); |
| } |
| #endif |
| } |
| |
| void tst_QVector::eraseInt() const |
| { |
| erase<int>(false); |
| } |
| |
| void tst_QVector::eraseIntShared() const |
| { |
| erase<int>(true); |
| } |
| |
| void tst_QVector::eraseMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| erase<Movable>(false); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::eraseMovableShared() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| erase<Movable>(true); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::eraseCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| erase<Custom>(false); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::eraseCustomShared() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| erase<Custom>(true); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| 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); |
| } |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| { |
| 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); |
| } |
| #endif |
| } |
| |
| void tst_QVector::eraseReservedInt() const |
| { |
| eraseReserved<int>(); |
| } |
| |
| void tst_QVector::eraseReservedMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| eraseReserved<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::eraseReservedCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| eraseReserved<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template<typename T> |
| void tst_QVector::fill() const |
| { |
| QVector<T> myvec; |
| |
| // resize |
| myvec.resize(5); |
| 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(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.loadAcquire(); |
| fill<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::fillCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| fill<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::fillDetaches() const |
| { |
| QVector<int> test = { 1, 2, 3 }; |
| QVector<int> copy = test; |
| copy.fill(42); |
| |
| QCOMPARE(test, QVector<int>({1, 2, 3})); |
| QCOMPARE(copy, QVector<int>({42, 42, 42})); |
| } |
| |
| void tst_QVector::first() const |
| { |
| QVector<int> myvec; |
| myvec << 69 << 42 << 3; |
| |
| // test it starts ok |
| QCOMPARE(myvec.first(), 69); |
| QCOMPARE(myvec.constFirst(), 69); |
| |
| // test removal changes |
| myvec.remove(0); |
| QCOMPARE(myvec.first(), 42); |
| QCOMPARE(myvec.constFirst(), 42); |
| |
| // test prepend changes |
| myvec.prepend(23); |
| QCOMPARE(myvec.first(), 23); |
| QCOMPARE(myvec.constFirst(), 23); |
| } |
| |
| void tst_QVector::constFirst() const |
| { |
| QVector<int> myvec; |
| myvec << 69 << 42 << 3; |
| |
| // test it starts ok |
| QCOMPARE(myvec.constFirst(), 69); |
| QVERIFY(myvec.isDetached()); |
| |
| QVector<int> myvecCopy = myvec; |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| QCOMPARE(myvec.constFirst(), 69); |
| QCOMPARE(myvecCopy.constFirst(), 69); |
| |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| // test removal changes |
| myvec.remove(0); |
| QVERIFY(myvec.isDetached()); |
| QVERIFY(!myvec.isSharedWith(myvecCopy)); |
| QCOMPARE(myvec.constFirst(), 42); |
| QCOMPARE(myvecCopy.constFirst(), 69); |
| |
| myvecCopy = myvec; |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| QCOMPARE(myvec.constFirst(), 42); |
| QCOMPARE(myvecCopy.constFirst(), 42); |
| |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| // test prepend changes |
| myvec.prepend(23); |
| QVERIFY(myvec.isDetached()); |
| QVERIFY(!myvec.isSharedWith(myvecCopy)); |
| QCOMPARE(myvec.constFirst(), 23); |
| QCOMPARE(myvecCopy.constFirst(), 42); |
| |
| myvecCopy = myvec; |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| QCOMPARE(myvec.constFirst(), 23); |
| QCOMPARE(myvecCopy.constFirst(), 23); |
| |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| } |
| |
| |
| template<typename T> |
| void tst_QVector::fromList() const |
| { |
| QList<T> list; |
| list << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3); |
| |
| QVector<T> myvec; |
| myvec = QVector<T>::fromList(list); |
| |
| // test it worked ok |
| 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.loadAcquire(); |
| fromList<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::fromListCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| fromList<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| #if QT_VERSION < QT_VERSION_CHECK(6,0,0) |
| void tst_QVector::fromStdVector() const |
| { |
| // stl = :( |
| std::vector<QString> svec; |
| svec.push_back(QLatin1String("aaa")); |
| svec.push_back(QLatin1String("bbb")); |
| svec.push_back(QLatin1String("ninjas")); |
| svec.push_back(QLatin1String("pirates")); |
| QVector<QString> myvec = QVector<QString>::fromStdVector(svec); |
| |
| // test it converts ok |
| QCOMPARE(myvec, QVector<QString>() << "aaa" << "bbb" << "ninjas" << "pirates"); |
| } |
| #endif |
| |
| void tst_QVector::indexOf() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C" << "B" << "A"; |
| |
| QVERIFY(myvec.indexOf("B") == 1); |
| QVERIFY(myvec.indexOf("B", 1) == 1); |
| QVERIFY(myvec.indexOf("B", 2) == 3); |
| QVERIFY(myvec.indexOf("X") == -1); |
| QVERIFY(myvec.indexOf("X", 2) == -1); |
| |
| // add an X |
| myvec << "X"; |
| QVERIFY(myvec.indexOf("X") == 5); |
| QVERIFY(myvec.indexOf("X", 5) == 5); |
| QVERIFY(myvec.indexOf("X", 6) == -1); |
| |
| // remove first A |
| myvec.remove(0); |
| QVERIFY(myvec.indexOf("A") == 3); |
| QVERIFY(myvec.indexOf("A", 3) == 3); |
| QVERIFY(myvec.indexOf("A", 4) == -1); |
| } |
| |
| template <typename T> |
| void tst_QVector::insert() const |
| { |
| QVector<T> myvec; |
| const T |
| tA = SimpleValue<T>::at(0), |
| tB = SimpleValue<T>::at(1), |
| tC = SimpleValue<T>::at(2), |
| tX = SimpleValue<T>::at(3), |
| tZ = SimpleValue<T>::at(4), |
| tT = SimpleValue<T>::at(5), |
| ti = SimpleValue<T>::at(6); |
| myvec << tA << tB << tC; |
| QVector<T> myvec2 = myvec; |
| |
| // first position |
| QCOMPARE(myvec.at(0), tA); |
| myvec.insert(0, tX); |
| QCOMPARE(myvec.at(0), tX); |
| QCOMPARE(myvec.at(1), tA); |
| |
| QCOMPARE(myvec2.at(0), tA); |
| myvec2.insert(myvec2.begin(), tX); |
| QCOMPARE(myvec2.at(0), tX); |
| QCOMPARE(myvec2.at(1), tA); |
| |
| // middle |
| myvec.insert(1, tZ); |
| QCOMPARE(myvec.at(0), tX); |
| QCOMPARE(myvec.at(1), tZ); |
| QCOMPARE(myvec.at(2), tA); |
| |
| myvec2.insert(myvec2.begin() + 1, tZ); |
| QCOMPARE(myvec2.at(0), tX); |
| QCOMPARE(myvec2.at(1), tZ); |
| QCOMPARE(myvec2.at(2), tA); |
| |
| // end |
| myvec.insert(5, tT); |
| QCOMPARE(myvec.at(5), tT); |
| QCOMPARE(myvec.at(4), tC); |
| |
| myvec2.insert(myvec2.end(), tT); |
| QCOMPARE(myvec2.at(5), tT); |
| QCOMPARE(myvec2.at(4), tC); |
| |
| // insert a lot of garbage in the middle |
| myvec.insert(2, 2, ti); |
| QCOMPARE(myvec, QVector<T>() << tX << tZ << ti << ti |
| << tA << tB << tC << tT); |
| |
| myvec2.insert(myvec2.begin() + 2, 2, ti); |
| QCOMPARE(myvec2, myvec); |
| |
| // insert from references to the same container: |
| myvec.insert(0, 1, myvec[5]); // inserts tB |
| myvec2.insert(0, 1, myvec2[5]); // inserts tB |
| QCOMPARE(myvec, QVector<T>() << tB << tX << tZ << ti << ti |
| << tA << tB << tC << tT); |
| QCOMPARE(myvec2, myvec); |
| |
| myvec.insert(0, 1, const_cast<const QVector<T>&>(myvec)[0]); // inserts tB |
| myvec2.insert(0, 1, const_cast<const QVector<T>&>(myvec2)[0]); // inserts tB |
| QCOMPARE(myvec, QVector<T>() << tB << tB << tX << tZ << ti << ti |
| << tA << tB << tC << tT); |
| QCOMPARE(myvec2, myvec); |
| } |
| |
| void tst_QVector::insertInt() const |
| { |
| insert<int>(); |
| } |
| |
| void tst_QVector::insertMovable() const |
| { |
| insert<Movable>(); |
| } |
| |
| void tst_QVector::insertCustom() const |
| { |
| insert<Custom>(); |
| } |
| |
| void tst_QVector::isEmpty() const |
| { |
| QVector<QString> myvec; |
| |
| // starts ok |
| QVERIFY(myvec.isEmpty()); |
| |
| // not empty now |
| myvec.append(QLatin1String("hello there")); |
| QVERIFY(!myvec.isEmpty()); |
| |
| // empty again |
| myvec.remove(0); |
| QVERIFY(myvec.isEmpty()); |
| } |
| |
| void tst_QVector::last() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C"; |
| |
| // test starts ok |
| QCOMPARE(myvec.last(), QLatin1String("C")); |
| QCOMPARE(myvec.constLast(), QLatin1String("C")); |
| |
| // test it changes ok |
| myvec.append(QLatin1String("X")); |
| QCOMPARE(myvec.last(), QLatin1String("X")); |
| QCOMPARE(myvec.constLast(), QLatin1String("X")); |
| |
| // and remove again |
| myvec.remove(3); |
| QCOMPARE(myvec.last(), QLatin1String("C")); |
| QCOMPARE(myvec.constLast(), QLatin1String("C")); |
| } |
| |
| void tst_QVector::constLast() const |
| { |
| QVector<int> myvec; |
| myvec << 69 << 42 << 3; |
| |
| // test it starts ok |
| QCOMPARE(myvec.constLast(), 3); |
| QVERIFY(myvec.isDetached()); |
| |
| QVector<int> myvecCopy = myvec; |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| QCOMPARE(myvec.constLast(), 3); |
| QCOMPARE(myvecCopy.constLast(), 3); |
| |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| // test removal changes |
| myvec.removeLast(); |
| QVERIFY(myvec.isDetached()); |
| QVERIFY(!myvec.isSharedWith(myvecCopy)); |
| QCOMPARE(myvec.constLast(), 42); |
| QCOMPARE(myvecCopy.constLast(), 3); |
| |
| myvecCopy = myvec; |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| QCOMPARE(myvec.constLast(), 42); |
| QCOMPARE(myvecCopy.constLast(), 42); |
| |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| // test prepend changes |
| myvec.append(23); |
| QVERIFY(myvec.isDetached()); |
| QVERIFY(!myvec.isSharedWith(myvecCopy)); |
| QCOMPARE(myvec.constLast(), 23); |
| QCOMPARE(myvecCopy.constLast(), 42); |
| |
| myvecCopy = myvec; |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| |
| QCOMPARE(myvec.constLast(), 23); |
| QCOMPARE(myvecCopy.constLast(), 23); |
| |
| QVERIFY(!myvec.isDetached()); |
| QVERIFY(!myvecCopy.isDetached()); |
| QVERIFY(myvec.isSharedWith(myvecCopy)); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| } |
| |
| void tst_QVector::lastIndexOf() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C" << "B" << "A"; |
| |
| QVERIFY(myvec.lastIndexOf("B") == 3); |
| QVERIFY(myvec.lastIndexOf("B", 2) == 1); |
| QVERIFY(myvec.lastIndexOf("X") == -1); |
| QVERIFY(myvec.lastIndexOf("X", 2) == -1); |
| |
| // add an X |
| myvec << "X"; |
| QVERIFY(myvec.lastIndexOf("X") == 5); |
| QVERIFY(myvec.lastIndexOf("X", 5) == 5); |
| QVERIFY(myvec.lastIndexOf("X", 3) == -1); |
| |
| // remove first A |
| myvec.remove(0); |
| QVERIFY(myvec.lastIndexOf("A") == 3); |
| QVERIFY(myvec.lastIndexOf("A", 3) == 3); |
| QVERIFY(myvec.lastIndexOf("A", 2) == -1); |
| } |
| |
| void tst_QVector::mid() const |
| { |
| QVector<QString> list; |
| list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty"; |
| |
| QCOMPARE(list.mid(3, 3), QVector<QString>() << "bak" << "buck" << "hello"); |
| QCOMPARE(list.mid(6, 10), QVector<QString>() << "kitty"); |
| QCOMPARE(list.mid(-1, 20), list); |
| QCOMPARE(list.mid(4), QVector<QString>() << "buck" << "hello" << "kitty"); |
| } |
| |
| template <typename T> |
| void tst_QVector::qhash() const |
| { |
| QVector<T> l1, l2; |
| QCOMPARE(qHash(l1), qHash(l2)); |
| l1 << SimpleValue<T>::at(0); |
| l2 << SimpleValue<T>::at(0); |
| QCOMPARE(qHash(l1), qHash(l2)); |
| } |
| |
| template <typename T> |
| void tst_QVector::move() const |
| { |
| QVector<T> list; |
| list << T_FOO << T_BAR << T_BAZ; |
| |
| // move an item |
| list.move(0, list.count() - 1); |
| QCOMPARE(list, QVector<T>() << T_BAR << T_BAZ << T_FOO); |
| |
| // move it back |
| list.move(list.count() - 1, 0); |
| QCOMPARE(list, QVector<T>() << T_FOO << T_BAR << T_BAZ); |
| |
| // move an item in the middle |
| list.move(1, 0); |
| QCOMPARE(list, QVector<T>() << T_BAR << T_FOO << T_BAZ); |
| } |
| |
| void tst_QVector::moveInt() const |
| { |
| move<int>(); |
| } |
| |
| void tst_QVector::moveMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| move<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::moveCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| move<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| template<typename T> |
| void tst_QVector::prepend() const |
| { |
| 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), val1); |
| |
| // add something |
| myvec.prepend(val4); |
| QCOMPARE(myvec.at(0), val4); |
| QCOMPARE(myvec.at(1), val1); |
| QVERIFY(myvec.size() == 4); |
| |
| // something else |
| myvec.prepend(val5); |
| QCOMPARE(myvec.at(0), val5); |
| QCOMPARE(myvec.at(1), val4); |
| QCOMPARE(myvec.at(2), val1); |
| QVERIFY(myvec.size() == 5); |
| |
| // clear and prepend to an empty vector |
| myvec.clear(); |
| QVERIFY(myvec.size() == 0); |
| myvec.prepend(val5); |
| QVERIFY(myvec.size() == 1); |
| QCOMPARE(myvec.at(0), val5); |
| } |
| |
| void tst_QVector::prependInt() const |
| { |
| prepend<int>(); |
| } |
| |
| void tst_QVector::prependMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| prepend<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::prependCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| prepend<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::removeAllWithAlias() const |
| { |
| QVector<QString> strings; |
| strings << "One" << "Two" << "Three" << "One" /* must be distinct, but equal */; |
| QCOMPARE(strings.removeAll(strings.front()), 2); // will trigger asan/ubsan |
| } |
| |
| 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); |
| T val4 = SimpleValue<T>::at(4); |
| myvec << val1 << val2 << val3; |
| myvec << val1 << val2 << val3; |
| myvec << val1 << val2 << val3; |
| // remove middle |
| myvec.remove(1); |
| QCOMPARE(myvec, QVector<T>() << val1 << val3 << val1 << val2 << val3 << val1 << val2 << val3); |
| |
| // removeOne() |
| QVERIFY(!myvec.removeOne(val4)); |
| QVERIFY(myvec.removeOne(val2)); |
| QCOMPARE(myvec, QVector<T>() << val1 << val3 << val1 << val3 << val1 << val2 << val3); |
| |
| QVector<T> myvecCopy = myvec; |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| // removeAll() |
| QCOMPARE(myvec.removeAll(val4), 0); |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| QCOMPARE(myvec.removeAll(val1), 3); |
| QVERIFY(!myvecCopy.isSharedWith(myvec)); |
| QCOMPARE(myvec, QVector<T>() << val3 << val3 << val2 << val3); |
| myvecCopy = myvec; |
| QVERIFY(myvecCopy.isSharedWith(myvec)); |
| QCOMPARE(myvec.removeAll(val2), 1); |
| QVERIFY(!myvecCopy.isSharedWith(myvec)); |
| QCOMPARE(myvec, QVector<T>() << val3 << val3 << val3); |
| |
| // remove rest |
| myvec.remove(0, 3); |
| QCOMPARE(myvec, QVector<T>()); |
| } |
| |
| void tst_QVector::removeInt() const |
| { |
| remove<int>(); |
| } |
| |
| void tst_QVector::removeMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| remove<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::removeCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| remove<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| struct RemoveLastTestClass |
| { |
| RemoveLastTestClass() { other = 0; deleted = false; } |
| RemoveLastTestClass *other; |
| bool deleted; |
| ~RemoveLastTestClass() |
| { |
| deleted = true; |
| if (other) |
| other->other = 0; |
| } |
| }; |
| |
| void tst_QVector::removeFirstLast() const |
| { |
| // pop_pack - pop_front |
| QVector<int> t, t2; |
| t.append(1); |
| t.append(2); |
| t.append(3); |
| t.append(4); |
| t2 = t; |
| t.pop_front(); |
| QCOMPARE(t.size(), 3); |
| QCOMPARE(t.at(0), 2); |
| t.pop_back(); |
| QCOMPARE(t.size(), 2); |
| QCOMPARE(t.at(0), 2); |
| QCOMPARE(t.at(1), 3); |
| |
| // takefirst - takeLast |
| int n1 = t2.takeLast(); |
| QCOMPARE(t2.size(), 3); |
| QCOMPARE(n1, 4); |
| QCOMPARE(t2.at(0), 1); |
| QCOMPARE(t2.at(2), 3); |
| n1 = t2.takeFirst(); |
| QCOMPARE(t2.size(), 2); |
| QCOMPARE(n1, 1); |
| QCOMPARE(t2.at(0), 2); |
| QCOMPARE(t2.at(1), 3); |
| |
| // remove first |
| QVector<int> x, y; |
| x.append(1); |
| x.append(2); |
| y = x; |
| x.removeFirst(); |
| QCOMPARE(x.size(), 1); |
| QCOMPARE(y.size(), 2); |
| QCOMPARE(x.at(0), 2); |
| |
| // remove Last |
| QVector<RemoveLastTestClass> v; |
| v.resize(2); |
| v[0].other = &(v[1]); |
| v[1].other = &(v[0]); |
| // Check dtor - complex type |
| QVERIFY(v.at(0).other != 0); |
| v.removeLast(); |
| QVERIFY(v.at(0).other == 0); |
| QCOMPARE(v.at(0).deleted, false); |
| // check iterator |
| int count = 0; |
| for (QVector<RemoveLastTestClass>::const_iterator i = v.constBegin(); i != v.constEnd(); ++i) { |
| ++count; |
| QVERIFY(i->other == 0); |
| QCOMPARE(i->deleted, false); |
| } |
| // Check size |
| QCOMPARE(count, 1); |
| QCOMPARE(v.size(), 1); |
| v.removeLast(); |
| QCOMPARE(v.size(), 0); |
| // Check if we do correct realloc |
| QVector<int> v2, v3; |
| v2.append(1); |
| v2.append(2); |
| v3 = v2; // shared |
| v2.removeLast(); |
| QCOMPARE(v2.size(), 1); |
| QCOMPARE(v3.size(), 2); |
| QCOMPARE(v2.at(0), 1); |
| QCOMPARE(v3.at(0), 1); |
| QCOMPARE(v3.at(1), 2); |
| |
| // Remove last with shared |
| QVector<int> z1, z2; |
| z1.append(9); |
| z2 = z1; |
| z1.removeLast(); |
| QCOMPARE(z1.size(), 0); |
| QCOMPARE(z2.size(), 1); |
| QCOMPARE(z2.at(0), 9); |
| } |
| |
| |
| 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); |
| |
| 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; |
| |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| 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("nullNotShared") << nullNotShared << 10; |
| QTest::newRow("emptyNotShared") << emptyNotShared << 10; |
| QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; |
| QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; |
| QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; |
| #endif |
| } |
| |
| 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.clear(); |
| 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); |
| |
| 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; |
| |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| 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("nullNotShared") << nullNotShared << 10; |
| QTest::newRow("emptyNotShared") << emptyNotShared << 10; |
| QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; |
| QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; |
| QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; |
| #endif |
| } |
| |
| void tst_QVector::resizeComplexMovable() const |
| { |
| const int items = Movable::counter.loadAcquire(); |
| { |
| QFETCH(QVector<Movable>, 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] == 'j'); // check initialization |
| |
| const int capacity = vector.capacity(); |
| |
| vector.resize(0); |
| QCOMPARE(vector.size(), 0); |
| QVERIFY(vector.capacity() <= capacity); |
| } |
| QCOMPARE(items, Movable::counter.loadAcquire()); |
| } |
| |
| 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); |
| |
| 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; |
| |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| 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("nullNotShared") << nullNotShared << 10; |
| QTest::newRow("emptyNotShared") << emptyNotShared << 10; |
| QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; |
| QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; |
| QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; |
| #endif |
| } |
| |
| void tst_QVector::resizeComplex() const |
| { |
| const int items = Custom::counter.loadAcquire(); |
| { |
| 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.loadAcquire(), items); |
| } |
| |
| void tst_QVector::resizeCtorAndDtor() const |
| { |
| const int items = Custom::counter.loadAcquire(); |
| { |
| 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.loadAcquire(), items); |
| } |
| |
| void tst_QVector::reverseIterators() const |
| { |
| QVector<int> v; |
| v << 1 << 2 << 3 << 4; |
| QVector<int> vr = v; |
| std::reverse(vr.begin(), vr.end()); |
| const QVector<int> &cvr = vr; |
| QVERIFY(std::equal(v.begin(), v.end(), vr.rbegin())); |
| QVERIFY(std::equal(v.begin(), v.end(), vr.crbegin())); |
| QVERIFY(std::equal(v.begin(), v.end(), cvr.rbegin())); |
| QVERIFY(std::equal(vr.rbegin(), vr.rend(), v.begin())); |
| QVERIFY(std::equal(vr.crbegin(), vr.crend(), v.begin())); |
| QVERIFY(std::equal(cvr.rbegin(), cvr.rend(), v.begin())); |
| } |
| |
| 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.loadAcquire(); |
| size<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::sizeCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| size<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| // ::squeeze() is tested in ::capacity(). |
| |
| void tst_QVector::startsWith() const |
| { |
| QVector<int> myvec; |
| |
| // empty vector |
| QVERIFY(!myvec.startsWith(1)); |
| |
| // add the one, should work |
| myvec.prepend(1); |
| QVERIFY(myvec.startsWith(1)); |
| |
| // add something else, fails now |
| myvec.prepend(3); |
| QVERIFY(!myvec.startsWith(1)); |
| |
| // remove it again :) |
| myvec.remove(0); |
| QVERIFY(myvec.startsWith(1)); |
| } |
| |
| template<typename T> |
| void tst_QVector::swap() const |
| { |
| 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<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.loadAcquire(); |
| swap<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::swapCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| swap<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::toList() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C"; |
| |
| // make sure it converts and doesn't modify the original vector |
| QCOMPARE(myvec.toList(), QList<QString>() << "A" << "B" << "C"); |
| QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); |
| } |
| |
| #if QT_VERSION < QT_VERSION_CHECK(6,0,0) |
| void tst_QVector::toStdVector() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C"; |
| |
| std::vector<QString> svec = myvec.toStdVector(); |
| QCOMPARE(svec.at(0), QLatin1String("A")); |
| QCOMPARE(svec.at(1), QLatin1String("B")); |
| QCOMPARE(svec.at(2), QLatin1String("C")); |
| |
| QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); |
| } |
| #endif |
| |
| void tst_QVector::value() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C"; |
| |
| // valid calls |
| QCOMPARE(myvec.value(0), QLatin1String("A")); |
| QCOMPARE(myvec.value(1), QLatin1String("B")); |
| QCOMPARE(myvec.value(2), QLatin1String("C")); |
| |
| // default calls |
| QCOMPARE(myvec.value(-1), QString()); |
| QCOMPARE(myvec.value(3), QString()); |
| |
| // test calls with a provided default, valid calls |
| QCOMPARE(myvec.value(0, QLatin1String("default")), QLatin1String("A")); |
| QCOMPARE(myvec.value(1, QLatin1String("default")), QLatin1String("B")); |
| QCOMPARE(myvec.value(2, QLatin1String("default")), QLatin1String("C")); |
| |
| // test calls with a provided default that will return the default |
| QCOMPARE(myvec.value(-1, QLatin1String("default")), QLatin1String("default")); |
| QCOMPARE(myvec.value(3, QLatin1String("default")), QLatin1String("default")); |
| } |
| |
| void tst_QVector::testOperators() const |
| { |
| QVector<QString> myvec; |
| myvec << "A" << "B" << "C"; |
| QVector<QString> myvectwo; |
| myvectwo << "D" << "E" << "F"; |
| QVector<QString> combined; |
| combined << "A" << "B" << "C" << "D" << "E" << "F"; |
| |
| // != |
| QVERIFY(myvec != myvectwo); |
| |
| // + |
| QCOMPARE(myvec + myvectwo, combined); |
| QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C"); |
| QCOMPARE(myvectwo, QVector<QString>() << "D" << "E" << "F"); |
| |
| // += |
| myvec += myvectwo; |
| QCOMPARE(myvec, combined); |
| |
| // == |
| QVERIFY(myvec == combined); |
| |
| // <, >, <=, >= |
| QVERIFY(!(myvec < combined)); |
| QVERIFY(!(myvec > combined)); |
| QVERIFY( myvec <= combined); |
| QVERIFY( myvec >= combined); |
| combined.push_back("G"); |
| QVERIFY( myvec < combined); |
| QVERIFY(!(myvec > combined)); |
| QVERIFY( myvec <= combined); |
| QVERIFY(!(myvec >= combined)); |
| QVERIFY(combined > myvec); |
| QVERIFY(combined >= myvec); |
| |
| // [] |
| QCOMPARE(myvec[0], QLatin1String("A")); |
| QCOMPARE(myvec[1], QLatin1String("B")); |
| QCOMPARE(myvec[2], QLatin1String("C")); |
| QCOMPARE(myvec[3], QLatin1String("D")); |
| QCOMPARE(myvec[4], QLatin1String("E")); |
| QCOMPARE(myvec[5], QLatin1String("F")); |
| } |
| |
| |
| int fooCtor; |
| int fooDtor; |
| |
| struct Foo |
| { |
| int *p; |
| |
| Foo() { p = new int; ++fooCtor; } |
| Foo(const Foo &other) { Q_UNUSED(other); p = new int; ++fooCtor; } |
| |
| void operator=(const Foo & /* other */) { } |
| |
| ~Foo() { delete p; ++fooDtor; } |
| }; |
| |
| void tst_QVector::reserve() |
| { |
| fooCtor = 0; |
| fooDtor = 0; |
| { |
| QVector<Foo> a; |
| a.resize(2); |
| QCOMPARE(fooCtor, 2); |
| QVector<Foo> b(a); |
| b.reserve(1); |
| QCOMPARE(b.size(), a.size()); |
| QCOMPARE(fooDtor, 0); |
| } |
| QCOMPARE(fooCtor, fooDtor); |
| } |
| |
| // This is a regression test for QTBUG-51758 |
| void tst_QVector::reserveZero() |
| { |
| QVector<int> vec; |
| vec.detach(); |
| vec.reserve(0); // should not crash |
| QCOMPARE(vec.size(), 0); |
| QCOMPARE(vec.capacity(), 0); |
| vec.squeeze(); |
| QCOMPARE(vec.size(), 0); |
| QCOMPARE(vec.capacity(), 0); |
| vec.reserve(-1); |
| QCOMPARE(vec.size(), 0); |
| QCOMPARE(vec.capacity(), 0); |
| vec.append(42); |
| QCOMPARE(vec.size(), 1); |
| QVERIFY(vec.capacity() >= 1); |
| } |
| |
| // This is a regression test for QTBUG-11763, where memory would be reallocated |
| // soon after copying a QVector. |
| void tst_QVector::reallocAfterCopy_data() |
| { |
| QTest::addColumn<int>("capacity"); |
| QTest::addColumn<int>("fill_size"); |
| QTest::addColumn<int>("func_id"); |
| QTest::addColumn<int>("result1"); |
| QTest::addColumn<int>("result2"); |
| QTest::addColumn<int>("result3"); |
| QTest::addColumn<int>("result4"); |
| |
| int result1, result2, result3, result4; |
| int fill_size; |
| for (int i = 70; i <= 100; i += 10) { |
| const QByteArray prefix = "reallocAfterCopy:" + QByteArray::number(i) + ','; |
| fill_size = i - 20; |
| for (int j = 0; j <= 3; j++) { |
| if (j == 0) { // append |
| result1 = i; |
| result2 = i; |
| result3 = i - 19; |
| result4 = i - 20; |
| } else if (j == 1) { // insert(0) |
| result1 = i; |
| result2 = i; |
| result3 = i - 19; |
| result4 = i - 20; |
| } else if (j == 2) { // insert(20) |
| result1 = i; |
| result2 = i; |
| result3 = i - 19; |
| result4 = i - 20; |
| } else if (j == 3) { // insert(0, 10) |
| result1 = i; |
| result2 = i; |
| result3 = i - 10; |
| result4 = i - 20; |
| } |
| QTest::newRow((prefix + QByteArray::number(j)).constData()) |
| << i << fill_size << j << result1 << result2 << result3 << result4; |
| } |
| } |
| } |
| |
| void tst_QVector::reallocAfterCopy() |
| { |
| QFETCH(int, capacity); |
| QFETCH(int, fill_size); |
| QFETCH(int, func_id); |
| QFETCH(int, result1); |
| QFETCH(int, result2); |
| QFETCH(int, result3); |
| QFETCH(int, result4); |
| |
| QVector<qreal> v1; |
| QVector<qreal> v2; |
| |
| v1.reserve(capacity); |
| v1.resize(0); |
| v1.fill(qreal(1.0), fill_size); |
| |
| v2 = v1; |
| |
| // no need to test begin() and end(), there is a detach() in them |
| if (func_id == 0) { |
| v1.append(qreal(1.0)); //push_back is same as append |
| } else if (func_id == 1) { |
| v1.insert(0, qreal(1.0)); //push_front is same as prepend, insert(0) |
| } else if (func_id == 2) { |
| v1.insert(20, qreal(1.0)); |
| } else if (func_id == 3) { |
| v1.insert(0, 10, qreal(1.0)); |
| } |
| |
| QCOMPARE(v1.capacity(), result1); |
| QCOMPARE(v2.capacity(), result2); |
| QCOMPARE(v1.size(), result3); |
| QCOMPARE(v2.size(), result4); |
| } |
| |
| template<typename T> |
| void tst_QVector::initializeList() |
| { |
| 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); |
| |
| QVector<T> v4({}); |
| QCOMPARE(v4.size(), 0); |
| } |
| |
| void tst_QVector::initializeListInt() |
| { |
| initializeList<int>(); |
| } |
| |
| void tst_QVector::initializeListMovable() |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| initializeList<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::initializeListCustom() |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| initializeList<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::const_shared_null() |
| { |
| QVector<int> v2; |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| QVector<int> v1; |
| v1.setSharable(false); |
| QVERIFY(v1.isDetached()); |
| |
| v2.setSharable(true); |
| #endif |
| QVERIFY(!v2.isDetached()); |
| } |
| |
| #if !defined(QT_NO_UNSHARABLE_CONTAINERS) |
| // ### Qt6 remove this section |
| template<typename T> |
| void tst_QVector::setSharable_data() const |
| { |
| QTest::addColumn<QVector<T> >("vector"); |
| QTest::addColumn<int>("size"); |
| QTest::addColumn<int>("capacity"); |
| QTest::addColumn<bool>("isCapacityReserved"); |
| |
| 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 << 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); |
| |
| QTest::newRow("null") << null << 0 << 0 << false; |
| QTest::newRow("empty") << empty << 0 << 0 << false; |
| QTest::newRow("empty, Reserved") << emptyReserved << 0 << 10 << true; |
| QTest::newRow("non-empty") << nonEmpty << 5 << 0 << false; |
| QTest::newRow("non-empty, Reserved") << nonEmptyReserved << 7 << 15 << true; |
| } |
| |
| template<typename T> |
| void tst_QVector::setSharable() const |
| { |
| QFETCH(QVector<T>, vector); |
| QFETCH(int, size); |
| QFETCH(int, capacity); |
| QFETCH(bool, isCapacityReserved); |
| |
| QVERIFY(!vector.isDetached()); // Shared with QTest |
| |
| vector.setSharable(true); |
| |
| QCOMPARE(vector.size(), size); |
| if (isCapacityReserved) |
| QVERIFY2(vector.capacity() >= capacity, |
| qPrintable(QString("Capacity is %1, expected at least %2.") |
| .arg(vector.capacity()) |
| .arg(capacity))); |
| |
| { |
| QVector<T> copy(vector); |
| |
| QVERIFY(!copy.isDetached()); |
| QVERIFY(copy.isSharedWith(vector)); |
| } |
| |
| vector.setSharable(false); |
| QVERIFY(vector.isDetached() || vector.isSharedWith(QVector<T>())); |
| |
| { |
| QVector<T> copy(vector); |
| |
| QVERIFY(copy.isDetached() || copy.isEmpty() || copy.isSharedWith(QVector<T>())); |
| QCOMPARE(copy.size(), size); |
| if (isCapacityReserved) |
| QVERIFY2(copy.capacity() >= capacity, |
| qPrintable(QString("Capacity is %1, expected at least %2.") |
| .arg(copy.capacity()) |
| .arg(capacity))); |
| QCOMPARE(copy, vector); |
| } |
| |
| vector.setSharable(true); |
| |
| { |
| QVector<T> copy(vector); |
| |
| QVERIFY(!copy.isDetached()); |
| QVERIFY(copy.isSharedWith(vector)); |
| } |
| |
| for (int i = 0; i < vector.size(); ++i) |
| QCOMPARE(vector[i], SimpleValue<T>::at(i)); |
| |
| QCOMPARE(vector.size(), size); |
| if (isCapacityReserved) |
| QVERIFY2(vector.capacity() >= capacity, |
| qPrintable(QString("Capacity is %1, expected at least %2.") |
| .arg(vector.capacity()) |
| .arg(capacity))); |
| } |
| #else |
| template<typename T> void tst_QVector::setSharable_data() const |
| { |
| } |
| |
| template<typename T> void tst_QVector::setSharable() const |
| { |
| } |
| #endif |
| |
| void tst_QVector::setSharableInt_data() |
| { |
| setSharable_data<int>(); |
| } |
| |
| void tst_QVector::setSharableMovable_data() |
| { |
| setSharable_data<Movable>(); |
| } |
| |
| void tst_QVector::setSharableCustom_data() |
| { |
| setSharable_data<Custom>(); |
| } |
| |
| void tst_QVector::setSharableInt() |
| { |
| setSharable<int>(); |
| } |
| |
| void tst_QVector::setSharableMovable() |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| setSharable<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::setSharableCustom() |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| setSharable<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| 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.loadAcquire(); |
| detach<Movable>(); |
| QCOMPARE(instancesCount, Movable::counter.loadAcquire()); |
| } |
| |
| void tst_QVector::detachCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| detach<Custom>(); |
| QCOMPARE(instancesCount, Custom::counter.loadAcquire()); |
| } |
| |
| static QAtomicPointer<QVector<int> > detachThreadSafetyDataInt; |
| static QAtomicPointer<QVector<Movable> > detachThreadSafetyDataMovable; |
| static QAtomicPointer<QVector<Custom> > detachThreadSafetyDataCustom; |
| |
| template<typename T> QAtomicPointer<QVector<T> > *detachThreadSafetyData(); |
| template<> QAtomicPointer<QVector<int> > *detachThreadSafetyData() { return &detachThreadSafetyDataInt; } |
| template<> QAtomicPointer<QVector<Movable> > *detachThreadSafetyData() { return &detachThreadSafetyDataMovable; } |
| template<> QAtomicPointer<QVector<Custom> > *detachThreadSafetyData() { return &detachThreadSafetyDataCustom; } |
| |
| static QSemaphore detachThreadSafetyLock; |
| |
| template<typename T> |
| void tst_QVector::detachThreadSafety() const |
| { |
| delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(new QVector<T>(SimpleValue<T>::vector(400))); |
| |
| static const uint threadsCount = 5; |
| |
| struct : QThread { |
| void run() override |
| { |
| QVector<T> copy(*detachThreadSafetyData<T>()->loadRelaxed()); |
| QVERIFY(!copy.isDetached()); |
| detachThreadSafetyLock.release(); |
| detachThreadSafetyLock.acquire(100); |
| copy.detach(); |
| } |
| } threads[threadsCount]; |
| |
| for (uint i = 0; i < threadsCount; ++i) |
| threads[i].start(); |
| QThread::yieldCurrentThread(); |
| detachThreadSafetyLock.acquire(threadsCount); |
| |
| // destroy static original data |
| delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(0); |
| |
| QVERIFY(threadsCount < 100); |
| detachThreadSafetyLock.release(threadsCount * 100); |
| QThread::yieldCurrentThread(); |
| |
| for (uint i = 0; i < threadsCount; ++i) |
| threads[i].wait(); |
| } |
| |
| void tst_QVector::detachThreadSafetyInt() const |
| { |
| for (uint i = 0; i < 128; ++i) |
| detachThreadSafety<int>(); |
| } |
| |
| void tst_QVector::detachThreadSafetyMovable() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| for (uint i = 0; i < 128; ++i) { |
| detachThreadSafety<Movable>(); |
| QCOMPARE(Movable::counter.loadAcquire(), instancesCount); |
| } |
| } |
| |
| void tst_QVector::detachThreadSafetyCustom() const |
| { |
| const int instancesCount = Custom::counter.loadAcquire(); |
| for (uint i = 0; i < 128; ++i) { |
| detachThreadSafety<Custom>(); |
| QCOMPARE(Custom::counter.loadAcquire(), instancesCount); |
| } |
| } |
| |
| void tst_QVector::insertMove() const |
| { |
| const int instancesCount = Movable::counter.loadAcquire(); |
| { |
| QVector<Movable> vec; |
| vec.reserve(7); |
| Movable m0; |
| Movable m1; |
| Movable m2; |
| Movable m3; |
| Movable m4; |
| Movable m5; |
| Movable m6; |
| |
| vec.append(std::move(m3)); |
| QVERIFY(m3.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m3)); |
| vec.push_back(std::move(m4)); |
| QVERIFY(m4.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m3)); |
| QVERIFY(vec.at(1).wasConstructedAt(&m4)); |
| vec.prepend(std::move(m1)); |
| QVERIFY(m1.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m1)); |
| QVERIFY(vec.at(1).wasConstructedAt(&m3)); |
| QVERIFY(vec.at(2).wasConstructedAt(&m4)); |
| vec.insert(1, std::move(m2)); |
| QVERIFY(m2.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m1)); |
| QVERIFY(vec.at(1).wasConstructedAt(&m2)); |
| QVERIFY(vec.at(2).wasConstructedAt(&m3)); |
| QVERIFY(vec.at(3).wasConstructedAt(&m4)); |
| vec += std::move(m5); |
| QVERIFY(m5.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m1)); |
| QVERIFY(vec.at(1).wasConstructedAt(&m2)); |
| QVERIFY(vec.at(2).wasConstructedAt(&m3)); |
| QVERIFY(vec.at(3).wasConstructedAt(&m4)); |
| QVERIFY(vec.at(4).wasConstructedAt(&m5)); |
| vec << std::move(m6); |
| QVERIFY(m6.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m1)); |
| QVERIFY(vec.at(1).wasConstructedAt(&m2)); |
| QVERIFY(vec.at(2).wasConstructedAt(&m3)); |
| QVERIFY(vec.at(3).wasConstructedAt(&m4)); |
| QVERIFY(vec.at(4).wasConstructedAt(&m5)); |
| QVERIFY(vec.at(5).wasConstructedAt(&m6)); |
| vec.push_front(std::move(m0)); |
| QVERIFY(m0.wasConstructedAt(nullptr)); |
| QVERIFY(vec.at(0).wasConstructedAt(&m0)); |
| QVERIFY(vec.at(1).wasConstructedAt(&m1)); |
| QVERIFY(vec.at(2).wasConstructedAt(&m2)); |
| QVERIFY(vec.at(3).wasConstructedAt(&m3)); |
| QVERIFY(vec.at(4).wasConstructedAt(&m4)); |
| QVERIFY(vec.at(5).wasConstructedAt(&m5)); |
| QVERIFY(vec.at(6).wasConstructedAt(&m6)); |
| |
| QCOMPARE(Movable::counter.loadAcquire(), instancesCount + 14); |
| } |
| QCOMPARE(Movable::counter.loadAcquire(), instancesCount); |
| } |
| |
| void tst_QVector::swapItemsAt() const |
| { |
| QVector<int> v; |
| v << 0 << 1 << 2 << 3; |
| |
| v.swapItemsAt(0, 2); |
| QCOMPARE(v.at(0), 2); |
| QCOMPARE(v.at(2), 0); |
| |
| auto copy = v; |
| copy.swapItemsAt(0, 2); |
| QCOMPARE(v.at(0), 2); |
| QCOMPARE(v.at(2), 0); |
| QCOMPARE(copy.at(0), 0); |
| QCOMPARE(copy.at(2), 2); |
| } |
| |
| QTEST_MAIN(tst_QVector) |
| #include "tst_qvector.moc" |