[2/2] Implement Unicode Normalization Form Quick Check (NF QC)

Use QuickCheck data from DerivedNormalizationProps.txt to check
if the input text is already in the desired Normalization Form.
\sa http://www.unicode.org/reports/tr15/#Detecting_Normalization_Forms

Using NF QC makes a significant boost to most operations that rely on
normalized input data, i.e. file path conversions on Mac, where "native"
form is a decomposed Unicode string.

Change-Id: I292a9da479c6beed730528fc7000c45bf1befc34
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Konstantin Ritt 2013-08-13 05:02:34 +03:00 committed by The Qt Project
parent 252bad7c58
commit 2e0a4b13ad
4 changed files with 6496 additions and 6210 deletions

View File

@ -1884,4 +1884,65 @@ static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, in
}
}
// returns true if the text is in a desired Normalization Form already; false otherwise.
// sets lastStable to the position of the last stable code point
static bool normalizationQuickCheckHelper(QString *str, QString::NormalizationForm mode, int from, int *lastStable)
{
Q_STATIC_ASSERT(QString::NormalizationForm_D == 0);
Q_STATIC_ASSERT(QString::NormalizationForm_C == 1);
Q_STATIC_ASSERT(QString::NormalizationForm_KD == 2);
Q_STATIC_ASSERT(QString::NormalizationForm_KC == 3);
enum { NFQC_YES = 0, NFQC_NO = 1, NFQC_MAYBE = 3 };
const ushort *string = reinterpret_cast<const ushort *>(str->constData());
int length = str->length();
// this avoids one out of bounds check in the loop
while (length > from && QChar::isHighSurrogate(string[length - 1]))
--length;
uchar lastCombining = 0;
for (int i = from; i < length; ++i) {
int pos = i;
uint uc = string[i];
if (uc < 0x80) {
// ASCII characters are stable code points
lastCombining = 0;
*lastStable = pos;
continue;
}
if (QChar::isHighSurrogate(uc)) {
ushort low = string[i + 1];
if (!QChar::isLowSurrogate(low)) {
// treat surrogate like stable code point
lastCombining = 0;
*lastStable = pos;
continue;
}
++i;
uc = QChar::surrogateToUcs4(uc, low);
}
const QUnicodeTables::Properties *p = qGetProp(uc);
if (p->combiningClass < lastCombining && p->combiningClass > 0)
return false;
const uchar check = (p->nfQuickCheck >> (mode << 1)) & 0x03;
if (check != NFQC_YES)
return false; // ### can we quick check NFQC_MAYBE ?
lastCombining = p->combiningClass;
if (lastCombining == 0)
*lastStable = pos;
}
if (length != str->length()) // low surrogate parts at the end of text
*lastStable = str->length() - 1;
return true;
}
QT_END_NAMESPACE

View File

@ -6637,6 +6637,8 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::
for (int i = from; i < len; ++i) {
if (p[i].unicode() >= 0x80) {
simple = false;
if (i > from)
from = i - 1;
break;
}
}
@ -6679,6 +6681,10 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::
}
}
}
if (normalizationQuickCheckHelper(data, mode, from, &from))
return;
decomposeHelper(data, mode < QString::NormalizationForm_KD, version, from);
canonicalOrderHelper(data, version, from);

File diff suppressed because it is too large Load Diff

View File

@ -79,8 +79,9 @@ struct Properties {
ushort titleCaseSpecial : 1;
ushort caseFoldSpecial : 1;
ushort unicodeVersion : 4;
ushort graphemeBreakClass : 8; /* 4 used */
ushort wordBreakClass : 8; /* 4 used */
ushort nfQuickCheck : 8;
ushort graphemeBreakClass : 4; /* 4 used */
ushort wordBreakClass : 4; /* 4 used */
ushort sentenceBreakClass : 8; /* 4 used */
ushort lineBreakClass : 8; /* 6 used */
ushort script : 8; /* 7 used */