summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorKonstantin Ritt <ritt.ks@gmail.com>2015-11-24 10:23:23 +0400
committerKonstantin Ritt <ritt.ks@gmail.com>2016-01-21 15:20:41 +0000
commitc3850dd636ab24c251942fde63f22d8f5b3a639e (patch)
treef13da2a05f805de9d4a3ddd14c03c6112fb233b6 /src/corelib
parent7edd488a5f1d5ac2e21ce08177a0d733185e38df (diff)
QString: optimize case conversion code
Handle special case mapping of length 1 explicitly; Skip calculating of high surrogate for the same plane; Optimize branch prediction with Q_LIKELY/Q_UNLIKELY; Replace peekNext() + advance() with just next() in the caller function. Change-Id: I0d37969749bd8ca855321242e6a0e72c405c5f8d Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/tools/qstring.cpp54
1 files changed, 30 insertions, 24 deletions
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 89d9889b2f..39ec66c7f1 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -5709,37 +5709,42 @@ static QString detachAndConvertCase(T &str, QStringIterator it)
Q_ASSERT(!str.isEmpty());
QString s = qMove(str); // will copy if T is const QString
QChar *pp = s.begin() + it.index(); // will detach if necessary
- uint uc = it.nextUnchecked();
- forever {
+
+ do {
+ uint uc = it.nextUnchecked();
+
const QUnicodeTables::Properties *prop = qGetProp(uc);
signed short caseDiff = Traits::caseDiff(prop);
if (Q_UNLIKELY(Traits::caseSpecial(prop))) {
- // slow path: the string is growing
const ushort *specialCase = specialCaseMap + caseDiff;
ushort length = *specialCase++;
- 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;
-
- // 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());
- } else if (QChar::requiresSurrogates(uc)) {
- *pp++ = QChar::highSurrogate(uc + caseDiff);
+
+ if (Q_LIKELY(length == 1)) {
+ *pp++ = QChar(*specialCase);
+ } 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;
+
+ // 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());
+ }
+ } else if (Q_UNLIKELY(QChar::requiresSurrogates(uc))) {
+ // so far, case convertion never changes planes (guaranteed by the qunicodetables generator)
+ pp++;
*pp++ = QChar::lowSurrogate(uc + caseDiff);
} else {
*pp++ = QChar(uc + caseDiff);
}
+ } while (it.hasNext());
- if (!it.hasNext())
- return s;
-
- uc = it.nextUnchecked();
- }
+ return s;
}
template <typename Traits, typename T>
@@ -5752,12 +5757,13 @@ static QString convertCase(T &str)
while (e != p && e[-1].isHighSurrogate())
--e;
- const QUnicodeTables::Properties *prop;
QStringIterator it(p, e);
- for ( ; it.hasNext(); it.advanceUnchecked()) {
- prop = qGetProp(it.peekNextUnchecked());
- if (Traits::caseDiff(prop))
+ while (it.hasNext()) {
+ uint uc = it.nextUnchecked();
+ if (Traits::caseDiff(qGetProp(uc))) {
+ it.recedeUnchecked();
return detachAndConvertCase<Traits>(str, it);
+ }
}
return qMove(str);
}