From 747800675044bc1782b9bc9b97cea2cc2ef2c06f Mon Sep 17 00:00:00 2001 From: Ievgenii Meshcheriakov Date: Tue, 12 Oct 2021 16:17:32 +0200 Subject: QVector: Don't require default-constructible types with insert() Don't require existence of a default constructor inside 3-argument insert() and use copy constructor and assignment operator instead. This makes insert() and other operations usable with types that have neither a default constructor nor a move constructor. Also use std::move() to shift the existing content. Add new testcases to tst_qvector to verify the functionality. Fixes: QTBUG-93392 Change-Id: I88fb4b882339d64f17e6477a974502efbb0dfb88 Reviewed-by: Edward Welbourne Reviewed-by: Sona Kurazyan --- tests/auto/corelib/tools/qvector/tst_qvector.cpp | 108 +++++++++++++++++++++++ 1 file changed, 108 insertions(+) (limited to 'tests/auto/corelib/tools/qvector/tst_qvector.cpp') diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp index 08d5a8cd50..01409bd188 100644 --- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp +++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp @@ -183,6 +183,94 @@ inline uint qHash(const Custom &key, uint seed = 0) { return qHash(key.i, seed); Q_DECLARE_METATYPE(Custom); +// Similar to Custom but not default-constructible and has move constructor and assignment +struct NonDefaultConstructible { + NonDefaultConstructible() = delete; + NonDefaultConstructible(char input) + : i(input) + , that(this) + , state(Constructed) + { + counter.fetchAndAddRelaxed(1); + } + NonDefaultConstructible(const NonDefaultConstructible &other) + : i(other.i) + , that(this) + , state(Constructed) + { + check(&other); + counter.fetchAndAddRelaxed(1); + } + NonDefaultConstructible(NonDefaultConstructible &&other) + : i(other.i) + , that(this) + , state(Constructed) + { + check(&other); + other.state = MovedFrom; + counter.fetchAndAddRelaxed(1); + } + ~NonDefaultConstructible() + { + check(this, true); + i = 0; + counter.fetchAndAddRelaxed(-1); + state = Destructed; + } + + bool operator==(const NonDefaultConstructible &other) const + { + check(&other); + check(this); + return i == other.i; + } + + bool operator<(const NonDefaultConstructible &other) const + { + check(&other); + check(this); + return i < other.i; + } + + NonDefaultConstructible &operator=(const NonDefaultConstructible &other) + { + check(&other); + check(this, true); + i = other.i; + state = Constructed; + return *this; + } + + NonDefaultConstructible &operator=(NonDefaultConstructible &&other) + { + check(&other); + check(this, true); + i = other.i; + state = Constructed; + other.state = MovedFrom; + return *this; + } + static QAtomicInt counter; + + char i; // used to identify origin of an instance +private: + NonDefaultConstructible *that; // used to catch copying using mem{cpy,move}() + + enum State { Constructed = 106, Destructed = 110, MovedFrom = 120 }; + State state; + + static void check(const NonDefaultConstructible *c, bool movedOk = false) + { + // check if c object has been moved incorrectly + QCOMPARE(c, c->that); + if (!movedOk || c->state != MovedFrom) + QCOMPARE(c->state, Constructed); + } +}; +QAtomicInt NonDefaultConstructible::counter = 0; + +inline uint qHash(const NonDefaultConstructible &key, uint seed = 0) { return qHash(key.i, seed); } + // tests depends on the fact that: Q_STATIC_ASSERT(!QTypeInfo::isStatic); Q_STATIC_ASSERT(!QTypeInfo::isComplex); @@ -190,6 +278,8 @@ Q_STATIC_ASSERT(!QTypeInfo::isStatic); Q_STATIC_ASSERT(QTypeInfo::isComplex); Q_STATIC_ASSERT(QTypeInfo::isStatic); Q_STATIC_ASSERT(QTypeInfo::isComplex); +Q_STATIC_ASSERT(QTypeInfo::isStatic); +Q_STATIC_ASSERT(QTypeInfo::isComplex); class tst_QVector : public QObject @@ -263,6 +353,7 @@ private slots: void insertInt() const; void insertMovable() const; void insertCustom() const; + void insertNonDefaultConstructible() const; void isEmpty() const; void last() const; void lastIndexOf() const; @@ -273,6 +364,7 @@ private slots: void prependInt() const; void prependMovable() const; void prependCustom() const; + void prependNonDefaultConstructible() const; void qhashInt() const { qhash(); } void qhashMovable() const { qhash(); } void qhashCustom() const { qhash(); } @@ -390,6 +482,10 @@ template<> const Movable SimpleValue::Values[] = { 110, 105, 101, 114, 111, 98 }; template<> const Custom SimpleValue::Values[] = { 110, 105, 101, 114, 111, 98 }; +template<> +const NonDefaultConstructible SimpleValue::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::at(0) @@ -1592,6 +1688,11 @@ void tst_QVector::insertCustom() const insert(); } +void tst_QVector::insertNonDefaultConstructible() const +{ + insert(); +} + void tst_QVector::isEmpty() const { QVector myvec; @@ -1831,6 +1932,13 @@ void tst_QVector::prependCustom() const QCOMPARE(instancesCount, Custom::counter.loadAcquire()); } +void tst_QVector::prependNonDefaultConstructible() const +{ + const int instancesCount = NonDefaultConstructible::counter.loadAcquire(); + prepend(); + QCOMPARE(instancesCount, NonDefaultConstructible::counter.loadAcquire()); +} + void tst_QVector::removeAllWithAlias() const { QVector strings; -- cgit v1.2.3