summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qarraydata.cpp11
-rw-r--r--src/corelib/tools/qarraydata.h7
-rw-r--r--tests/auto/corelib/tools/qarraydata/simplevector.h6
-rw-r--r--tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp34
4 files changed, 49 insertions, 9 deletions
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 5ed3ce015f..8498d0e4d5 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include <QtCore/qarraydata.h>
+#include <QtCore/private/qtools_p.h>
#include <stdlib.h>
@@ -63,14 +64,20 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
? const_cast<QArrayData *>(&qt_array_empty)
: const_cast<QArrayData *>(&qt_array_unsharable_empty);
- size_t allocSize = sizeof(QArrayData) + objectSize * capacity;
+ size_t headerSize = sizeof(QArrayData);
// 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!
// Padding is skipped when allocating a header for RawData.
if (!(options & RawData))
- allocSize += (alignment - Q_ALIGNOF(QArrayData));
+ headerSize += (alignment - Q_ALIGNOF(QArrayData));
+
+ // Allocate additional space if array is growing
+ if (options & Grow)
+ capacity = qAllocMore(objectSize * capacity, headerSize) / objectSize;
+
+ size_t allocSize = headerSize + objectSize * capacity;
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
if (header) {
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index da2058dccf..351a75aade 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -81,9 +81,10 @@ struct Q_CORE_EXPORT QArrayData
}
enum AllocationOption {
- CapacityReserved = 0x1,
- Unsharable = 0x2,
- RawData = 0x4,
+ CapacityReserved = 0x1,
+ Unsharable = 0x2,
+ RawData = 0x4,
+ Grow = 0x8,
Default = 0
};
diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h
index a0a9b5f764..fe8108bff2 100644
--- a/tests/auto/corelib/tools/qarraydata/simplevector.h
+++ b/tests/auto/corelib/tools/qarraydata/simplevector.h
@@ -178,7 +178,7 @@ public:
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
qMax(capacity(), size() + (last - first)),
- d->detachFlags()));
+ d->detachFlags() | Data::Grow));
detached.d->copyAppend(first, last);
detached.d->copyAppend(begin, begin + d->size);
@@ -199,7 +199,7 @@ public:
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
qMax(capacity(), size() + (last - first)),
- d->detachFlags()));
+ d->detachFlags() | Data::Grow));
if (d->size) {
const T *const begin = constBegin();
@@ -239,7 +239,7 @@ public:
|| capacity() - size() < size_t(last - first)) {
SimpleVector detached(Data::allocate(
qMax(capacity(), size() + (last - first)),
- d->detachFlags()));
+ d->detachFlags() | Data::Grow));
if (position)
detached.d->copyAppend(begin, where);
diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
index 36bf7516a9..f3f1daba0f 100644
--- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
+++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
@@ -87,6 +87,7 @@ private slots:
void literals();
void variadicLiterals();
void rValueReferences();
+ void grow();
};
template <class T> const T &const_(const T &t) { return t; }
@@ -651,6 +652,7 @@ void tst_QArrayData::allocate_data()
QArrayData::CapacityReserved | QArrayData::Unsharable, true, false,
unsharable_empty },
{ "Unsharable", QArrayData::Unsharable, false, false, unsharable_empty },
+ { "Grow", QArrayData::Grow, false, true, shared_empty }
};
for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i)
@@ -690,7 +692,10 @@ void tst_QArrayData::allocate()
keeper.headers.append(data);
QCOMPARE(data->size, 0);
- QVERIFY(data->alloc >= uint(capacity));
+ if (allocateOptions & QArrayData::Grow)
+ QVERIFY(data->alloc > uint(capacity));
+ else
+ QCOMPARE(data->alloc, uint(capacity));
QCOMPARE(data->capacityReserved, uint(isCapacityReserved));
QCOMPARE(data->ref.isSharable(), isSharable);
@@ -1385,5 +1390,32 @@ void tst_QArrayData::rValueReferences()
#endif
}
+void tst_QArrayData::grow()
+{
+ SimpleVector<int> vector;
+
+ QCOMPARE(vector.size(), size_t(0));
+
+ size_t previousCapacity = vector.capacity();
+ size_t allocations = 0;
+ for (size_t i = 1; i <= (1 << 20); ++i) {
+ int source[1] = { i };
+ vector.append(source, source + 1);
+ QCOMPARE(vector.size(), i);
+ if (vector.capacity() != previousCapacity) {
+ previousCapacity = vector.capacity();
+ ++allocations;
+ }
+ }
+ QCOMPARE(vector.size(), size_t(1 << 20));
+
+ // QArrayData::Grow prevents excessive allocations on a growing container
+ QVERIFY(allocations > 20 / 2);
+ QVERIFY(allocations < 20 * 2);
+
+ for (size_t i = 0; i < (1 << 20); ++i)
+ QCOMPARE(const_(vector).at(i), int(i + 1));
+}
+
QTEST_APPLESS_MAIN(tst_QArrayData)
#include "tst_qarraydata.moc"