diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 785a26c3a8..de149b701c 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -89,6 +89,14 @@ struct QPodArrayOps this->size += n; } + void truncate(size_t newSize) + { + Q_ASSERT(!this->ref.isShared()); + Q_ASSERT(newSize < size_t(this->size)); + + this->size = newSize; + } + void destroyAll() // Call from destructors, ONLY! { Q_ASSERT(this->ref.atomic.load() == 0); @@ -153,6 +161,17 @@ struct QGenericArrayOps } } + void truncate(size_t newSize) + { + Q_ASSERT(!this->ref.isShared()); + Q_ASSERT(newSize < size_t(this->size)); + + const T *const b = this->begin(); + do { + (b + --this->size)->~T(); + } while (uint(this->size) != newSize); + } + void destroyAll() // Call from destructors, ONLY { // As this is to be called only from destructor, it doesn't need to be @@ -239,6 +258,7 @@ struct QMovableArrayOps { // using QGenericArrayOps::appendInitialize; // using QGenericArrayOps::copyAppend; + // using QGenericArrayOps::truncate; // using QGenericArrayOps::destroyAll; void insert(T *where, const T *b, const T *e) diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index 54c9fae589..641516e0d0 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -170,6 +170,36 @@ public: detached.swap(*this); } + void resize(size_t newSize) + { + if (size() == newSize) + return; + + if (d->ref.isShared() || newSize > capacity()) { + SimpleVector detached(Data::allocate( + d->detachCapacity(newSize), d->detachFlags())); + if (newSize) { + if (newSize < size()) { + const T *const begin = constBegin(); + detached.d->copyAppend(begin, begin + newSize); + } else { + if (size()) { + const T *const begin = constBegin(); + detached.d->copyAppend(begin, begin + size()); + } + detached.d->appendInitialize(newSize); + } + } + detached.swap(*this); + return; + } + + if (newSize > size()) + d->appendInitialize(newSize); + else + d->truncate(newSize); + } + void prepend(const_iterator first, const_iterator last) { if (!d->size) { diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index b3b8040b1c..53217b2222 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -81,7 +81,7 @@ private slots: void typedData(); void gccBug43247(); void arrayOps(); - void appendInitialize(); + void arrayOps2(); void setSharable_data(); void setSharable(); void fromRawData(); @@ -1115,7 +1115,7 @@ void tst_QArrayData::arrayOps() } } -void tst_QArrayData::appendInitialize() +void tst_QArrayData::arrayOps2() { CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker) @@ -1137,6 +1137,69 @@ void tst_QArrayData::appendInitialize() QCOMPARE(vo[i].id, i); QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); } + + //////////////////////////////////////////////////////////////////////////// + // appendInitialize, again + + // These will detach + vi.resize(10); + vs.resize(10); + vo.resize(10); + + QCOMPARE(vi.size(), size_t(10)); + QCOMPARE(vs.size(), size_t(10)); + QCOMPARE(vo.size(), size_t(10)); + + QCOMPARE(CountedObject::liveCount, size_t(10)); + for (size_t i = 0; i < 5; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i); + QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed + | CountedObject::CopyConstructed); + } + + for (size_t i = 5; i < 10; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i + 5); + QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); + } + + //////////////////////////////////////////////////////////////////////////// + // truncate + QVERIFY(!vi.isShared()); + QVERIFY(!vs.isShared()); + QVERIFY(!vo.isShared()); + + // These shouldn't detach + vi.resize(7); + vs.resize(7); + vo.resize(7); + + QCOMPARE(vi.size(), size_t(7)); + QCOMPARE(vs.size(), size_t(7)); + QCOMPARE(vo.size(), size_t(7)); + + QCOMPARE(CountedObject::liveCount, size_t(7)); + for (size_t i = 0; i < 5; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i); + QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed + | CountedObject::CopyConstructed); + } + + for (size_t i = 5; i < 7; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i + 5); + QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); + } } Q_DECLARE_METATYPE(QArrayDataPointer)