Get rid of QArrayData::sharedNull()
Remove the last places where those got used and avoid allocations when we resize to 0. Change-Id: Ib553f4e7ce7cc24c31da15a55a86d18bdf1cc5c3 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
c01804bd1e
commit
fbce2e58e6
|
|
@ -1732,7 +1732,7 @@ QByteArray QByteArray::nulTerminated() const
|
|||
|
||||
QByteArray &QByteArray::prepend(const QByteArray &ba)
|
||||
{
|
||||
if (size() == 0 && d->isStatic() && ba.d.isMutable()) {
|
||||
if (size() == 0 && ba.d.isMutable()) {
|
||||
*this = ba;
|
||||
} else if (ba.size() != 0) {
|
||||
QByteArray tmp = *this;
|
||||
|
|
@ -1825,7 +1825,7 @@ QByteArray &QByteArray::prepend(char ch)
|
|||
|
||||
QByteArray &QByteArray::append(const QByteArray &ba)
|
||||
{
|
||||
if (size() == 0 && d->isStatic() && ba.d.isMutable()) {
|
||||
if (size() == 0 && ba.d.isMutable()) {
|
||||
*this = ba;
|
||||
} else if (ba.size() != 0) {
|
||||
if (d->needsDetach() || size() + ba.size() > capacity())
|
||||
|
|
|
|||
|
|
@ -147,25 +147,7 @@ qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t heade
|
|||
return result;
|
||||
}
|
||||
|
||||
// End of qtools_p.h implementation
|
||||
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_GCC("-Wmissing-field-initializers")
|
||||
|
||||
const QArrayData QArrayData::shared_null[2] = {
|
||||
{ Q_BASIC_ATOMIC_INITIALIZER(-1), 0, 0 }, // shared null
|
||||
/* zero initialized terminator */};
|
||||
|
||||
static const QArrayData emptyNotNullShared[2] = {
|
||||
{ Q_BASIC_ATOMIC_INITIALIZER(-1), 0, 0 }, // shared empty
|
||||
/* zero initialized terminator */};
|
||||
|
||||
QT_WARNING_POP
|
||||
|
||||
static const QArrayData &qt_array_empty = emptyNotNullShared[0];
|
||||
|
||||
static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
|
||||
uint options)
|
||||
static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize, uint options)
|
||||
{
|
||||
// Calculate the byte size
|
||||
// allocSize = objectSize * capacity + headerSize, but checked for overflow
|
||||
|
|
@ -199,9 +181,8 @@ void *QArrayData::allocate(QArrayData **dptr, size_t objectSize, size_t alignmen
|
|||
&& !(alignment & (alignment - 1)));
|
||||
|
||||
if (capacity == 0) {
|
||||
// optimization for empty headers
|
||||
*dptr = const_cast<QArrayData *>(&qt_array_empty);
|
||||
return sharedNullData();
|
||||
*dptr = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t headerSize = sizeof(QArrayData);
|
||||
|
|
|
|||
|
|
@ -77,24 +77,16 @@ struct Q_CORE_EXPORT QArrayData
|
|||
/// Returns true if sharing took place
|
||||
bool ref()
|
||||
{
|
||||
if (!isStatic())
|
||||
ref_.ref();
|
||||
ref_.ref();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns false if deallocation is necessary
|
||||
bool deref()
|
||||
{
|
||||
if (isStatic())
|
||||
return true;
|
||||
return ref_.deref();
|
||||
}
|
||||
|
||||
bool isStatic() const
|
||||
{
|
||||
return ref_.loadRelaxed() == -1;
|
||||
}
|
||||
|
||||
bool isShared() const
|
||||
{
|
||||
return ref_.loadRelaxed() != 1;
|
||||
|
|
@ -133,14 +125,6 @@ struct Q_CORE_EXPORT QArrayData
|
|||
size_t objectSize, size_t newCapacity, ArrayOptions newOptions = DefaultAllocationFlags) Q_DECL_NOTHROW;
|
||||
static void deallocate(QArrayData *data, size_t objectSize,
|
||||
size_t alignment) noexcept;
|
||||
|
||||
static const QArrayData shared_null[2];
|
||||
static QArrayData *sharedNull() noexcept { return const_cast<QArrayData*>(shared_null); }
|
||||
static void *sharedNullData()
|
||||
{
|
||||
QArrayData *const null = const_cast<QArrayData *>(&shared_null[1]);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ public:
|
|||
explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> adata, size_t n = 0)
|
||||
: d(adata.first), ptr(adata.second), size(int(n))
|
||||
{
|
||||
Q_CHECK_PTR(d);
|
||||
}
|
||||
|
||||
static QArrayDataPointer fromRawData(const T *rawData, size_t length)
|
||||
|
|
@ -183,7 +182,6 @@ public:
|
|||
void ref() noexcept { if (d) d->ref(); }
|
||||
bool deref() noexcept { return !d || d->deref(); }
|
||||
bool isMutable() const noexcept { return d; }
|
||||
bool isStatic() const noexcept { return !d; }
|
||||
bool isShared() const noexcept { return !d || d->isShared(); }
|
||||
bool isSharedWith(const QArrayDataPointer &other) const noexcept { return d && d == other.d; }
|
||||
bool needsDetach() const noexcept { return !d || d->needsDetach(); }
|
||||
|
|
@ -199,7 +197,6 @@ private:
|
|||
Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const
|
||||
{
|
||||
QPair<Data *, T *> pair = Data::allocate(detachCapacity(size), options);
|
||||
Q_CHECK_PTR(pair.first);
|
||||
QArrayDataPointer copy(pair.first, pair.second, 0);
|
||||
if (size)
|
||||
copy->copyAppend(begin(), end());
|
||||
|
|
|
|||
|
|
@ -167,8 +167,8 @@ QByteArray verifyZeroTermination(const QByteArray &ba)
|
|||
|
||||
QByteArray::DataPointer baDataPtr = const_cast<QByteArray &>(ba).data_ptr();
|
||||
|
||||
// Skip if isStatic() as those offer no guarantees
|
||||
if (baDataPtr->isStatic())
|
||||
// Skip if !isMutable() as those offer no guarantees
|
||||
if (!baDataPtr->isMutable())
|
||||
return ba;
|
||||
|
||||
int baSize = ba.size();
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ QString verifyZeroTermination(const QString &str)
|
|||
QString::DataPointer strDataPtr = const_cast<QString &>(str).data_ptr();
|
||||
|
||||
// Skip if isStatic() or fromRawData(), as those offer no guarantees
|
||||
if (strDataPtr->isStatic() || !strDataPtr->isMutable())
|
||||
if (!strDataPtr->isMutable())
|
||||
return str;
|
||||
|
||||
int strSize = str.size();
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public:
|
|||
bool isNull() const { return d.isNull(); }
|
||||
bool isEmpty() const { return this->empty(); }
|
||||
|
||||
bool isStatic() const { return d->isStatic(); }
|
||||
bool isStatic() const { return !d.isMutable(); }
|
||||
bool isShared() const { return d->isShared(); }
|
||||
bool isSharedWith(const SimpleVector &other) const { return d == other.d; }
|
||||
|
||||
|
|
|
|||
|
|
@ -33,29 +33,12 @@
|
|||
|
||||
#include "simplevector.h"
|
||||
|
||||
struct SharedNullVerifier
|
||||
{
|
||||
SharedNullVerifier()
|
||||
{
|
||||
Q_ASSERT(QArrayData::shared_null[0].isStatic());
|
||||
Q_ASSERT(QArrayData::shared_null[0].isShared());
|
||||
}
|
||||
};
|
||||
|
||||
// This is meant to verify/ensure that shared_null is not being dynamically
|
||||
// initialized and stays away from the order-of-static-initialization fiasco.
|
||||
//
|
||||
// Of course, if this was to fail, qmake and the build should have crashed and
|
||||
// burned before we ever got to this point :-)
|
||||
SharedNullVerifier globalInit;
|
||||
|
||||
class tst_QArrayData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void referenceCounting();
|
||||
void sharedNullEmpty();
|
||||
void simpleVector();
|
||||
void simpleVectorReserve_data();
|
||||
void simpleVectorReserve();
|
||||
|
|
@ -87,8 +70,6 @@ void tst_QArrayData::referenceCounting()
|
|||
|
||||
QCOMPARE(array.ref_.loadRelaxed(), 1);
|
||||
|
||||
QVERIFY(!array.isStatic());
|
||||
|
||||
QVERIFY(array.ref());
|
||||
QCOMPARE(array.ref_.loadRelaxed(), 2);
|
||||
|
||||
|
|
@ -108,37 +89,6 @@ void tst_QArrayData::referenceCounting()
|
|||
}
|
||||
}
|
||||
|
||||
void tst_QArrayData::sharedNullEmpty()
|
||||
{
|
||||
QArrayData *null = const_cast<QArrayData *>(QArrayData::shared_null);
|
||||
QArrayData *empty;
|
||||
QArrayData::allocate(&empty, 1, alignof(QArrayData), 0);
|
||||
|
||||
QVERIFY(null->isStatic());
|
||||
QVERIFY(null->isShared());
|
||||
|
||||
QVERIFY(empty->isStatic());
|
||||
QVERIFY(empty->isShared());
|
||||
|
||||
QCOMPARE(null->ref_.loadRelaxed(), -1);
|
||||
QCOMPARE(empty->ref_.loadRelaxed(), -1);
|
||||
|
||||
QCOMPARE(null->ref_.loadRelaxed(), -1);
|
||||
QCOMPARE(empty->ref_.loadRelaxed(), -1);
|
||||
|
||||
QVERIFY(null->deref());
|
||||
QVERIFY(empty->deref());
|
||||
|
||||
QCOMPARE(null->ref_.loadRelaxed(), -1);
|
||||
QCOMPARE(empty->ref_.loadRelaxed(), -1);
|
||||
|
||||
QVERIFY(null != empty);
|
||||
|
||||
QCOMPARE(null->allocatedCapacity(), size_t(0));
|
||||
|
||||
QCOMPARE(empty->allocatedCapacity(), size_t(0));
|
||||
}
|
||||
|
||||
void tst_QArrayData::simpleVector()
|
||||
{
|
||||
int data[] = { 0, 1, 2, 3, 4, 5, 6 };
|
||||
|
|
@ -479,7 +429,6 @@ void tst_QArrayData::allocate_data()
|
|||
QTest::addColumn<size_t>("alignment");
|
||||
QTest::addColumn<QArrayData::ArrayOptions>("allocateOptions");
|
||||
QTest::addColumn<bool>("isCapacityReserved");
|
||||
QTest::addColumn<const QArrayData *>("commonEmpty");
|
||||
|
||||
struct {
|
||||
char const *typeName;
|
||||
|
|
@ -491,19 +440,14 @@ void tst_QArrayData::allocate_data()
|
|||
{ "void *", sizeof(void *), alignof(void *) }
|
||||
};
|
||||
|
||||
QArrayData *shared_empty;
|
||||
(void)QArrayData::allocate(&shared_empty, 1, alignof(QArrayData), 0);
|
||||
QVERIFY(shared_empty);
|
||||
|
||||
struct {
|
||||
char const *description;
|
||||
QArrayData::ArrayOptions allocateOptions;
|
||||
bool isCapacityReserved;
|
||||
const QArrayData *commonEmpty;
|
||||
} options[] = {
|
||||
{ "Default", QArrayData::DefaultAllocationFlags, false, shared_empty },
|
||||
{ "Reserved", QArrayData::CapacityReserved, true, shared_empty },
|
||||
{ "Grow", QArrayData::GrowsForward, false, shared_empty }
|
||||
{ "Default", QArrayData::DefaultAllocationFlags, false },
|
||||
{ "Reserved", QArrayData::CapacityReserved, true },
|
||||
{ "Grow", QArrayData::GrowsForward, false }
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i)
|
||||
|
|
@ -513,8 +457,7 @@ void tst_QArrayData::allocate_data()
|
|||
+ QLatin1String(": ")
|
||||
+ QLatin1String(options[j].description)))
|
||||
<< types[i].objectSize << types[i].alignment
|
||||
<< options[j].allocateOptions << options[j].isCapacityReserved
|
||||
<< options[j].commonEmpty;
|
||||
<< options[j].allocateOptions << options[j].isCapacityReserved;
|
||||
}
|
||||
|
||||
void tst_QArrayData::allocate()
|
||||
|
|
@ -523,21 +466,15 @@ void tst_QArrayData::allocate()
|
|||
QFETCH(size_t, alignment);
|
||||
QFETCH(QArrayData::ArrayOptions, allocateOptions);
|
||||
QFETCH(bool, isCapacityReserved);
|
||||
QFETCH(const QArrayData *, commonEmpty);
|
||||
|
||||
// Minimum alignment that can be requested is that of QArrayData.
|
||||
// Typically, this alignment is sizeof(void *) and ensured by malloc.
|
||||
size_t minAlignment = qMax(alignment, alignof(QArrayData));
|
||||
|
||||
// Shared Empty
|
||||
QArrayData *empty;
|
||||
QCOMPARE((QArrayData::allocate(&empty, objectSize, minAlignment, 0,
|
||||
QArrayData::ArrayOptions(allocateOptions)), empty), commonEmpty);
|
||||
|
||||
Deallocator keeper(objectSize, minAlignment);
|
||||
keeper.headers.reserve(1024);
|
||||
|
||||
for (int capacity = 1; capacity <= 1024; capacity <<= 1) {
|
||||
for (qsizetype capacity = 1; capacity <= 1024; capacity <<= 1) {
|
||||
QArrayData *data;
|
||||
void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment,
|
||||
capacity, QArrayData::ArrayOptions(allocateOptions));
|
||||
|
|
@ -545,9 +482,9 @@ void tst_QArrayData::allocate()
|
|||
keeper.headers.append(data);
|
||||
|
||||
if (allocateOptions & QArrayData::GrowsForward)
|
||||
QVERIFY(data->allocatedCapacity() > uint(capacity));
|
||||
QVERIFY(data->allocatedCapacity() > capacity);
|
||||
else
|
||||
QCOMPARE(data->allocatedCapacity(), size_t(capacity));
|
||||
QCOMPARE(data->allocatedCapacity(), capacity);
|
||||
QCOMPARE(bool(data->flags & QArrayData::CapacityReserved), isCapacityReserved);
|
||||
|
||||
// Check that the allocated array can be used. Best tested with a
|
||||
|
|
@ -587,9 +524,9 @@ void tst_QArrayData::reallocate()
|
|||
keeper.headers.append(data);
|
||||
|
||||
if (allocateOptions & QArrayData::GrowsForward)
|
||||
QVERIFY(data->allocatedCapacity() > size_t(newCapacity));
|
||||
QVERIFY(data->allocatedCapacity() > newCapacity);
|
||||
else
|
||||
QCOMPARE(data->allocatedCapacity(), size_t(newCapacity));
|
||||
QCOMPARE(data->allocatedCapacity(), newCapacity);
|
||||
QCOMPARE(!(data->flags & QArrayData::CapacityReserved), !isCapacityReserved);
|
||||
|
||||
for (int i = 0; i < capacity; ++i)
|
||||
|
|
@ -658,7 +595,7 @@ void tst_QArrayData::typedData()
|
|||
keeper.headers.append(array);
|
||||
|
||||
QVERIFY(array);
|
||||
QCOMPARE(array->allocatedCapacity(), size_t(10));
|
||||
QCOMPARE(array->allocatedCapacity(), qsizetype(10));
|
||||
|
||||
// Check that the allocated array can be used. Best tested with a
|
||||
// memory checker, such as valgrind, running.
|
||||
|
|
@ -678,7 +615,7 @@ void tst_QArrayData::typedData()
|
|||
keeper.headers.append(array);
|
||||
|
||||
QVERIFY(array);
|
||||
QCOMPARE(array->allocatedCapacity(), size_t(10));
|
||||
QCOMPARE(array->allocatedCapacity(), qsizetype(10));
|
||||
|
||||
// Check that the allocated array can be used. Best tested with a
|
||||
// memory checker, such as valgrind, running.
|
||||
|
|
@ -698,7 +635,7 @@ void tst_QArrayData::typedData()
|
|||
keeper.headers.append(array);
|
||||
|
||||
QVERIFY(array);
|
||||
QCOMPARE(array->allocatedCapacity(), size_t(10));
|
||||
QCOMPARE(array->allocatedCapacity(), qsizetype(10));
|
||||
|
||||
// Check that the allocated array can be used. Best tested with a
|
||||
// memory checker, such as valgrind, running.
|
||||
|
|
|
|||
Loading…
Reference in New Issue