Introduce QArrayDataOps::appendInitialize

Adds given number of default-initialized elements at end of array. For
POD types, initialization is reduced to a single memset call. Other
types get default constructed in place.

As part of adding a test for the new functionality the arrayOps test was
extended to verify objects are being constructed and assigned as
desired.

Change-Id: I9fb2afe0d92667e76993313fcd370fe129d72b90
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
João Abecasis 2012-02-16 23:27:07 +01:00 committed by Qt by Nokia
parent e4682cc880
commit 646dc6c5da
3 changed files with 103 additions and 1 deletions

View File

@ -57,6 +57,16 @@ template <class T>
struct QPodArrayOps struct QPodArrayOps
: QTypedArrayData<T> : QTypedArrayData<T>
{ {
void appendInitialize(size_t newSize)
{
Q_ASSERT(!this->ref.isShared());
Q_ASSERT(newSize > uint(this->size));
Q_ASSERT(newSize <= this->alloc);
::memset(this->end(), 0, (newSize - this->size) * sizeof(T));
this->size = newSize;
}
void copyAppend(const T *b, const T *e) void copyAppend(const T *b, const T *e)
{ {
Q_ASSERT(!this->ref.isShared()); Q_ASSERT(!this->ref.isShared());
@ -105,6 +115,18 @@ template <class T>
struct QGenericArrayOps struct QGenericArrayOps
: QTypedArrayData<T> : QTypedArrayData<T>
{ {
void appendInitialize(size_t newSize)
{
Q_ASSERT(!this->ref.isShared());
Q_ASSERT(newSize > uint(this->size));
Q_ASSERT(newSize <= this->alloc);
T *const begin = this->begin();
do {
new (begin + this->size) T();
} while (uint(++this->size) != newSize);
}
void copyAppend(const T *b, const T *e) void copyAppend(const T *b, const T *e)
{ {
Q_ASSERT(!this->ref.isShared()); Q_ASSERT(!this->ref.isShared());
@ -215,6 +237,7 @@ template <class T>
struct QMovableArrayOps struct QMovableArrayOps
: QGenericArrayOps<T> : QGenericArrayOps<T>
{ {
// using QGenericArrayOps<T>::appendInitialize;
// using QGenericArrayOps<T>::copyAppend; // using QGenericArrayOps<T>::copyAppend;
// using QGenericArrayOps<T>::destroyAll; // using QGenericArrayOps<T>::destroyAll;

View File

@ -63,6 +63,13 @@ public:
{ {
} }
explicit SimpleVector(size_t n)
: d(Data::allocate(n))
{
if (n)
d->appendInitialize(n);
}
SimpleVector(size_t n, const T &t) SimpleVector(size_t n, const T &t)
: d(Data::allocate(n)) : d(Data::allocate(n))
{ {

View File

@ -81,6 +81,7 @@ private slots:
void typedData(); void typedData();
void gccBug43247(); void gccBug43247();
void arrayOps(); void arrayOps();
void appendInitialize();
void setSharable_data(); void setSharable_data();
void setSharable(); void setSharable();
void fromRawData(); void fromRawData();
@ -894,11 +895,15 @@ struct CountedObject
{ {
CountedObject() CountedObject()
: id(liveCount++) : id(liveCount++)
, flags(DefaultConstructed)
{ {
} }
CountedObject(const CountedObject &other) CountedObject(const CountedObject &other)
: id(other.id) : id(other.id)
, flags(other.flags == DefaultConstructed
? ObjectFlags(CopyConstructed | DefaultConstructed)
: CopyConstructed)
{ {
++liveCount; ++liveCount;
} }
@ -910,6 +915,7 @@ struct CountedObject
CountedObject &operator=(const CountedObject &other) CountedObject &operator=(const CountedObject &other)
{ {
flags = ObjectFlags(other.flags | CopyAssigned);
id = other.id; id = other.id;
return *this; return *this;
} }
@ -930,7 +936,15 @@ struct CountedObject
const size_t previousLiveCount; const size_t previousLiveCount;
}; };
enum ObjectFlags {
DefaultConstructed = 1,
CopyConstructed = 2,
CopyAssigned = 4
};
size_t id; // not unique size_t id; // not unique
ObjectFlags flags;
static size_t liveCount; static size_t liveCount;
}; };
@ -968,7 +982,10 @@ void tst_QArrayData::arrayOps()
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
QCOMPARE(vi[i], intArray[i]); QCOMPARE(vi[i], intArray[i]);
QVERIFY(vs[i].isSharedWith(stringArray[i])); QVERIFY(vs[i].isSharedWith(stringArray[i]));
QCOMPARE(vo[i].id, objArray[i].id); QCOMPARE(vo[i].id, objArray[i].id);
QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
| CountedObject::DefaultConstructed);
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -997,7 +1014,10 @@ void tst_QArrayData::arrayOps()
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
QCOMPARE(vi[i], referenceInt); QCOMPARE(vi[i], referenceInt);
QVERIFY(vs[i].isSharedWith(referenceString)); QVERIFY(vs[i].isSharedWith(referenceString));
QCOMPARE(vo[i].id, referenceObject.id); QCOMPARE(vo[i].id, referenceObject.id);
QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
| CountedObject::DefaultConstructed);
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -1042,28 +1062,80 @@ void tst_QArrayData::arrayOps()
QCOMPARE(vo.size(), size_t(30)); QCOMPARE(vo.size(), size_t(30));
QCOMPARE(CountedObject::liveCount, size_t(36)); QCOMPARE(CountedObject::liveCount, size_t(36));
for (int i = 0; i < 15; ++i) { for (int i = 0; i < 5; ++i) {
QCOMPARE(vi[i], intArray[i % 5]); QCOMPARE(vi[i], intArray[i % 5]);
QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); QVERIFY(vs[i].isSharedWith(stringArray[i % 5]));
QCOMPARE(vo[i].id, objArray[i % 5].id); QCOMPARE(vo[i].id, objArray[i % 5].id);
QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed
| CountedObject::CopyAssigned);
}
for (int i = 5; i < 15; ++i) {
QCOMPARE(vi[i], intArray[i % 5]);
QVERIFY(vs[i].isSharedWith(stringArray[i % 5]));
QCOMPARE(vo[i].id, objArray[i % 5].id);
QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
| CountedObject::CopyAssigned);
} }
for (int i = 15; i < 20; ++i) { for (int i = 15; i < 20; ++i) {
QCOMPARE(vi[i], referenceInt); QCOMPARE(vi[i], referenceInt);
QVERIFY(vs[i].isSharedWith(referenceString)); QVERIFY(vs[i].isSharedWith(referenceString));
QCOMPARE(vo[i].id, referenceObject.id); QCOMPARE(vo[i].id, referenceObject.id);
QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
| CountedObject::CopyAssigned);
} }
for (int i = 20; i < 25; ++i) { for (int i = 20; i < 25; ++i) {
QCOMPARE(vi[i], intArray[i % 5]); QCOMPARE(vi[i], intArray[i % 5]);
QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); QVERIFY(vs[i].isSharedWith(stringArray[i % 5]));
QCOMPARE(vo[i].id, objArray[i % 5].id); QCOMPARE(vo[i].id, objArray[i % 5].id);
// Originally inserted as (DefaultConstructed | CopyAssigned), later
// get shuffled into place by std::rotate (SimpleVector::insert,
// overlapping mode).
// Depending on implementation of rotate, final assignment can be:
// - straight from source: DefaultConstructed | CopyAssigned
// - through a temporary: CopyConstructed | CopyAssigned
QCOMPARE(vo[i].flags & CountedObject::CopyAssigned,
int(CountedObject::CopyAssigned));
} }
for (int i = 25; i < 30; ++i) { for (int i = 25; i < 30; ++i) {
QCOMPARE(vi[i], referenceInt); QCOMPARE(vi[i], referenceInt);
QVERIFY(vs[i].isSharedWith(referenceString)); QVERIFY(vs[i].isSharedWith(referenceString));
QCOMPARE(vo[i].id, referenceObject.id); QCOMPARE(vo[i].id, referenceObject.id);
QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
| CountedObject::CopyAssigned);
}
}
void tst_QArrayData::appendInitialize()
{
CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker)
////////////////////////////////////////////////////////////////////////////
// appendInitialize
SimpleVector<int> vi(5);
SimpleVector<QString> vs(5);
SimpleVector<CountedObject> vo(5);
QCOMPARE(vi.size(), size_t(5));
QCOMPARE(vs.size(), size_t(5));
QCOMPARE(vo.size(), size_t(5));
QCOMPARE(CountedObject::liveCount, size_t(5));
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), int(CountedObject::DefaultConstructed));
} }
} }