template<class T> struct QTypedArrayData
authorJoão Abecasis <joao.abecasis@nokia.com>
Tue, 29 Nov 2011 16:53:57 +0000 (17:53 +0100)
committerQt by Nokia <qt-info@nokia.com>
Sun, 11 Dec 2011 11:07:13 +0000 (12:07 +0100)
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 <joao.abecasis@nokia.com>
src/corelib/tools/qarraydata.h
tests/auto/corelib/tools/qarraydata/simplevector.h
tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp

index 684f008..1312fec 100644 (file)
@@ -82,6 +82,48 @@ struct Q_CORE_EXPORT QArrayData
     static const QArrayData shared_empty;
 };
 
+template <class T>
+struct QTypedArrayData
+    : QArrayData
+{
+    typedef T *iterator;
+    typedef const T *const_iterator;
+
+    T *data() { return static_cast<T *>(QArrayData::data()); }
+    const T *data() const { return static_cast<const T *>(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<QTypedArrayData *>(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<QTypedArrayData *>(
+                const_cast<QArrayData *>(&QArrayData::shared_null));
+    }
+
+    static QTypedArrayData *sharedEmpty()
+    {
+        return static_cast<QTypedArrayData *>(
+                const_cast<QArrayData *>(&QArrayData::shared_empty));
+    }
+};
+
 template <class T, size_t N>
 struct QStaticArrayData
 {
index ad08ad5..099045d 100644 (file)
@@ -50,15 +50,15 @@ template <class T>
 struct SimpleVector
 {
 private:
-    typedef QArrayData Data;
+    typedef QTypedArrayData<T> 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<QArrayData *>(&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<T *>(d->data()); }
-    const_iterator end() const { return static_cast<T *>(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<QArrayData *>(&Data::shared_empty);
+        d = Data::sharedEmpty();
     }
 
 private:
index 7dfbd65..8bbef9b 100644 (file)
@@ -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<int> v1;
     SimpleVector<int> v2(v1);
-    SimpleVector<int> v3(&data0);
-    SimpleVector<int> v4(&data1.header);
-    SimpleVector<int> v5(&data0);
-    SimpleVector<int> v6(&data1.header);
+    SimpleVector<int> v3(static_cast<QTypedArrayData<int> *>(&data0));
+    SimpleVector<int> v4(static_cast<QTypedArrayData<int> *>(&data1.header));
+    SimpleVector<int> v5(static_cast<QTypedArrayData<int> *>(&data0));
+    SimpleVector<int> v6(static_cast<QTypedArrayData<int> *>(&data1.header));
+    SimpleVector<int> 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<int, 10> 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<int> *array =
+            static_cast<QTypedArrayData<int> *>(&data.header);
+        QCOMPARE(array->data(), data.data);
+
+        int j = 0;
+        for (QTypedArrayData<int>::iterator iter = array->begin();
+                iter != array->end(); ++iter, ++j)
+            QCOMPARE(iter, data.data + j);
+        QCOMPARE(j, 10);
+    }
+
+    {
+        const QTypedArrayData<int> *array =
+            static_cast<const QTypedArrayData<int> *>(&data.header);
+
+        QCOMPARE(array->data(), data.data);
+
+        int j = 0;
+        for (QTypedArrayData<int>::const_iterator iter = array->begin();
+                iter != array->end(); ++iter, ++j)
+            QCOMPARE(iter, data.data + j);
+        QCOMPARE(j, 10);
+    }
+
+    {
+        QTypedArrayData<int> *null = QTypedArrayData<int>::sharedNull();
+        QTypedArrayData<int> *empty = QTypedArrayData<int>::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<char>::AlignmentDummy));
+        QArrayData *array = QTypedArrayData<char>::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<short>::deallocate(array);
+
+        QVERIFY(true);
+    }
+
+    {
+        Deallocator keeper(sizeof(short),
+                Q_ALIGNOF(QTypedArrayData<short>::AlignmentDummy));
+        QArrayData *array = QTypedArrayData<short>::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<short>::deallocate(array);
+
+        QVERIFY(true);
+    }
+
+    {
+        Deallocator keeper(sizeof(double),
+                Q_ALIGNOF(QTypedArrayData<double>::AlignmentDummy));
+        QArrayData *array = QTypedArrayData<double>::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<double>::deallocate(array);
+
+        QVERIFY(true);
+    }
+}
+
 QTEST_APPLESS_MAIN(tst_QArrayData)
 #include "tst_qarraydata.moc"