QStringMatcher: fix setCaseSensitivity() on a non-QString-backed matcher

When a non-QString-backed mode (via the (QChar*, int) ctor) was added
for Qt 4.5, the author forgot to adjust the setCaseSensitivity()
function.  It still uses q_pattern instead of (p.uc, p.len) as the
pattern for which to create the skip-table. Since there is no
setPattern() overload for this mode, the correctness of the matcher is
not harmed by this, but its performance degrades to that of a linear
scan: the skip-table, being filled from an empty pattern, will be
all-zeros, sending bm_find() into the 'possible match' case at every
character.

Since matching is still correct, but slow, it's not possible to write
a test for this. I did, however, leave my attempts in the auto-test,
for when we add QStringView overloads of setPattern() which will then
be able to expose the bug.

Change-Id: I7b803e8624b0352a0a974900affbbfc0c260d93b
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Marc Mutz 2017-02-05 14:55:01 +01:00
parent 18e6e81059
commit 9e5e30fa13
2 changed files with 13 additions and 4 deletions

View File

@ -252,7 +252,7 @@ void QStringMatcher::setCaseSensitivity(Qt::CaseSensitivity cs)
{
if (cs == q_cs)
return;
bm_init_skiptable((const ushort *)q_pattern.unicode(), q_pattern.size(), p.q_skiptable, cs);
bm_init_skiptable((const ushort *)p.uc, p.len, p.q_skiptable, cs);
q_cs = cs;
}

View File

@ -54,12 +54,21 @@ void tst_QStringMatcher::qstringmatcher()
// public Qt::CaseSensitivity caseSensitivity() const
void tst_QStringMatcher::caseSensitivity()
{
QStringMatcher matcher;
const QString haystack = QStringLiteral("foobarFoo");
const QStringRef needle = haystack.rightRef(3); // "Foo"
QStringMatcher matcher(needle.data(), needle.size());
QCOMPARE(matcher.caseSensitivity(), Qt::CaseSensitive);
QCOMPARE(matcher.indexIn(haystack), 6);
matcher.setCaseSensitivity(Qt::CaseInsensitive);
QCOMPARE(matcher.caseSensitivity(), Qt::CaseInsensitive);
QCOMPARE(matcher.indexIn(haystack), 0);
matcher.setCaseSensitivity(Qt::CaseSensitive);
QCOMPARE(matcher.caseSensitivity(), Qt::CaseSensitive);
matcher.setCaseSensitivity(Qt::CaseInsensitive);
QCOMPARE(matcher.caseSensitivity(), Qt::CaseInsensitive);
QCOMPARE(matcher.indexIn(haystack), 6);
}
void tst_QStringMatcher::indexIn_data()