Introduce QArrayDataOps::truncate

This enables a truncating resize() to be implemented. It is similar to
destroyAll(), but updates the size() as it goes, so it is safe to use
outside a container's destructor (and doesn't necessarily destroy all
elements).

The appendInitialize test was repurposed and now doubles as an
additional test for QArrayDataOps as well as exercising SimpleVector's
resize().

Change-Id: Iee94a685c9ea436c6af5b1b77486734a38c49ca1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
João Abecasis 2012-02-16 23:27:44 +01:00 committed by Qt by Nokia
parent 8c413f3eff
commit 15e3ae6b9d
3 changed files with 115 additions and 2 deletions

View File

@ -89,6 +89,14 @@ struct QPodArrayOps
this->size += n; 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! void destroyAll() // Call from destructors, ONLY!
{ {
Q_ASSERT(this->ref.atomic.load() == 0); 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 void destroyAll() // Call from destructors, ONLY
{ {
// As this is to be called only from destructor, it doesn't need to be // As this is to be called only from destructor, it doesn't need to be
@ -239,6 +258,7 @@ struct QMovableArrayOps
{ {
// using QGenericArrayOps<T>::appendInitialize; // using QGenericArrayOps<T>::appendInitialize;
// using QGenericArrayOps<T>::copyAppend; // using QGenericArrayOps<T>::copyAppend;
// using QGenericArrayOps<T>::truncate;
// using QGenericArrayOps<T>::destroyAll; // using QGenericArrayOps<T>::destroyAll;
void insert(T *where, const T *b, const T *e) void insert(T *where, const T *b, const T *e)

View File

@ -170,6 +170,36 @@ public:
detached.swap(*this); 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) void prepend(const_iterator first, const_iterator last)
{ {
if (!d->size) { if (!d->size) {

View File

@ -81,7 +81,7 @@ private slots:
void typedData(); void typedData();
void gccBug43247(); void gccBug43247();
void arrayOps(); void arrayOps();
void appendInitialize(); void arrayOps2();
void setSharable_data(); void setSharable_data();
void setSharable(); void setSharable();
void fromRawData(); void fromRawData();
@ -1115,7 +1115,7 @@ void tst_QArrayData::arrayOps()
} }
} }
void tst_QArrayData::appendInitialize() void tst_QArrayData::arrayOps2()
{ {
CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker) CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker)
@ -1137,6 +1137,69 @@ void tst_QArrayData::appendInitialize()
QCOMPARE(vo[i].id, i); QCOMPARE(vo[i].id, i);
QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); 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<int>) Q_DECLARE_METATYPE(QArrayDataPointer<int>)