summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/text/qbytearray.cpp87
-rw-r--r--src/corelib/text/qstring.cpp48
-rw-r--r--src/corelib/tools/qarraydataops.h45
-rw-r--r--src/corelib/tools/qlist.h24
4 files changed, 104 insertions, 100 deletions
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 1b5fa8e5eb..d729667ff7 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -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);
- return insert(i, a);
+ // 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;
}
- 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);
+ if (!d->needsDetach() && points_into_range(str, d.data(), d.data() + d.size)) {
+ QVarLengthArray a(str, str + size);
+ return insert(i, a);
}
+
+ 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;
}
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 40d69c9d9c..6e7809d868 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -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))
- 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);
+ // 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;
}
- d.data()[d.size] = '\0';
+
+ if (!d->needsDetach() && points_into_range(s, d.data(), d.data() + d.size))
+ return insert(i, QStringView{QVarLengthArray(s, s + size)});
+
+ d->insert(i, s, size);
+ d.data()[d.size] = u'\0';
return *this;
}
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 7121da6660..02f52fbefe 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -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)
{
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 960bf18cac..da3a5926ea 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -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;
}