QArrayDataPointer: add an allocating constructor

It's by far the most common use, so having to call two things is just
cumbersome.

Change-Id: I79e700614d034281bf55fffd178f454c4e31929e
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Thiago Macieira 2023-08-22 15:40:42 -07:00
parent 793cfec941
commit 2fd0996324
7 changed files with 41 additions and 40 deletions

View File

@ -685,7 +685,7 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
if (nbytes < SingleAllocLimit) { if (nbytes < SingleAllocLimit) {
// use maximum size // use maximum size
capacity += compressBound(uLong(nbytes)); // cannot overflow (both times)! capacity += compressBound(uLong(nbytes)); // cannot overflow (both times)!
return QArrayDataPointer{QTypedArrayData<char>::allocate(capacity)}; return QArrayDataPointer<char>(capacity);
} }
// for larger buffers, assume it compresses optimally, and // for larger buffers, assume it compresses optimally, and
@ -695,7 +695,7 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
// but use a nearby power-of-two (faster) // but use a nearby power-of-two (faster)
capacity += std::max(qsizetype(compressBound(uLong(SingleAllocLimit))), capacity += std::max(qsizetype(compressBound(uLong(SingleAllocLimit))),
nbytes / MaxCompressionFactor); nbytes / MaxCompressionFactor);
return QArrayDataPointer{QTypedArrayData<char>::allocate(capacity, QArrayData::Grow)}; return QArrayDataPointer<char>(capacity, 0, QArrayData::Grow);
}(); }();
if (out.data() == nullptr) // allocation failed if (out.data() == nullptr) // allocation failed
@ -783,7 +783,7 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
qsizetype capacity = std::max(qsizetype(expectedSize), // cannot overflow! qsizetype capacity = std::max(qsizetype(expectedSize), // cannot overflow!
nbytes); nbytes);
QArrayDataPointer d(QTypedArrayData<char>::allocate(capacity, QArrayData::KeepSize)); QArrayDataPointer<char> d(capacity);
return xxflate(ZLibOp::Decompression, std::move(d), {data + HeaderSize, nbytes - HeaderSize}, return xxflate(ZLibOp::Decompression, std::move(d), {data + HeaderSize, nbytes - HeaderSize},
[] (z_stream *zs) { return inflateInit(zs); }, [] (z_stream *zs) { return inflateInit(zs); },
[] (z_stream *zs, size_t) { return inflate(zs, Z_NO_FLUSH); }, [] (z_stream *zs, size_t) { return inflate(zs, Z_NO_FLUSH); },
@ -1793,7 +1793,7 @@ QByteArray::QByteArray(const char *data, qsizetype size)
if (!size) { if (!size) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(size), size); d = DataPointer(size, size);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
memcpy(d.data(), data, size); memcpy(d.data(), data, size);
d.data()[size] = '\0'; d.data()[size] = '\0';
@ -1812,7 +1812,7 @@ QByteArray::QByteArray(qsizetype size, char ch)
if (size <= 0) { if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(size), size); d = DataPointer(size, size);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
memset(d.data(), ch, size); memset(d.data(), ch, size);
d.data()[size] = '\0'; d.data()[size] = '\0';
@ -1828,7 +1828,7 @@ QByteArray::QByteArray(qsizetype size, Qt::Initialization)
if (size <= 0) { if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(size), size); d = DataPointer(size, size);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
d.data()[size] = '\0'; d.data()[size] = '\0';
} }
@ -1917,7 +1917,7 @@ void QByteArray::reallocData(qsizetype alloc, QArrayData::AllocationOption optio
const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0; const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
if (d->needsDetach() || cannotUseReallocate) { if (d->needsDetach() || cannotUseReallocate) {
DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size)); DataPointer dd(alloc, qMin(alloc, d.size), option);
Q_CHECK_PTR(dd.data()); Q_CHECK_PTR(dd.data());
if (dd.size > 0) if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size); ::memcpy(dd.data(), d.data(), dd.size);

View File

@ -2492,7 +2492,7 @@ QString::QString(const QChar *unicode, qsizetype size)
if (!size) { if (!size) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(size), size); d = DataPointer(size, size);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
memcpy(d.data(), unicode, size * sizeof(QChar)); memcpy(d.data(), unicode, size * sizeof(QChar));
d.data()[size] = '\0'; d.data()[size] = '\0';
@ -2511,7 +2511,7 @@ QString::QString(qsizetype size, QChar ch)
if (size <= 0) { if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(size), size); d = DataPointer(size, size);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
d.data()[size] = '\0'; d.data()[size] = '\0';
char16_t *b = d.data(); char16_t *b = d.data();
@ -2532,7 +2532,7 @@ QString::QString(qsizetype size, Qt::Initialization)
if (size <= 0) { if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(size), size); d = DataPointer(size, size);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
d.data()[size] = '\0'; d.data()[size] = '\0';
} }
@ -2550,7 +2550,7 @@ QString::QString(qsizetype size, Qt::Initialization)
*/ */
QString::QString(QChar ch) QString::QString(QChar ch)
{ {
d = DataPointer(Data::allocate(1), 1); d = DataPointer(1, 1);
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
d.data()[0] = ch.unicode(); d.data()[0] = ch.unicode();
d.data()[1] = '\0'; d.data()[1] = '\0';
@ -2768,7 +2768,7 @@ void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0; const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
if (d->needsDetach() || cannotUseReallocate) { if (d->needsDetach() || cannotUseReallocate) {
DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size)); DataPointer dd(alloc, qMin(alloc, d.size), option);
Q_CHECK_PTR(dd.data()); Q_CHECK_PTR(dd.data());
if (dd.size > 0) if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar)); ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
@ -5717,7 +5717,7 @@ QString QString::fromLatin1(QByteArrayView ba)
} else if (ba.size() == 0) { } else if (ba.size() == 0) {
d = DataPointer::fromRawData(&_empty, 0); d = DataPointer::fromRawData(&_empty, 0);
} else { } else {
d = DataPointer(Data::allocate(ba.size()), ba.size()); d = DataPointer(ba.size(), ba.size());
Q_CHECK_PTR(d.data()); Q_CHECK_PTR(d.data());
d.data()[ba.size()] = '\0'; d.data()[ba.size()] = '\0';
char16_t *dst = d.data(); char16_t *dst = d.data();

View File

@ -236,7 +236,7 @@ public:
if (it == end) if (it == end)
return result; return result;
QPodArrayOps<T> other{ Data::allocate(this->size), this->size }; QPodArrayOps<T> other(this->size, this->size);
Q_CHECK_PTR(other.data()); Q_CHECK_PTR(other.data());
auto dest = other.begin(); auto dest = other.begin();
// std::uninitialized_copy will fallback to ::memcpy/memmove() // std::uninitialized_copy will fallback to ::memcpy/memmove()

View File

@ -52,6 +52,13 @@ public:
{ {
} }
Q_NODISCARD_CTOR explicit
QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
QArrayData::AllocationOption option = QArrayData::KeepSize)
: QArrayDataPointer(Data::allocate(alloc, option), n)
{
}
Q_NODISCARD_CTOR Q_NODISCARD_CTOR
static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
{ {
@ -326,11 +333,11 @@ public:
if constexpr (IsFwdIt) { if constexpr (IsFwdIt) {
const qsizetype n = std::distance(first, last); const qsizetype n = std::distance(first, last);
if (needsDetach() || n > constAllocatedCapacity()) { if (needsDetach() || n > constAllocatedCapacity()) {
QArrayDataPointer allocated(Data::allocate(detachCapacity(n))); QArrayDataPointer allocated(detachCapacity(n));
swap(allocated); swap(allocated);
} }
} else if (needsDetach()) { } else if (needsDetach()) {
QArrayDataPointer allocated(Data::allocate(allocatedCapacity())); QArrayDataPointer allocated(allocatedCapacity());
swap(allocated); swap(allocated);
// We don't want to copy data that we know we'll overwrite // We don't want to copy data that we know we'll overwrite
} }

View File

@ -276,20 +276,20 @@ public:
public: public:
QList() = default; QList() = default;
explicit QList(qsizetype size) explicit QList(qsizetype size)
: d(Data::allocate(size)) : d(size)
{ {
if (size) if (size)
d->appendInitialize(size); d->appendInitialize(size);
} }
QList(qsizetype size, parameter_type t) QList(qsizetype size, parameter_type t)
: d(Data::allocate(size)) : d(size)
{ {
if (size) if (size)
d->copyAppend(size, t); d->copyAppend(size, t);
} }
inline QList(std::initializer_list<T> args) inline QList(std::initializer_list<T> args)
: d(Data::allocate(qsizetype(args.size()))) : d(qsizetype(args.size()))
{ {
if (args.size()) if (args.size())
d->copyAppend(args.begin(), args.end()); d->copyAppend(args.begin(), args.end());
@ -308,7 +308,7 @@ public:
} else { } else {
const auto distance = std::distance(i1, i2); const auto distance = std::distance(i1, i2);
if (distance) { if (distance) {
d = DataPointer(Data::allocate(qsizetype(distance))); d = DataPointer(qsizetype(distance));
// appendIteratorRange can deal with contiguous iterators on its own, // appendIteratorRange can deal with contiguous iterators on its own,
// this is an optimization for C++17 code. // this is an optimization for C++17 code.
if constexpr (std::is_same_v<std::decay_t<InputIterator>, iterator> || if constexpr (std::is_same_v<std::decay_t<InputIterator>, iterator> ||
@ -424,7 +424,7 @@ public:
return; return;
if (d->needsDetach()) { if (d->needsDetach()) {
// must allocate memory // must allocate memory
DataPointer detached(Data::allocate(d.allocatedCapacity())); DataPointer detached(d.allocatedCapacity());
d.swap(detached); d.swap(detached);
} else { } else {
d->truncate(0); d->truncate(0);
@ -747,7 +747,7 @@ void QList<T>::reserve(qsizetype asize)
} }
} }
DataPointer detached(Data::allocate(qMax(asize, size()))); DataPointer detached(qMax(asize, size()));
detached->copyAppend(d->begin(), d->end()); detached->copyAppend(d->begin(), d->end());
if (detached.d_ptr()) if (detached.d_ptr())
detached->setFlag(Data::CapacityReserved); detached->setFlag(Data::CapacityReserved);
@ -761,7 +761,7 @@ inline void QList<T>::squeeze()
return; return;
if (d->needsDetach() || size() < capacity()) { if (d->needsDetach() || size() < capacity()) {
// must allocate memory // must allocate memory
DataPointer detached(Data::allocate(size())); DataPointer detached(size());
if (size()) { if (size()) {
if (d.needsDetach()) if (d.needsDetach())
detached->copyAppend(d.data(), d.data() + d.size); detached->copyAppend(d.data(), d.data() + d.size);
@ -890,7 +890,7 @@ inline QList<T> &QList<T>::fill(parameter_type t, qsizetype newSize)
newSize = size(); newSize = size();
if (d->needsDetach() || newSize > capacity()) { if (d->needsDetach() || newSize > capacity()) {
// must allocate memory // must allocate memory
DataPointer detached(Data::allocate(d->detachCapacity(newSize))); DataPointer detached(d->detachCapacity(newSize));
detached->copyAppend(newSize, t); detached->copyAppend(newSize, t);
d.swap(detached); d.swap(detached);
} else { } else {
@ -972,7 +972,7 @@ inline QList<T> QList<T>::mid(qsizetype pos, qsizetype len) const
} }
// Allocate memory // Allocate memory
DataPointer copied(Data::allocate(l)); DataPointer copied(l);
copied->copyAppend(data() + p, data() + p + l); copied->copyAppend(data() + p, data() + p + l);
return copied; return copied;
} }

View File

@ -28,7 +28,7 @@ public:
} }
explicit SimpleVector(size_t n, bool capacityReserved = false) explicit SimpleVector(size_t n, bool capacityReserved = false)
: d(Data::allocate(n)) : d(n)
{ {
if (n) if (n)
d->appendInitialize(n); d->appendInitialize(n);
@ -37,7 +37,7 @@ public:
} }
SimpleVector(size_t n, const T &t, bool capacityReserved = false) SimpleVector(size_t n, const T &t, bool capacityReserved = false)
: d(Data::allocate(n)) : d(n)
{ {
if (n) if (n)
d->copyAppend(n, t); d->copyAppend(n, t);
@ -46,7 +46,7 @@ public:
} }
SimpleVector(const T *begin, const T *end, bool capacityReserved = false) SimpleVector(const T *begin, const T *end, bool capacityReserved = false)
: d(Data::allocate(end - begin)) : d(end - begin)
{ {
if (end - begin) if (end - begin)
d->copyAppend(begin, end); d->copyAppend(begin, end);
@ -59,11 +59,6 @@ public:
{ {
} }
explicit SimpleVector(QPair<Data*, T*> ptr, size_t len = 0)
: d(ptr, len)
{
}
SimpleVector(const QArrayDataPointer<T> &other) SimpleVector(const QArrayDataPointer<T> &other)
: d(other) : d(other)
{ {
@ -135,7 +130,7 @@ public:
} }
} }
SimpleVector detached(Data::allocate(qMax(n, size()))); SimpleVector detached(DataPointer(qMax(n, size())));
if (size()) { if (size()) {
detached.d->copyAppend(constBegin(), constEnd()); detached.d->copyAppend(constBegin(), constEnd());
detached.d->setFlag(QArrayData::CapacityReserved); detached.d->setFlag(QArrayData::CapacityReserved);
@ -149,7 +144,7 @@ public:
return; return;
if (d->needsDetach() || newSize > capacity()) { if (d->needsDetach() || newSize > capacity()) {
SimpleVector detached(Data::allocate(d->detachCapacity(newSize))); SimpleVector detached(DataPointer(d->detachCapacity(newSize)));
if (newSize) { if (newSize) {
if (newSize < size()) { if (newSize < size()) {
const T *const begin = constBegin(); const T *const begin = constBegin();
@ -223,7 +218,7 @@ public:
const T *const end = begin + d->size; const T *const end = begin + d->size;
if (d->needsDetach()) { if (d->needsDetach()) {
SimpleVector detached(Data::allocate(d->detachCapacity(size() - (last - first)))); SimpleVector detached(DataPointer(d->detachCapacity(size() - (last - first))));
if (first != begin) if (first != begin)
detached.d->copyAppend(begin, first); detached.d->copyAppend(begin, first);
detached.d->copyAppend(last, end); detached.d->copyAppend(last, end);

View File

@ -1116,8 +1116,7 @@ void tst_QArrayData::arrayOpsExtra()
const auto cloneArrayDataPointer = [] (auto &dataPointer, size_t capacity) { const auto cloneArrayDataPointer = [] (auto &dataPointer, size_t capacity) {
using ArrayPointer = std::decay_t<decltype(dataPointer)>; using ArrayPointer = std::decay_t<decltype(dataPointer)>;
using Type = std::decay_t<typename ArrayPointer::parameter_type>; ArrayPointer copy{qsizetype(capacity)};
ArrayPointer copy(QTypedArrayData<Type>::allocate(qsizetype(capacity)));
copy->copyAppend(dataPointer.begin(), dataPointer.end()); copy->copyAppend(dataPointer.begin(), dataPointer.end());
return copy; return copy;
}; };
@ -2037,7 +2036,7 @@ void tst_QArrayData::dataPointerAllocate()
const auto createDataPointer = [] (qsizetype capacity, auto initValue) { const auto createDataPointer = [] (qsizetype capacity, auto initValue) {
using Type = std::decay_t<decltype(initValue)>; using Type = std::decay_t<decltype(initValue)>;
Q_UNUSED(initValue); Q_UNUSED(initValue);
return QArrayDataPointer<Type>(QTypedArrayData<Type>::allocate(capacity)); return QArrayDataPointer<Type>(capacity);
}; };
const auto testRealloc = [&] (qsizetype capacity, qsizetype newSize, auto initValue) { const auto testRealloc = [&] (qsizetype capacity, qsizetype newSize, auto initValue) {
@ -2453,7 +2452,7 @@ void tst_QArrayData::relocateWithExceptions()
}; };
const auto createDataPointer = [](qsizetype capacity, qsizetype initSize) { const auto createDataPointer = [](qsizetype capacity, qsizetype initSize) {
QArrayDataPointer<ThrowingType> qadp(QTypedArrayData<ThrowingType>::allocate(capacity)); QArrayDataPointer<ThrowingType> qadp(capacity);
qadp->appendInitialize(initSize); qadp->appendInitialize(initSize);
int i = 0; int i = 0;
std::generate(qadp.begin(), qadp.end(), [&i]() { return ThrowingType(i++); }); std::generate(qadp.begin(), qadp.end(), [&i]() { return ThrowingType(i++); });