diff options
-rw-r--r-- | src/corelib/tools/qarraydata.cpp | 9 | ||||
-rw-r--r-- | src/corelib/tools/qarraydata.h | 23 | ||||
-rw-r--r-- | src/corelib/tools/qarraydatapointer.h | 4 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/simplevector.h | 6 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp | 51 |
5 files changed, 89 insertions, 4 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index efed984aef..8f0a95c82c 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -56,16 +56,19 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, && !(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); diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 8eb543ee51..5a17d718c9 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -73,9 +73,18 @@ struct Q_CORE_EXPORT QArrayData 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 }; @@ -139,6 +148,20 @@ struct QTypedArrayData 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 *>( diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index 1dc02daa63..8b1d2a805c 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -114,6 +114,8 @@ public: 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 @@ -138,7 +140,7 @@ public: bool detach() { - if (d->ref.isShared()) { + if (!d->isMutable() || d->ref.isShared()) { Data *copy = clone(d->detachFlags()); QArrayDataPointer old(d); d = copy; diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index a1eb2dac48..3fa7905a39 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -274,6 +274,12 @@ public: d.detach(); } + static SimpleVector fromRawData(const T *data, size_t size, + QArrayData::AllocateOptions options = Data::Default) + { + return SimpleVector(Data::fromRawData(data, size, options)); + } + private: QArrayDataPointer<T> d; }; diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 90c865c9e7..4dba02cc70 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 arrayOps(); void setSharable_data(); void setSharable(); + void fromRawData(); }; template <class T> const T &const_(const T &t) { return t; } @@ -1131,5 +1132,55 @@ void tst_QArrayData::setSharable() 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" |