Move insert() operation into QArrayDataOps
This allows us to unify and simplify the code base between QList, QString and QByteArray. Change-Id: Idc8f360d78f508a68f38eb3ef0ed6e5d37f90574 Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
b76fbb48fb
commit
9ee50a14b7
@ -1922,39 +1922,34 @@ QByteArray& QByteArray::append(char ch)
|
||||
QByteArray &QByteArray::insert(qsizetype i, QByteArrayView data)
|
||||
{
|
||||
const char *str = data.data();
|
||||
qsizetype len = data.size();
|
||||
if (i < 0 || str == nullptr || len <= 0)
|
||||
qsizetype size = data.size();
|
||||
if (i < 0 || size <= 0)
|
||||
return *this;
|
||||
|
||||
if (points_into_range(str, d.data(), d.data() + d.size)) {
|
||||
QVarLengthArray a(str, str + len);
|
||||
// handle this specially, as QArrayDataOps::insert() doesn't handle out of
|
||||
// bounds positions
|
||||
if (i >= d->size) {
|
||||
// In case when data points into the range or is == *this, we need to
|
||||
// defer a call to free() so that it comes after we copied the data from
|
||||
// the old memory:
|
||||
DataPointer detached{}; // construction is free
|
||||
if (d->needsDetach() || i + size - d->size > d.freeSpaceAtEnd()) {
|
||||
detached = DataPointer::allocateGrow(d, i + size - d->size, Data::AllocateAtEnd);
|
||||
detached->copyAppend(d.constBegin(), d.constEnd());
|
||||
d.swap(detached);
|
||||
}
|
||||
d->copyAppend(i - d->size, ' ');
|
||||
d->copyAppend(str, str + size);
|
||||
d.data()[d.size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!d->needsDetach() && points_into_range(str, d.data(), d.data() + d.size)) {
|
||||
QVarLengthArray a(str, str + size);
|
||||
return insert(i, a);
|
||||
}
|
||||
|
||||
const auto oldSize = this->size();
|
||||
qsizetype sizeToGrow = len;
|
||||
if (i > oldSize)
|
||||
sizeToGrow += i - oldSize;
|
||||
|
||||
if (d->needsDetach() || (sizeToGrow > d.freeSpaceAtBegin() && sizeToGrow > d.freeSpaceAtEnd())) {
|
||||
QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd;
|
||||
if (oldSize != 0 && i <= (oldSize >> 1))
|
||||
pos = QArrayData::AllocateAtBeginning;
|
||||
|
||||
DataPointer detached(DataPointer::allocateGrow(d, sizeToGrow, pos));
|
||||
auto where = d.constBegin() + qMin(i, d->size);
|
||||
detached->copyAppend(d.constBegin(), where);
|
||||
if (i > oldSize)
|
||||
detached->copyAppend(i - oldSize, u' ');
|
||||
detached->copyAppend(str, str + len);
|
||||
detached->copyAppend(where, d.constEnd());
|
||||
d.swap(detached);
|
||||
} else {
|
||||
if (i > oldSize) // set spaces in the uninitialized gap
|
||||
d->copyAppend(i - oldSize, ' ');
|
||||
|
||||
d->insert(d.begin() + i, str, str + len);
|
||||
}
|
||||
d->insert(i, str, size);
|
||||
d.data()[d.size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
@ -1995,30 +1990,20 @@ QByteArray &QByteArray::insert(qsizetype i, qsizetype count, char ch)
|
||||
if (i < 0 || count <= 0)
|
||||
return *this;
|
||||
|
||||
const auto oldSize = this->size();
|
||||
qsizetype sizeToGrow = count;
|
||||
if (i > oldSize)
|
||||
sizeToGrow += i - oldSize;
|
||||
|
||||
if (d->needsDetach() || (sizeToGrow > d.freeSpaceAtBegin() && sizeToGrow > d.freeSpaceAtEnd())) {
|
||||
QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd;
|
||||
if (oldSize != 0 && i <= (oldSize >> 1))
|
||||
pos = QArrayData::AllocateAtBeginning;
|
||||
|
||||
DataPointer detached(DataPointer::allocateGrow(d, sizeToGrow, pos));
|
||||
auto where = d.constBegin() + qMin(i, d->size);
|
||||
detached->copyAppend(d.constBegin(), where);
|
||||
if (i > oldSize)
|
||||
detached->copyAppend(i - oldSize, ' ');
|
||||
detached->copyAppend(count, ch);
|
||||
detached->copyAppend(where, d.constEnd());
|
||||
d.swap(detached);
|
||||
} else {
|
||||
if (i > oldSize) // set spaces in the uninitialized gap
|
||||
d->copyAppend(i - oldSize, u' ');
|
||||
|
||||
d->insert(d.begin() + i, count, ch);
|
||||
if (i >= d->size) {
|
||||
// handle this specially, as QArrayDataOps::insert() doesn't handle out of bounds positions
|
||||
if (d->needsDetach() || i + count - d->size > d.freeSpaceAtEnd()) {
|
||||
DataPointer detached(DataPointer::allocateGrow(d, i + count - d->size, Data::AllocateAtEnd));
|
||||
detached->copyAppend(d.constBegin(), d.constEnd());
|
||||
d.swap(detached);
|
||||
}
|
||||
d->copyAppend(i - d->size, ' ');
|
||||
d->copyAppend(count, ch);
|
||||
d.data()[d.size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
d->insert(i, count, ch);
|
||||
d.data()[d.size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
@ -2728,34 +2728,30 @@ QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size)
|
||||
return *this;
|
||||
|
||||
const auto s = reinterpret_cast<const char16_t *>(unicode);
|
||||
if (points_into_range(s, d.data(), d.data() + d.size))
|
||||
|
||||
// handle this specially, as QArrayDataOps::insert() doesn't handle out of
|
||||
// bounds positions
|
||||
if (i >= d->size) {
|
||||
// In case when data points into the range or is == *this, we need to
|
||||
// defer a call to free() so that it comes after we copied the data from
|
||||
// the old memory:
|
||||
DataPointer detached{}; // construction is free
|
||||
if (d->needsDetach() || i + size - d->size > d.freeSpaceAtEnd()) {
|
||||
detached = DataPointer::allocateGrow(d, i + size - d->size, Data::AllocateAtEnd);
|
||||
detached->copyAppend(d.constBegin(), d.constEnd());
|
||||
d.swap(detached);
|
||||
}
|
||||
d->copyAppend(i - d->size, u' ');
|
||||
d->copyAppend(s, s + size);
|
||||
d.data()[d.size] = u'\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!d->needsDetach() && points_into_range(s, d.data(), d.data() + d.size))
|
||||
return insert(i, QStringView{QVarLengthArray(s, s + size)});
|
||||
|
||||
const auto oldSize = this->size();
|
||||
qsizetype sizeToGrow = size;
|
||||
if (i > oldSize)
|
||||
sizeToGrow += i - oldSize;
|
||||
|
||||
if (d->needsDetach() || (sizeToGrow > d.freeSpaceAtBegin() && sizeToGrow > d.freeSpaceAtEnd())) {
|
||||
QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd;
|
||||
if (oldSize != 0 && i <= (oldSize >> 1))
|
||||
pos = QArrayData::AllocateAtBeginning;
|
||||
|
||||
DataPointer detached(DataPointer::allocateGrow(d, sizeToGrow, pos));
|
||||
auto where = d.constBegin() + qMin(i, d->size);
|
||||
detached->copyAppend(d.constBegin(), where);
|
||||
if (i > oldSize)
|
||||
detached->copyAppend(i - oldSize, u' ');
|
||||
detached->copyAppend(s, s + size);
|
||||
detached->copyAppend(where, d.constEnd());
|
||||
d.swap(detached);
|
||||
} else {
|
||||
if (i > oldSize) // set spaces in the uninitialized gap
|
||||
d->copyAppend(i - oldSize, u' ');
|
||||
|
||||
d->insert(d.begin() + i, s, s + size);
|
||||
}
|
||||
d.data()[d.size] = '\0';
|
||||
d->insert(i, s, size);
|
||||
d.data()[d.size] = u'\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1024,6 +1024,7 @@ struct QCommonArrayOps : QArrayOpsSelector<T>::Type
|
||||
{
|
||||
using Base = typename QArrayOpsSelector<T>::Type;
|
||||
using Data = QTypedArrayData<T>;
|
||||
using DataPointer = QArrayDataPointer<T>;
|
||||
using parameter_type = typename Base::parameter_type;
|
||||
using iterator = typename Base::iterator;
|
||||
using const_iterator = typename Base::const_iterator;
|
||||
@ -1216,6 +1217,50 @@ public:
|
||||
Base::insert(GrowsForwardTag{}, where, qsizetype(n) - beginSize, t);
|
||||
}
|
||||
|
||||
void insert(qsizetype i, qsizetype n, parameter_type t)
|
||||
{
|
||||
if (this->needsDetach() || (n > this->freeSpaceAtBegin() && n > this->freeSpaceAtEnd())) {
|
||||
typename Data::AllocationPosition pos = Data::AllocateAtEnd;
|
||||
if (this->size != 0 && i <= (this->size >> 1))
|
||||
pos = Data::AllocateAtBeginning;
|
||||
|
||||
DataPointer detached(DataPointer::allocateGrow(*this, n, pos));
|
||||
const_iterator where = this->constBegin() + i;
|
||||
detached->copyAppend(this->constBegin(), where);
|
||||
detached->copyAppend(n, t);
|
||||
detached->copyAppend(where, this->constEnd());
|
||||
this->swap(detached);
|
||||
} else {
|
||||
// we're detached and we can just move data around
|
||||
if (i == this->size && n <= this->freeSpaceAtEnd()) {
|
||||
copyAppend(n, t);
|
||||
} else {
|
||||
T copy(t);
|
||||
insert(this->begin() + i, n, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void insert(qsizetype i, const T *data, qsizetype n)
|
||||
{
|
||||
if (this->needsDetach() || (n > this->freeSpaceAtBegin() && n > this->freeSpaceAtEnd())) {
|
||||
typename Data::AllocationPosition pos = Data::AllocateAtEnd;
|
||||
if (this->size != 0 && i <= (this->size >> 1))
|
||||
pos = Data::AllocateAtBeginning;
|
||||
|
||||
DataPointer detached(DataPointer::allocateGrow(*this, n, pos));
|
||||
auto where = this->constBegin() + i;
|
||||
detached->copyAppend(this->constBegin(), where);
|
||||
detached->copyAppend(data, data + n);
|
||||
detached->copyAppend(where, this->constEnd());
|
||||
this->swap(detached);
|
||||
} else {
|
||||
insert(this->begin() + i, data, data + n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename iterator, typename ...Args>
|
||||
void emplace(iterator where, Args&&... args)
|
||||
{
|
||||
|
@ -732,29 +732,7 @@ QList<T>::insert(qsizetype i, qsizetype n, parameter_type t)
|
||||
{
|
||||
Q_ASSERT_X(size_t(i) <= size_t(d->size), "QList<T>::insert", "index out of range");
|
||||
|
||||
// we don't have a quick exit for n == 0
|
||||
// it's not worth wasting CPU cycles for that
|
||||
|
||||
if (d->needsDetach() || (n > d.freeSpaceAtBegin() && n > d.freeSpaceAtEnd())) {
|
||||
typename QArrayData::AllocationPosition pos = QArrayData::AllocateAtEnd;
|
||||
if (d.size != 0 && i <= (d.size >> 1))
|
||||
pos = QArrayData::AllocateAtBeginning;
|
||||
|
||||
DataPointer detached(DataPointer::allocateGrow(d, n, pos));
|
||||
const_iterator where = constBegin() + i;
|
||||
detached->copyAppend(constBegin(), where);
|
||||
detached->copyAppend(n, t);
|
||||
detached->copyAppend(where, constEnd());
|
||||
d.swap(detached);
|
||||
} else {
|
||||
// we're detached and we can just move data around
|
||||
if (i == size() && n <= d.freeSpaceAtEnd()) {
|
||||
d->copyAppend(n, t);
|
||||
} else {
|
||||
T copy(t);
|
||||
d->insert(d.begin() + i, n, copy);
|
||||
}
|
||||
}
|
||||
d->insert(i, n, t);
|
||||
return d.begin() + i;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user