From 646dc6c5daeefa99c9af070802c39bc66dc4f1f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 16 Feb 2012 23:27:07 +0100 Subject: [PATCH] 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 --- src/corelib/tools/qarraydataops.h | 23 ++++++ .../corelib/tools/qarraydata/simplevector.h | 7 ++ .../tools/qarraydata/tst_qarraydata.cpp | 74 ++++++++++++++++++- 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 1b8ed3372d..785a26c3a8 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -57,6 +57,16 @@ template struct QPodArrayOps : QTypedArrayData { + 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) { Q_ASSERT(!this->ref.isShared()); @@ -105,6 +115,18 @@ template struct QGenericArrayOps : QTypedArrayData { + 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) { Q_ASSERT(!this->ref.isShared()); @@ -215,6 +237,7 @@ template struct QMovableArrayOps : QGenericArrayOps { + // using QGenericArrayOps::appendInitialize; // using QGenericArrayOps::copyAppend; // using QGenericArrayOps::destroyAll; diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index fe8108bff2..0cc7561b46 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -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) : d(Data::allocate(n)) { diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 4bd04f9bc3..6d3bbf046f 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -81,6 +81,7 @@ private slots: void typedData(); void gccBug43247(); void arrayOps(); + void appendInitialize(); void setSharable_data(); void setSharable(); void fromRawData(); @@ -894,11 +895,15 @@ struct CountedObject { CountedObject() : id(liveCount++) + , flags(DefaultConstructed) { } CountedObject(const CountedObject &other) : id(other.id) + , flags(other.flags == DefaultConstructed + ? ObjectFlags(CopyConstructed | DefaultConstructed) + : CopyConstructed) { ++liveCount; } @@ -910,6 +915,7 @@ struct CountedObject CountedObject &operator=(const CountedObject &other) { + flags = ObjectFlags(other.flags | CopyAssigned); id = other.id; return *this; } @@ -930,7 +936,15 @@ struct CountedObject const size_t previousLiveCount; }; + enum ObjectFlags { + DefaultConstructed = 1, + CopyConstructed = 2, + CopyAssigned = 4 + }; + size_t id; // not unique + ObjectFlags flags; + static size_t liveCount; }; @@ -968,7 +982,10 @@ void tst_QArrayData::arrayOps() for (int i = 0; i < 5; ++i) { QCOMPARE(vi[i], intArray[i]); QVERIFY(vs[i].isSharedWith(stringArray[i])); + 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) { QCOMPARE(vi[i], referenceInt); QVERIFY(vs[i].isSharedWith(referenceString)); + 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(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]); QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); + 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) { QCOMPARE(vi[i], referenceInt); QVERIFY(vs[i].isSharedWith(referenceString)); + QCOMPARE(vo[i].id, referenceObject.id); + QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed + | CountedObject::CopyAssigned); } for (int i = 20; i < 25; ++i) { QCOMPARE(vi[i], intArray[i % 5]); QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); + 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) { QCOMPARE(vi[i], referenceInt); QVERIFY(vs[i].isSharedWith(referenceString)); + 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 vi(5); + SimpleVector vs(5); + SimpleVector 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)); } }