Add QArrayDataPointer::freeSpace*() functions
Added functions that tell how much free space is available at the beginning and at the end of the storage Updated preconditions of operations to use freeSpace* functions Also, changed casts uint(this->size) to size_t(this->size) Task-number: QTBUG-84320 Change-Id: Iad94c1060a00f62068da9d1327e332a00d4f4109 Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
This commit is contained in:
parent
0bd647fa4f
commit
4bf8e82d41
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
@ -191,16 +191,15 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
|
||||
|
||||
qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
|
||||
QArrayData *header = allocateData(allocSize, options);
|
||||
quintptr data = 0;
|
||||
void *data = nullptr;
|
||||
if (header) {
|
||||
// find where offset should point to so that data() is aligned to alignment bytes
|
||||
data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
|
||||
& ~(alignment - 1);
|
||||
data = QTypedArrayData<void>::dataStart(header, alignment);
|
||||
header->alloc = qsizetype(capacity);
|
||||
}
|
||||
|
||||
*dptr = header;
|
||||
return reinterpret_cast<void *>(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
QPair<QArrayData *, void *>
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 Intel Corporation.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
@ -235,6 +235,15 @@ struct QTypedArrayData
|
||||
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
|
||||
QArrayData::deallocate(data, sizeof(T), alignof(AlignmentDummy));
|
||||
}
|
||||
|
||||
static T *dataStart(QArrayData *data, qsizetype alignment) noexcept
|
||||
{
|
||||
// Alignment is a power of two
|
||||
Q_ASSERT(alignment >= qsizetype(alignof(QArrayData)) && !(alignment & (alignment - 1)));
|
||||
void *start = reinterpret_cast<void *>(
|
||||
(quintptr(data) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1));
|
||||
return static_cast<T *>(start);
|
||||
}
|
||||
};
|
||||
|
||||
namespace QtPrivate {
|
||||
|
@ -233,11 +233,11 @@ public:
|
||||
{
|
||||
Q_ASSERT(this->isMutable());
|
||||
Q_ASSERT(!this->isShared());
|
||||
Q_ASSERT(newSize > uint(this->size));
|
||||
Q_ASSERT(newSize <= this->allocatedCapacity());
|
||||
Q_ASSERT(newSize > size_t(this->size));
|
||||
Q_ASSERT(newSize - this->size <= size_t(this->freeSpaceAtEnd()));
|
||||
|
||||
::memset(static_cast<void *>(this->end()), 0, (newSize - this->size) * sizeof(T));
|
||||
this->size = int(newSize);
|
||||
this->size = qsizetype(newSize);
|
||||
}
|
||||
|
||||
template<typename iterator>
|
||||
@ -245,7 +245,7 @@ public:
|
||||
{
|
||||
Q_ASSERT(this->isMutable() || b == e);
|
||||
Q_ASSERT(!this->isShared() || b == e);
|
||||
Q_ASSERT(std::distance(b, e) >= 0 && size_t(std::distance(b, e)) <= this->allocatedCapacity() - this->size);
|
||||
Q_ASSERT(std::distance(b, e) >= 0 && qsizetype(std::distance(b, e)) <= this->freeSpaceAtEnd());
|
||||
|
||||
T *iter = this->end();
|
||||
for (; b != e; ++iter, ++b) {
|
||||
@ -272,7 +272,7 @@ public:
|
||||
Q_ASSERT(!this->isShared());
|
||||
Q_ASSERT(newSize < size_t(this->size));
|
||||
|
||||
this->size = int(newSize);
|
||||
this->size = qsizetype(newSize);
|
||||
}
|
||||
|
||||
void destroyAll() // Call from destructors, ONLY!
|
||||
@ -291,7 +291,7 @@ public:
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(b <= e);
|
||||
Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
|
||||
Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
|
||||
Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
|
||||
|
||||
::memmove(static_cast<void *>(where + (e - b)), static_cast<void *>(where),
|
||||
(static_cast<const T*>(this->end()) - where) * sizeof(T));
|
||||
@ -303,11 +303,11 @@ public:
|
||||
{
|
||||
Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(this->allocatedCapacity() - this->size >= n);
|
||||
Q_ASSERT(size_t(this->freeSpaceAtEnd()) >= n);
|
||||
|
||||
::memmove(static_cast<void *>(where + n), static_cast<void *>(where),
|
||||
(static_cast<const T*>(this->end()) - where) * sizeof(T));
|
||||
this->size += int(n); // PODs can't throw on copy
|
||||
this->size += qsizetype(n); // PODs can't throw on copy
|
||||
while (n--)
|
||||
*where++ = t;
|
||||
}
|
||||
@ -320,7 +320,7 @@ public:
|
||||
{
|
||||
Q_ASSERT(!this->isShared());
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
|
||||
Q_ASSERT(this->freeSpaceAtEnd() >= 1);
|
||||
|
||||
if (where == this->end()) {
|
||||
new (this->end()) T(std::forward<Args>(args)...);
|
||||
@ -394,13 +394,13 @@ struct QGenericArrayOps
|
||||
{
|
||||
Q_ASSERT(this->isMutable());
|
||||
Q_ASSERT(!this->isShared());
|
||||
Q_ASSERT(newSize > uint(this->size));
|
||||
Q_ASSERT(newSize <= this->allocatedCapacity());
|
||||
Q_ASSERT(newSize > size_t(this->size));
|
||||
Q_ASSERT(newSize - this->size <= size_t(this->freeSpaceAtEnd()));
|
||||
|
||||
T *const b = this->begin();
|
||||
do {
|
||||
new (b + this->size) T;
|
||||
} while (uint(++this->size) != newSize);
|
||||
} while (size_t(++this->size) != newSize);
|
||||
}
|
||||
|
||||
template<typename iterator>
|
||||
@ -408,7 +408,7 @@ struct QGenericArrayOps
|
||||
{
|
||||
Q_ASSERT(this->isMutable() || b == e);
|
||||
Q_ASSERT(!this->isShared() || b == e);
|
||||
Q_ASSERT(std::distance(b, e) >= 0 && size_t(std::distance(b, e)) <= this->allocatedCapacity() - this->size);
|
||||
Q_ASSERT(std::distance(b, e) >= 0 && qsizetype(std::distance(b, e)) <= this->freeSpaceAtEnd());
|
||||
|
||||
T *iter = this->end();
|
||||
for (; b != e; ++iter, ++b) {
|
||||
@ -425,7 +425,7 @@ struct QGenericArrayOps
|
||||
Q_ASSERT(this->isMutable() || b == e);
|
||||
Q_ASSERT(!this->isShared() || b == e);
|
||||
Q_ASSERT(b <= e);
|
||||
Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
|
||||
Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
|
||||
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
|
||||
|
||||
@ -454,7 +454,7 @@ struct QGenericArrayOps
|
||||
const T *const b = this->begin();
|
||||
do {
|
||||
(b + --this->size)->~T();
|
||||
} while (uint(this->size) != newSize);
|
||||
} while (size_t(this->size) != newSize);
|
||||
}
|
||||
|
||||
void destroyAll() // Call from destructors, ONLY
|
||||
@ -479,7 +479,7 @@ struct QGenericArrayOps
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(b <= e);
|
||||
Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
|
||||
Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
|
||||
Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
|
||||
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::template Destructor<T *> Destructor;
|
||||
|
||||
@ -527,7 +527,7 @@ struct QGenericArrayOps
|
||||
{
|
||||
Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(this->allocatedCapacity() - this->size >= n);
|
||||
Q_ASSERT(size_t(this->freeSpaceAtEnd()) >= n);
|
||||
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::template Destructor<T *> Destructor;
|
||||
|
||||
@ -578,7 +578,7 @@ struct QGenericArrayOps
|
||||
{
|
||||
Q_ASSERT(!this->isShared());
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(this->allocatedCapacity() - this->size >= 1);
|
||||
Q_ASSERT(this->freeSpaceAtEnd() >= 1);
|
||||
|
||||
createInPlace(this->end(), std::forward<Args>(args)...);
|
||||
++this->size;
|
||||
@ -651,7 +651,7 @@ struct QMovableArrayOps
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(b <= e);
|
||||
Q_ASSERT(e <= where || b > this->end() || where == this->end()); // No overlap or append
|
||||
Q_ASSERT(size_t(e - b) <= this->allocatedCapacity() - this->size);
|
||||
Q_ASSERT((e - b) <= this->freeSpaceAtEnd());
|
||||
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::Displacer ReversibleDisplace;
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
|
||||
@ -670,7 +670,7 @@ struct QMovableArrayOps
|
||||
{
|
||||
Q_ASSERT(!this->isShared() || (n == 0 && where == this->end()));
|
||||
Q_ASSERT(where >= this->begin() && where <= this->end());
|
||||
Q_ASSERT(this->allocatedCapacity() - this->size >= n);
|
||||
Q_ASSERT(size_t(this->freeSpaceAtEnd()) >= n);
|
||||
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::Displacer ReversibleDisplace;
|
||||
typedef typename QArrayExceptionSafetyPrimitives<T>::Constructor CopyConstructor;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtCore module of the Qt Toolkit.
|
||||
@ -194,6 +194,20 @@ public:
|
||||
|
||||
Data *d_ptr() noexcept { return d; }
|
||||
|
||||
qsizetype freeSpaceAtBegin() const noexcept
|
||||
{
|
||||
if (d == nullptr)
|
||||
return 0;
|
||||
return this->ptr - Data::dataStart(d, alignof(typename Data::AlignmentDummy));
|
||||
}
|
||||
|
||||
qsizetype freeSpaceAtEnd() const noexcept
|
||||
{
|
||||
if (d == nullptr)
|
||||
return 0;
|
||||
return d->constAllocatedCapacity() - freeSpaceAtBegin() - this->size;
|
||||
}
|
||||
|
||||
private:
|
||||
Q_REQUIRED_RESULT QPair<Data *, T *> clone(QArrayData::ArrayOptions options) const
|
||||
{
|
||||
|
@ -76,6 +76,8 @@ private slots:
|
||||
void variadicLiterals();
|
||||
void rValueReferences();
|
||||
void grow();
|
||||
void freeSpace_data();
|
||||
void freeSpace();
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
void exceptionSafetyPrimitives_constructor();
|
||||
void exceptionSafetyPrimitives_destructor();
|
||||
@ -1814,6 +1816,43 @@ void tst_QArrayData::grow()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QArrayData::freeSpace_data()
|
||||
{
|
||||
QTest::addColumn<QArrayData::ArrayOptions>("allocationOptions");
|
||||
QTest::addColumn<size_t>("n");
|
||||
|
||||
for (const size_t n : {1, 3, 5, 7, 16, 25}) {
|
||||
QString suffix = QString::number(n) + QLatin1String("-elements");
|
||||
QTest::newRow(qPrintable(QLatin1String("default-alloc-") + suffix))
|
||||
<< QArrayData::ArrayOptions(QArrayData::DefaultAllocationFlags) << n;
|
||||
QTest::newRow(qPrintable(QLatin1String("grows-forward-") + suffix))
|
||||
<< QArrayData::ArrayOptions(QArrayData::GrowsForward) << n;
|
||||
QTest::newRow(qPrintable(QLatin1String("grows-bidirectional-") + suffix))
|
||||
<< QArrayData::ArrayOptions(QArrayData::GrowsForward | QArrayData::GrowsBackwards) << n;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QArrayData::freeSpace()
|
||||
{
|
||||
QFETCH(QArrayData::ArrayOptions, allocationOptions);
|
||||
QFETCH(size_t, n);
|
||||
const auto testFreeSpace = [] (auto dummy, auto options, size_t n) {
|
||||
using Type = std::decay_t<decltype(dummy)>;
|
||||
using Data = QTypedArrayData<Type>;
|
||||
using DataPointer = QArrayDataPointer<Type>;
|
||||
Q_UNUSED(dummy);
|
||||
DataPointer ptr(Data::allocate(n, options));
|
||||
const auto alloc = qsizetype(ptr.constAllocatedCapacity());
|
||||
QVERIFY(size_t(alloc) >= n);
|
||||
QCOMPARE(ptr.freeSpaceAtBegin() + ptr.freeSpaceAtEnd(), alloc);
|
||||
};
|
||||
RUN_TEST_FUNC(testFreeSpace, char(0), allocationOptions, n);
|
||||
RUN_TEST_FUNC(testFreeSpace, char16_t(0), allocationOptions, n);
|
||||
RUN_TEST_FUNC(testFreeSpace, int(0), allocationOptions, n);
|
||||
RUN_TEST_FUNC(testFreeSpace, QString(), allocationOptions, n);
|
||||
RUN_TEST_FUNC(testFreeSpace, CountedObject(), allocationOptions, n);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_EXCEPTIONS
|
||||
struct ThrowingTypeWatcher
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user