summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/text/qchar.cpp23
-rw-r--r--src/corelib/text/qstring.cpp34
-rw-r--r--src/corelib/text/qunicodetables.cpp2
3 files changed, 40 insertions, 19 deletions
diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp
index 6b1bb33949..1b8cfb642e 100644
--- a/src/corelib/text/qchar.cpp
+++ b/src/corelib/text/qchar.cpp
@@ -1550,6 +1550,29 @@ 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
+{
+ FullConvertCaseResult result = {};
+ auto pp = result.begin();
+
+ const auto fold = qGetProp(uc)->cases[which];
+ const auto caseDiff = fold.diff;
+
+ if (Q_UNLIKELY(fold.special)) {
+ const auto *specialCase = specialCaseMap + caseDiff;
+ auto length = *specialCase++;
+ while (length--)
+ *pp++ = *specialCase++;
+ } else if (Q_UNLIKELY(QChar::requiresSurrogates(uc))) {
+ // so far, case convertion never changes planes (guaranteed by the qunicodetables generator)
+ *pp++ = QChar::highSurrogate(uc);
+ *pp++ = QChar::lowSurrogate(uc + caseDiff);
+ } else {
+ *pp++ = uc + caseDiff;
+ }
+ return result;
+}
template <typename T>
Q_DECL_CONST_FUNCTION static inline T convertCase_helper(T uc, QUnicodeTables::Case which) noexcept
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 49ddb9279b..d8c74aac62 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -6533,36 +6533,32 @@ static QString detachAndConvertCase(T &str, QStringIterator it, QUnicodeTables::
QChar *pp = s.begin() + it.index(); // will detach if necessary
do {
- auto uc = it.nextUnchecked();
-
- const auto fold = qGetProp(uc)->cases[which];
- signed short caseDiff = fold.diff;
-
- if (Q_UNLIKELY(fold.special)) {
- const ushort *specialCase = specialCaseMap + caseDiff;
- ushort length = *specialCase++;
-
- if (Q_LIKELY(length == 1)) {
- *pp++ = QChar(*specialCase);
+ const auto folded = fullConvertCase(it.nextUnchecked(), which);
+ if (Q_UNLIKELY(folded[1])) {
+ if (folded[0] == *pp && !folded[2]) {
+ // special case: only second actually changed (e.g. surrogate pairs),
+ // avoid slow case
+ ++pp;
+ *pp++ = folded[1];
} else {
// slow path: the string is growing
int inpos = it.index() - 1;
int outpos = pp - s.constBegin();
- s.replace(outpos, 1, reinterpret_cast<const QChar *>(specialCase), length);
- pp = const_cast<QChar *>(s.constBegin()) + outpos + length;
+ 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;
// 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 + length, s.constEnd());
+ it = QStringIterator(s.constBegin(), inpos + foldedSize, s.constEnd());
}
- } else if (Q_UNLIKELY(QChar::requiresSurrogates(uc))) {
- // so far, case convertion never changes planes (guaranteed by the qunicodetables generator)
- pp++;
- *pp++ = QChar(QChar::lowSurrogate(uc + caseDiff));
} else {
- *pp++ = QChar(uc + caseDiff);
+ *pp++ = folded[0];
}
} while (it.hasNext());
diff --git a/src/corelib/text/qunicodetables.cpp b/src/corelib/text/qunicodetables.cpp
index e6f6487126..865f93ba52 100644
--- a/src/corelib/text/qunicodetables.cpp
+++ b/src/corelib/text/qunicodetables.cpp
@@ -9946,6 +9946,8 @@ static const unsigned short specialCaseMap[] = {
0x1, 0xa64b
};
+const unsigned int MaxSpecialCaseLength = 3;
+
static const unsigned short uc_decomposition_trie[] = {
// 0 - 0x3400