summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qarraydata.cpp9
-rw-r--r--src/corelib/tools/qarraydata.h23
-rw-r--r--src/corelib/tools/qarraydatapointer.h4
-rw-r--r--tests/auto/corelib/tools/qarraydata/simplevector.h6
-rw-r--r--tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp51
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"