QString: use QVLA instead of built-in array

This simplifies the code as a QVLA's size isn't limited to 1024.
Also it allows the code to allocate a big enough buffer to hold the
result, i.e. no reallocations.

insert_helper() takes care of storing a copy of "after" if it points
into "this" string; and "before" pointing into "this" isn't an issue
since we collected the indices before starting the replacement.

Change-Id: I612948187226439349118e65e9525ded2b387da0
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
bb10
Ahmad Samir 2022-11-27 21:18:37 +02:00
parent 6b89883f6a
commit 9532339788
1 changed files with 25 additions and 65 deletions

View File

@ -3677,49 +3677,21 @@ QString &QString::replace(const QChar *before, qsizetype blen,
return replace(*before, *after, cs);
QStringMatcher matcher(before, blen, cs);
QChar *beforeBuffer = nullptr, *afterBuffer = nullptr;
qsizetype index = 0;
while (1) {
size_t indices[1024];
size_t pos = 0;
while (pos < 1024) {
index = matcher.indexIn(*this, index);
if (index == -1)
break;
indices[pos++] = index;
if (blen) // Step over before:
index += blen;
else // Only count one instance of empty between any two characters:
index++;
}
if (!pos) // Nothing to replace
break;
if (Q_UNLIKELY(index != -1)) {
/*
We're about to change data, that before and after might point
into, and we'll need that data for our next batch of indices.
*/
if (!afterBuffer && QtPrivate::q_points_into_range(after, *this))
after = afterBuffer = textCopy(after, alen);
if (!beforeBuffer && QtPrivate::q_points_into_range(before, *this)) {
beforeBuffer = textCopy(before, blen);
matcher = QStringMatcher(beforeBuffer, blen, cs);
}
}
replace_helper(*this, indices, pos, blen, after, alen);
if (Q_LIKELY(index == -1)) // Nothing left to replace
break;
// The call to replace_helper just moved what index points at:
index += pos*(alen-blen);
QVarLengthArray<size_t> indices;
while ((index = matcher.indexIn(*this, index)) != -1) {
indices.push_back(index);
if (blen) // Step over before:
index += blen;
else // Only count one instance of empty between any two characters:
index++;
}
::free(afterBuffer);
::free(beforeBuffer);
if (indices.isEmpty())
return *this;
replace_helper(*this, indices.data(), indices.size(), blen, after, alen);
return *this;
}
@ -3741,35 +3713,23 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
if (size() == 0)
return *this;
char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
const char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
qsizetype index = 0;
while (1) {
size_t indices[1024];
size_t pos = 0;
if (cs == Qt::CaseSensitive) {
while (pos < 1024 && index < size()) {
if (d.data()[index] == cc)
indices[pos++] = index;
index++;
}
} else {
while (pos < 1024 && index < size()) {
if (QChar::toCaseFolded(d.data()[index]) == cc)
indices[pos++] = index;
index++;
}
}
if (!pos) // Nothing to replace
break;
replace_helper(*this, indices, pos, 1, after.constData(), after.size());
if (Q_LIKELY(index == size())) // Nothing left to replace
break;
// The call to replace_helper just moved what index points at:
index += pos*(after.size() - 1);
QVarLengthArray<size_t> indices;
if (cs == Qt::CaseSensitive) {
for (qsizetype i = 0; i < d.size; ++i)
if (d.data()[i] == cc)
indices.push_back(i);
} else {
for (qsizetype i = 0; i < d.size; ++i)
if (QChar::toCaseFolded(d.data()[i]) == cc)
indices.push_back(i);
}
if (indices.isEmpty())
return *this;
replace_helper(*this, indices.data(), indices.size(), 1, after.constData(), after.size());
return *this;
}