QChar: make fullConvertCase()'s result type more usable

Move it into the function, give it an explicit size and make it
iterable and indicate to QStringView that it's a compatible container.

Change-Id: I483d9225ac73ad93f2037489f2d32473c377e8b7
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Marc Mutz 2020-05-15 00:03:25 +02:00
parent e875f45805
commit fae7a47bb3
2 changed files with 22 additions and 15 deletions

View File

@ -1590,11 +1590,21 @@ QChar::UnicodeVersion QChar::currentUnicodeVersion() noexcept
return UNICODE_DATA_VERSION;
}
using FullConvertCaseResult = std::array<char16_t, MaxSpecialCaseLength + 1>;
static FullConvertCaseResult fullConvertCase(char32_t uc, QUnicodeTables::Case which) noexcept
static auto fullConvertCase(char32_t uc, QUnicodeTables::Case which) noexcept
{
FullConvertCaseResult result = {};
auto pp = result.begin();
struct R {
char16_t chars[MaxSpecialCaseLength + 1];
qint8 sz;
// iterable
auto begin() const { return chars; }
auto end() const { return chars + sz; }
// QStringView-compatible
auto data() const { return chars; }
auto size() const { return sz; }
} result;
auto pp = result.chars;
const auto fold = qGetProp(uc)->cases[which];
const auto caseDiff = fold.diff;
@ -1609,6 +1619,7 @@ static FullConvertCaseResult fullConvertCase(char32_t uc, QUnicodeTables::Case w
for (char16_t c : QChar::fromUcs4(uc + caseDiff))
*pp++ = c;
}
result.sz = pp - result.chars;
return result;
}

View File

@ -6148,31 +6148,27 @@ static QString detachAndConvertCase(T &str, QStringIterator it, QUnicodeTables::
do {
const auto folded = fullConvertCase(it.nextUnchecked(), which);
if (Q_UNLIKELY(folded[1])) {
if (folded[0] == *pp && !folded[2]) {
if (Q_UNLIKELY(folded.size() > 1)) {
if (folded.chars[0] == *pp && folded.size() == 2) {
// special case: only second actually changed (e.g. surrogate pairs),
// avoid slow case
++pp;
*pp++ = folded[1];
*pp++ = folded.chars[1];
} else {
// slow path: the string is growing
int inpos = it.index() - 1;
int outpos = pp - s.constBegin();
int foldedSize = 2; // must be at least 2, b/c folded[1] != NUL
while (folded[foldedSize])
++foldedSize;
s.replace(outpos, 1, reinterpret_cast<const QChar *>(folded.data()), foldedSize);
pp = const_cast<QChar *>(s.constBegin()) + outpos + foldedSize;
s.replace(outpos, 1, reinterpret_cast<const QChar *>(folded.data()), folded.size());
pp = const_cast<QChar *>(s.constBegin()) + outpos + folded.size();
// do we need to adjust the input iterator too?
// if it is pointing to s's data, str is empty
if (str.isEmpty())
it = QStringIterator(s.constBegin(), inpos + foldedSize, s.constEnd());
it = QStringIterator(s.constBegin(), inpos + folded.size(), s.constEnd());
}
} else {
*pp++ = folded[0];
*pp++ = folded.chars[0];
}
} while (it.hasNext());