From 390eec325b25a142ce2204f1d1950621d4a519e3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20Abecasis?= Date: Tue, 29 Nov 2011 17:53:57 +0100 Subject: [PATCH] template struct QTypedArrayData MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit QTypedArrayData is a typed overlay for QArrayData, providing convenience and type-safety. It adds no data members to QArrayData, thus avoiding compiler-generated warnings for aliasing issues when casting back and forth. Change-Id: I969342a30989c4c14b3d03d0602e3d60a4cc0e9d Reviewed-by: João Abecasis --- src/corelib/tools/qarraydata.h | 42 +++++++ tests/auto/corelib/tools/qarraydata/simplevector.h | 34 ++++-- .../corelib/tools/qarraydata/tst_qarraydata.cpp | 133 ++++++++++++++++++++- 3 files changed, 194 insertions(+), 15 deletions(-) diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 684f008..1312fec 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -82,6 +82,48 @@ struct Q_CORE_EXPORT QArrayData static const QArrayData shared_empty; }; +template +struct QTypedArrayData + : QArrayData +{ + typedef T *iterator; + typedef const T *const_iterator; + + T *data() { return static_cast(QArrayData::data()); } + const T *data() const { return static_cast(QArrayData::data()); } + + T *begin() { return data(); } + T *end() { return data() + size; } + const T *begin() const { return data(); } + const T *end() const { return data() + size; } + + class AlignmentDummy { QArrayData header; T data; }; + + static QTypedArrayData *allocate(size_t capacity, bool reserve = false) + Q_REQUIRED_RESULT + { + return static_cast(QArrayData::allocate(sizeof(T), + Q_ALIGNOF(AlignmentDummy), capacity, reserve)); + } + + static void deallocate(QArrayData *data) + { + QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy)); + } + + static QTypedArrayData *sharedNull() + { + return static_cast( + const_cast(&QArrayData::shared_null)); + } + + static QTypedArrayData *sharedEmpty() + { + return static_cast( + const_cast(&QArrayData::shared_empty)); + } +}; + template struct QStaticArrayData { diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index ad08ad5..099045d 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -50,15 +50,15 @@ template struct SimpleVector { private: - typedef QArrayData Data; + typedef QTypedArrayData Data; public: typedef T value_type; - typedef T *iterator; - typedef const T *const_iterator; + typedef typename Data::iterator iterator; + typedef typename Data::const_iterator const_iterator; SimpleVector() - : d(const_cast(&Data::shared_null)) + : d(Data::sharedNull()) { } @@ -68,6 +68,15 @@ public: d->ref.ref(); } + SimpleVector(size_t n, const T &t) + : d(Data::allocate(n)) + { + for (size_t i = 0; i < n; ++i) { + new (d->end()) T(t); + ++d->size; + } + } + explicit SimpleVector(Data *ptr) : d(ptr) { @@ -75,9 +84,12 @@ public: ~SimpleVector() { - if (!d->ref.deref()) - // Not implemented - Q_ASSERT(false); + if (!d->ref.deref()) { + const T *const data = d->data(); + while (d->size--) + data[d->size].~T(); + Data::deallocate(d); + } } SimpleVector &operator=(const SimpleVector &vec) @@ -88,7 +100,7 @@ public: } bool empty() const { return d->size == 0; } - bool isNull() const { return d == &Data::shared_null; } + bool isNull() const { return d == Data::sharedNull(); } bool isEmpty() const { return this->empty(); } bool isSharedWith(const SimpleVector &other) const { return d == other.d; } @@ -96,8 +108,8 @@ public: size_t size() const { return d->size; } size_t capacity() const { return d->alloc; } - const_iterator begin() const { return static_cast(d->data()); } - const_iterator end() const { return static_cast(d->data()) + d->size; } + const_iterator begin() const { return d->begin(); } + const_iterator end() const { return d->end(); } const_iterator constBegin() const { return begin(); } const_iterator constEnd() const { return end(); } @@ -125,7 +137,7 @@ public: void clear() { SimpleVector tmp(d); - d = const_cast(&Data::shared_empty); + d = Data::sharedEmpty(); } private: diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 7dfbd65..8bbef9b 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -58,6 +58,7 @@ private slots: void allocate(); void alignment_data(); void alignment(); + void typedData(); }; void tst_QArrayData::referenceCounting() @@ -165,10 +166,11 @@ void tst_QArrayData::simpleVector() SimpleVector v1; SimpleVector v2(v1); - SimpleVector v3(&data0); - SimpleVector v4(&data1.header); - SimpleVector v5(&data0); - SimpleVector v6(&data1.header); + SimpleVector v3(static_cast *>(&data0)); + SimpleVector v4(static_cast *>(&data1.header)); + SimpleVector v5(static_cast *>(&data0)); + SimpleVector v6(static_cast *>(&data1.header)); + SimpleVector v7(10, 5); v3 = v1; v1.swap(v3); @@ -180,6 +182,7 @@ void tst_QArrayData::simpleVector() QVERIFY(!v4.isNull()); QVERIFY(!v5.isNull()); QVERIFY(!v6.isNull()); + QVERIFY(!v7.isNull()); QVERIFY(v1.isEmpty()); QVERIFY(v2.isEmpty()); @@ -187,6 +190,7 @@ void tst_QArrayData::simpleVector() QVERIFY(v4.isEmpty()); QVERIFY(v5.isEmpty()); QVERIFY(!v6.isEmpty()); + QVERIFY(!v7.isEmpty()); QCOMPARE(v1.size(), size_t(0)); QCOMPARE(v2.size(), size_t(0)); @@ -194,6 +198,7 @@ void tst_QArrayData::simpleVector() QCOMPARE(v4.size(), size_t(0)); QCOMPARE(v5.size(), size_t(0)); QCOMPARE(v6.size(), size_t(7)); + QCOMPARE(v7.size(), size_t(10)); QCOMPARE(v1.capacity(), size_t(0)); QCOMPARE(v2.capacity(), size_t(0)); @@ -201,6 +206,7 @@ void tst_QArrayData::simpleVector() QCOMPARE(v4.capacity(), size_t(0)); QCOMPARE(v5.capacity(), size_t(0)); // v6.capacity() is unspecified, for now + QVERIFY(v7.capacity() >= size_t(10)); QVERIFY(v1.isSharedWith(v2)); QVERIFY(v1.isSharedWith(v3)); @@ -211,6 +217,7 @@ void tst_QArrayData::simpleVector() QVERIFY(v1.constBegin() == v1.constEnd()); QVERIFY(v4.constBegin() == v4.constEnd()); QVERIFY(v6.constBegin() + v6.size() == v6.constEnd()); + QVERIFY(v7.constBegin() + v7.size() == v7.constEnd()); QVERIFY(v1 == v2); QVERIFY(v1 == v3); @@ -241,6 +248,16 @@ void tst_QArrayData::simpleVector() QCOMPARE(&v6[i], &v6.at(i)); } + { + int count = 0; + Q_FOREACH (int value, v7) { + QCOMPARE(value, 5); + ++count; + } + + QCOMPARE(count, 10); + } + v5 = v6; QVERIFY(v5.isSharedWith(v6)); QVERIFY(!v1.isSharedWith(v5)); @@ -397,5 +414,113 @@ void tst_QArrayData::alignment() } } +void tst_QArrayData::typedData() +{ + QStaticArrayData data = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } + }; + QCOMPARE(data.header.size, 10); + + { + QTypedArrayData *array = + static_cast *>(&data.header); + QCOMPARE(array->data(), data.data); + + int j = 0; + for (QTypedArrayData::iterator iter = array->begin(); + iter != array->end(); ++iter, ++j) + QCOMPARE(iter, data.data + j); + QCOMPARE(j, 10); + } + + { + const QTypedArrayData *array = + static_cast *>(&data.header); + + QCOMPARE(array->data(), data.data); + + int j = 0; + for (QTypedArrayData::const_iterator iter = array->begin(); + iter != array->end(); ++iter, ++j) + QCOMPARE(iter, data.data + j); + QCOMPARE(j, 10); + } + + { + QTypedArrayData *null = QTypedArrayData::sharedNull(); + QTypedArrayData *empty = QTypedArrayData::sharedEmpty(); + + QVERIFY(null != empty); + + QCOMPARE(null->size, 0); + QCOMPARE(empty->size, 0); + + QCOMPARE(null->begin(), null->end()); + QCOMPARE(empty->begin(), empty->end()); + } + + + { + Deallocator keeper(sizeof(char), + Q_ALIGNOF(QTypedArrayData::AlignmentDummy)); + QArrayData *array = QTypedArrayData::allocate(10, false); + keeper.headers.append(array); + + QVERIFY(array); + QCOMPARE(array->size, 0); + QCOMPARE(array->alloc, 10u); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(array->data(), 0, 10 * sizeof(char)); + + keeper.headers.clear(); + QTypedArrayData::deallocate(array); + + QVERIFY(true); + } + + { + Deallocator keeper(sizeof(short), + Q_ALIGNOF(QTypedArrayData::AlignmentDummy)); + QArrayData *array = QTypedArrayData::allocate(10, false); + keeper.headers.append(array); + + QVERIFY(array); + QCOMPARE(array->size, 0); + QCOMPARE(array->alloc, 10u); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(array->data(), 0, 10 * sizeof(short)); + + keeper.headers.clear(); + QTypedArrayData::deallocate(array); + + QVERIFY(true); + } + + { + Deallocator keeper(sizeof(double), + Q_ALIGNOF(QTypedArrayData::AlignmentDummy)); + QArrayData *array = QTypedArrayData::allocate(10, false); + keeper.headers.append(array); + + QVERIFY(array); + QCOMPARE(array->size, 0); + QCOMPARE(array->alloc, 10u); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(array->data(), 0, 10 * sizeof(double)); + + keeper.headers.clear(); + QTypedArrayData::deallocate(array); + + QVERIFY(true); + } +} + QTEST_APPLESS_MAIN(tst_QArrayData) #include "tst_qarraydata.moc" -- 2.7.4