template<class T> struct QTypedArrayData
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>
This commit is contained in:
parent
0806bc2d1b
commit
390eec325b
@ -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
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user