&& !(alignment & (alignment - 1)));
// Don't allocate empty headers
- if (!capacity)
+ if (!(options & RawData) && !capacity)
return !(options & Unsharable)
? const_cast<QArrayData *>(&qt_array_empty)
: const_cast<QArrayData *>(&qt_array_unsharable_empty);
+ size_t allocSize = sizeof(QArrayData) + objectSize * capacity;
+
// Allocate extra (alignment - Q_ALIGNOF(QArrayData)) padding bytes so we
// can properly align the data array. This assumes malloc is able to
// provide appropriate alignment for the header -- as it should!
- size_t allocSize = sizeof(QArrayData) + objectSize * capacity
- + (alignment - Q_ALIGNOF(QArrayData));
+ // Padding is skipped when allocating a header for RawData.
+ if (!(options & RawData))
+ allocSize += (alignment - Q_ALIGNOF(QArrayData));
QArrayData *header = static_cast<QArrayData *>(qMalloc(allocSize));
Q_CHECK_PTR(header);
return reinterpret_cast<const char *>(this) + offset;
}
+ // This refers to array data mutability, not "header data" represented by
+ // data members in QArrayData. Shared data (array and header) must still
+ // follow COW principles.
+ bool isMutable() const
+ {
+ return alloc != 0;
+ }
+
enum AllocateOption {
CapacityReserved = 0x1,
Unsharable = 0x2,
+ RawData = 0x4,
Default = 0
};
QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy));
}
+ static QTypedArrayData *fromRawData(const T *data, size_t n,
+ AllocateOptions options = Default)
+ {
+ QTypedArrayData *result = allocate(0, options | RawData);
+ if (result) {
+ Q_ASSERT(!result->ref.isShared()); // No shared empty, please!
+
+ result->offset = reinterpret_cast<const char *>(data)
+ - reinterpret_cast<const char *>(result);
+ result->size = n;
+ }
+ return result;
+ }
+
static QTypedArrayData *sharedNull()
{
return static_cast<QTypedArrayData *>(
void setSharable(bool sharable)
{
+ // Can't call setSharable on static read-only data, like shared_null
+ // and the internal shared-empties.
if (d->alloc == 0 && d->size == 0) {
d = Data::allocate(0, sharable
? QArrayData::Default
bool detach()
{
- if (d->ref.isShared()) {
+ if (!d->isMutable() || d->ref.isShared()) {
Data *copy = clone(d->detachFlags());
QArrayDataPointer old(d);
d = copy;
void arrayOps();
void setSharable_data();
void setSharable();
+ void fromRawData();
};
template <class T> const T &const_(const T &t) { return t; }
QVERIFY(array->ref.isSharable());
}
+void tst_QArrayData::fromRawData()
+{
+ static const int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ {
+ // Default: Immutable, sharable
+ SimpleVector<int> raw = SimpleVector<int>::fromRawData(array,
+ sizeof(array)/sizeof(array[0]), QArrayData::Default);
+
+ QCOMPARE(raw.size(), size_t(11));
+ QCOMPARE(raw.constBegin(), array);
+ QCOMPARE(raw.constEnd(), array + sizeof(array)/sizeof(array[0]));
+
+ QVERIFY(!raw.isShared());
+ QVERIFY(SimpleVector<int>(raw).isSharedWith(raw));
+ QVERIFY(!raw.isShared());
+
+ // Detach
+ QCOMPARE(raw.back(), 11);
+ QVERIFY(raw.constBegin() != array);
+ }
+
+ {
+ // Immutable, unsharable
+ SimpleVector<int> raw = SimpleVector<int>::fromRawData(array,
+ sizeof(array)/sizeof(array[0]), QArrayData::Unsharable);
+
+ QCOMPARE(raw.size(), size_t(11));
+ QCOMPARE(raw.constBegin(), array);
+ QCOMPARE(raw.constEnd(), array + sizeof(array)/sizeof(array[0]));
+
+ SimpleVector<int> copy(raw);
+ QVERIFY(!copy.isSharedWith(raw));
+ QVERIFY(!raw.isShared());
+
+ QCOMPARE(copy.size(), size_t(11));
+
+ for (size_t i = 0; i < 11; ++i)
+ QCOMPARE(const_(copy)[i], const_(raw)[i]);
+
+ QCOMPARE(raw.size(), size_t(11));
+ QCOMPARE(raw.constBegin(), array);
+ QCOMPARE(raw.constEnd(), array + sizeof(array)/sizeof(array[0]));
+
+ // Detach
+ QCOMPARE(raw.back(), 11);
+ QVERIFY(raw.constBegin() != array);
+ }
+}
+
QTEST_APPLESS_MAIN(tst_QArrayData)
#include "tst_qarraydata.moc"