Add static constexpr Boyer-Moore Latin-1 string matcher

QStaticLatin1StringMatcher is a static templated Latin-1 Boyer-Moore
string matcher which can be case sensitive or not. It should be used
when the needle is known at compile time so there is no run-time
overhead when generating the skip table.
The convenience functions qMakeStaticCaseSensitiveLatin1StringMatcher
and qMakeStaticCaseInsensitiveLatin1StringMatcher should be used to
construct the matcher objects.

Green Hills Optimizing Compilers are currently not supported.

[ChangeLog][QtCore] Added QStaticLatin1StringMatcher, which can be used
to create a static constexpr string matcher for Latin-1 content.

Task-number: QTBUG-100236
Change-Id: I8b8eed1e88e152f29cbf8d36d83e410fafc5ca2c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Øystein Heskestad 2022-10-04 15:00:42 +02:00
parent f18082bbed
commit d83aabad0f
5 changed files with 505 additions and 0 deletions

View File

@ -222,6 +222,7 @@ qt_internal_add_module(Core
text/qlocale.cpp text/qlocale.h text/qlocale_p.h text/qlocale.cpp text/qlocale.h text/qlocale_p.h
text/qlocale_data_p.h text/qlocale_data_p.h
text/qlocale_tools.cpp text/qlocale_tools_p.h text/qlocale_tools.cpp text/qlocale_tools_p.h
text/qstaticlatin1stringmatcher.h
text/qstring.cpp text/qstring.h text/qstring.cpp text/qstring.h
text/qstringalgorithms.h text/qstringalgorithms_p.h text/qstringalgorithms.h text/qstringalgorithms_p.h
text/qstringbuilder.cpp text/qstringbuilder.h text/qstringbuilder.cpp text/qstringbuilder.h

View File

@ -0,0 +1,8 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
static constexpr auto matcher = qMakeStaticCaseSensitiveLatin1StringViewMatcher("needle");
//! [0]
//! [1]
static constexpr auto matcher = qMakeStaticCaseInsensitiveLatin1StringViewMatcher("needle");
//! [1]

View File

@ -0,0 +1,139 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTATICLATIN1STRINGMATCHER_H
#define QSTATICLATIN1STRINGMATCHER_H
#include <functional>
#include <iterator>
#include <limits>
#include <QtCore/q20algorithm.h>
#include <QtCore/qlatin1stringmatcher.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
#ifdef Q_CC_GHS
# define QT_STATIC_BOYER_MOORE_NOT_SUPPORTED
#else
namespace QtPrivate {
template <class RandomIt1,
class Hash = std::hash<typename std::iterator_traits<RandomIt1>::value_type>,
class BinaryPredicate = std::equal_to<>>
class q_boyer_moore_searcher
{
public:
constexpr q_boyer_moore_searcher(RandomIt1 pat_first, RandomIt1 pat_last) : m_skiptable{}
{
const size_t n = std::distance(pat_first, pat_last);
constexpr auto uchar_max = (std::numeric_limits<uchar>::max)();
uchar max = n > uchar_max ? uchar_max : uchar(n);
q20::fill(std::begin(m_skiptable), std::end(m_skiptable), max);
Hash hf;
RandomIt1 pattern = std::next(pat_first, n - max);
while (max--)
m_skiptable[hf(*pattern++)] = max;
}
template <class RandomIt2>
constexpr auto operator()(RandomIt2 first, RandomIt2 last, RandomIt1 pat_first,
RandomIt1 pat_last) const
{
struct R
{
RandomIt2 begin, end;
};
Hash hf;
BinaryPredicate pred;
auto pat_length = std::distance(pat_first, pat_last);
if (pat_length == 0)
return R{ first, first };
auto haystack_length = std::distance(first, last);
if (haystack_length < pat_length)
return R{ last, last };
const qsizetype pl_minus_one = qsizetype(pat_length - 1);
RandomIt2 current = first + pl_minus_one;
qsizetype skip = 0;
while (current < last - skip) {
current += skip;
skip = m_skiptable[hf(*current)];
if (!skip) {
// possible match
while (skip < pat_length) {
if (!pred(hf(*(current - skip)), hf(pat_first[pl_minus_one - skip])))
break;
skip++;
}
if (skip > pl_minus_one) { // we have a match
auto match = current + 1 - skip;
return R{ match, match + pat_length };
}
// If we don't have a match we are a bit inefficient as we only skip by one
// when we have the non matching char in the string.
if (m_skiptable[hf(*(current - skip))] == pat_length)
skip = pat_length - skip;
else
skip = 1;
}
}
return R{ last, last };
}
private:
alignas(16) uchar m_skiptable[256];
};
} // namespace QtPrivate
template <Qt::CaseSensitivity CS, size_t N>
class QStaticLatin1StringMatcher
{
static_assert(N > 2, "QStaticLatin1Matcher makes no sense for finding a single-char pattern");
QLatin1StringView m_pattern;
using Hasher = std::conditional_t<CS == Qt::CaseSensitive, QtPrivate::QCaseSensitiveLatin1Hash,
QtPrivate::QCaseInsensitiveLatin1Hash>;
QtPrivate::q_boyer_moore_searcher<const char *, Hasher> m_searcher;
public:
explicit constexpr QStaticLatin1StringMatcher(QLatin1StringView patternToMatch) noexcept
: m_pattern(patternToMatch),
m_searcher(patternToMatch.begin(), patternToMatch.begin() + N - 1)
{
}
constexpr qsizetype indexIn(QLatin1StringView haystack, qsizetype from = 0) const noexcept
{
if (from >= haystack.size())
return -1;
const char *begin = haystack.begin() + from;
const char *end = haystack.end();
const auto r = m_searcher(begin, end, m_pattern.begin(), m_pattern.end());
return r.begin == end ? -1 : std::distance(haystack.begin(), r.begin);
}
};
template <size_t N>
constexpr auto qMakeStaticCaseSensitiveLatin1StringMatcher(const char (&patternToMatch)[N]) noexcept
{
return QStaticLatin1StringMatcher<Qt::CaseSensitive, N>(
QLatin1StringView(patternToMatch, qsizetype(N) - 1));
}
template <size_t N>
constexpr auto
qMakeStaticCaseInsensitiveLatin1StringMatcher(const char (&patternToMatch)[N]) noexcept
{
return QStaticLatin1StringMatcher<Qt::CaseInsensitive, N>(
QLatin1StringView(patternToMatch, qsizetype(N) - 1));
}
#endif
QT_END_NAMESPACE
#endif // QSTATICLATIN1STRINGMATCHER_H

View File

@ -0,0 +1,86 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*! \class QStaticLatin1StringMatcher
\inmodule QtCore
\brief The QStaticLatin1StringMatcher class is a compile-time version
of QLatin1StringMatcher.
\since 6.7
\ingroup tools
\ingroup string-processing
This class is useful when your code needs to search efficiently
in Latin-1 strings for a substring that's known at compile-time.
This is common, for example, in parsers. Using a matcher
object's IndexIn() is faster than using the indexOf() method of
the string you are searching in, especially when the string to
be found will be searched for repeatedly or within a large
Latin-1 string that may contain many matches to prefixes of the
substring to be found.
Unlike QLatin1StringMatcher, this class calculates the internal
representation at \e{compile-time}, so it can even benefit if you
are doing one-off Latin-1 string matches.
Create the QStaticLatin1StringMatcher by calling
qMakeStaticCaseSensitiveLatin1StringMatcher() or
qMakeStaticCaseInsensitiveLatin1StringMatcher() passing the Latin-1
string to search for as a C string literal. Store the return value of
that function in a \c{static constexpr auto} variable, so you don't
need to pass the \c{N} template parameter explicitly.
Then call indexIn() on the QLatin1StringView in which you want to search,
just like with QLatin1StringMatcher.
Since this class is designed to do all the up-front calculations at
compile-time, it does not offer setPattern() or setCaseSensitivity()
methods.
Integrity is currently not supported.
\sa QLatin1StringMatcher, QStaticByteArrayMatcher, QByteArrayMatcher
*/
/*!
\fn template<Qt::CaseSensitivity CS, size_t N> constexpr qsizetype QStaticLatin1StringMatcher<CS, N>::indexIn(QLatin1StringView haystack, qsizetype from) const
Searches the QLatin1StringView \a haystack, from byte position \a from
(default 0, i.e. from the first byte), for QLatin1StringView pattern()
that was set in the constructor. Using the case sensitivity that was also
set in the constructor.
Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
*/
/*!
\fn template<size_t N> constexpr auto qMakeStaticCaseSensitiveLatin1StringMatcher(const char
(&patternToMatch)[N])
\since 6.7
\relates QStaticLatin1StringMatcher
Return a QStaticLatin1StringMatcher with the correct \c{N} determined
automatically from the \a patternToMatch passed, and with case sensitivity.
To take full advantage of this function, assign the result to a
\c{static constexpr auto} variable:
\snippet code/src_corelib_text_qstaticlatin1stringmatcher.cpp 0
*/
/*!
\fn template<size_t N> constexpr auto qMakeStaticCaseInsensitiveLatin1StringMatcher(const char
(&patternToMatch)[N])
\since 6.7
\relates QStaticLatin1StringMatcher
Return a QStaticLatin1StringMatcher with the correct \c{N} determined
automatically from the \a patternToMatch passed, and without case sensitivity.
To take full advantage of this function, assign the result to a
\c{static constexpr auto} variable:
\snippet code/src_corelib_text_qstaticlatin1stringmatcher.cpp 1
*/

View File

@ -4,6 +4,7 @@
#include <QTest> #include <QTest>
#include <QtCore/QLatin1StringMatcher> #include <QtCore/QLatin1StringMatcher>
#include <QtCore/QStaticLatin1StringMatcher>
#include <numeric> #include <numeric>
#include <string> #include <string>
@ -23,9 +24,11 @@ class tst_QLatin1StringMatcher : public QObject
private slots: private slots:
void overloads(); void overloads();
void staticOverloads();
void interface(); void interface();
void indexIn(); void indexIn();
void haystacksWithMoreThan4GiBWork(); void haystacksWithMoreThan4GiBWork();
void staticLatin1StringMatcher();
}; };
void tst_QLatin1StringMatcher::overloads() void tst_QLatin1StringMatcher::overloads()
@ -81,6 +84,128 @@ void tst_QLatin1StringMatcher::overloads()
} }
} }
void tst_QLatin1StringMatcher::staticOverloads()
{
#ifdef QT_STATIC_BOYER_MOORE_NOT_SUPPORTED
QSKIP("Test is only valid on an OS that supports static latin1 string matcher");
#else
constexpr QLatin1StringView hello = "hello"_L1;
QByteArray hello2B = QByteArrayView(hello).toByteArray().repeated(2);
QLatin1StringView hello2(hello2B);
{
static constexpr auto m = qMakeStaticCaseSensitiveLatin1StringMatcher("hel");
QCOMPARE(m.indexIn("hello"_L1), 0);
QCOMPARE(m.indexIn("Hello"_L1), -1);
QCOMPARE(m.indexIn("Hellohello"_L1), 5);
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("he"_L1), -1);
QCOMPARE(m.indexIn("hel"_L1), 0);
QCOMPARE(m.indexIn(hello), 0);
QCOMPARE(m.indexIn(hello, 1), -1); // from is 1
QCOMPARE(m.indexIn(hello2, 2), hello.size()); // from is 2
QCOMPARE(m.indexIn(hello2, 3), hello.size()); // from is 3
QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
static_assert(m.indexIn("hello"_L1) == 0);
static_assert(m.indexIn("Hello"_L1) == -1);
static_assert(m.indexIn("Hellohello"_L1) == 5);
static_assert(m.indexIn("helloHello"_L1) == 0);
static_assert(m.indexIn("he"_L1) == -1);
static_assert(m.indexIn("hel"_L1) == 0);
static_assert(m.indexIn("hellohello"_L1, 2) == 5); // from is 2
static_assert(m.indexIn("hellohello"_L1, 3) == 5); // from is 3
static_assert(m.indexIn("hellohello"_L1, 6) == -1); // from is 6
}
{
static constexpr auto m = qMakeStaticCaseSensitiveLatin1StringMatcher("Hel");
QCOMPARE(m.indexIn("hello"_L1), -1);
QCOMPARE(m.indexIn("Hello"_L1), 0);
QCOMPARE(m.indexIn("Hellohello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
QCOMPARE(m.indexIn("He"_L1), -1);
QCOMPARE(m.indexIn("Hel"_L1), 0);
QCOMPARE(m.indexIn(hello), -1);
QCOMPARE(m.indexIn(hello2, 2), -1); // from is 2
QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
static_assert(m.indexIn("hello"_L1) == -1);
static_assert(m.indexIn("Hello"_L1) == 0);
static_assert(m.indexIn("Hellohello"_L1) == 0);
static_assert(m.indexIn("helloHello"_L1) == 5);
static_assert(m.indexIn("helloHello"_L1, 6) == -1);
static_assert(m.indexIn("He"_L1) == -1);
static_assert(m.indexIn("Hel"_L1) == 0);
static_assert(m.indexIn("hellohello"_L1, 2) == -1); // from is 2
static_assert(m.indexIn("hellohello"_L1, 6) == -1); // from is 6
}
{
static constexpr auto m = qMakeStaticCaseInsensitiveLatin1StringMatcher("hel");
QCOMPARE(m.indexIn("hello"_L1), 0);
QCOMPARE(m.indexIn("Hello"_L1), 0);
QCOMPARE(m.indexIn("Hellohello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("he"_L1), -1);
QCOMPARE(m.indexIn("hel"_L1), 0);
QCOMPARE(m.indexIn(hello), 0);
QCOMPARE(m.indexIn(hello, 1), -1);
QCOMPARE(m.indexIn(hello2, 2), hello.size()); // from is 2
QCOMPARE(m.indexIn(hello2, 3), hello.size()); // from is 3
QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
static_assert(m.indexIn("hello"_L1) == 0);
static_assert(m.indexIn("Hello"_L1) == 0);
static_assert(m.indexIn("Hellohello"_L1) == 0);
static_assert(m.indexIn("helloHello"_L1) == 0);
static_assert(m.indexIn("he"_L1) == -1);
static_assert(m.indexIn("hel"_L1) == 0);
static_assert(m.indexIn("hellohello"_L1, 2) == 5); // from is 2
static_assert(m.indexIn("hellohello"_L1, 3) == 5); // from is 3
static_assert(m.indexIn("hellohello"_L1, 6) == -1); // from is 6
}
{
static constexpr auto m = qMakeStaticCaseInsensitiveLatin1StringMatcher("Hel");
QCOMPARE(m.indexIn("hello"_L1), 0);
QCOMPARE(m.indexIn("Hello"_L1), 0);
QCOMPARE(m.indexIn("Hellohello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("he"_L1), -1);
QCOMPARE(m.indexIn("hel"_L1), 0);
QCOMPARE(m.indexIn(hello), 0);
QCOMPARE(m.indexIn(hello, 1), -1);
QCOMPARE(m.indexIn(hello2, 2), hello.size()); // from is 2
QCOMPARE(m.indexIn(hello2, 3), hello.size()); // from is 3
QCOMPARE(m.indexIn(hello2, 6), -1); // from is 6
static_assert(m.indexIn("hello"_L1) == 0);
static_assert(m.indexIn("Hello"_L1) == 0);
static_assert(m.indexIn("Hellohello"_L1) == 0);
static_assert(m.indexIn("helloHello"_L1) == 0);
static_assert(m.indexIn("he"_L1) == -1);
static_assert(m.indexIn("hel"_L1) == 0);
static_assert(m.indexIn("hellohello"_L1, 2) == 5); // from is 2
static_assert(m.indexIn("hellohello"_L1, 3) == 5); // from is 3
static_assert(m.indexIn("hellohello"_L1, 6) == -1); // from is 6
}
{
static constexpr auto m = qMakeStaticCaseInsensitiveLatin1StringMatcher("b\xF8");
QCOMPARE(m.indexIn("B\xD8"_L1), 0);
QCOMPARE(m.indexIn("B\xF8"_L1), 0);
QCOMPARE(m.indexIn("b\xD8"_L1), 0);
QCOMPARE(m.indexIn("b\xF8"_L1), 0);
QCOMPARE(m.indexIn("b\xF8lle"_L1), 0);
QCOMPARE(m.indexIn("m\xF8lle"_L1), -1);
QCOMPARE(m.indexIn("Si b\xF8"_L1), 3);
}
{
static constexpr auto m = qMakeStaticCaseSensitiveLatin1StringMatcher("b\xF8");
QCOMPARE(m.indexIn("B\xD8"_L1), -1);
QCOMPARE(m.indexIn("B\xF8"_L1), -1);
QCOMPARE(m.indexIn("b\xD8"_L1), -1);
QCOMPARE(m.indexIn("b\xF8"_L1), 0);
QCOMPARE(m.indexIn("b\xF8lle"_L1), 0);
QCOMPARE(m.indexIn("m\xF8lle"_L1), -1);
QCOMPARE(m.indexIn("Si b\xF8"_L1), 3);
}
#endif
}
void tst_QLatin1StringMatcher::interface() void tst_QLatin1StringMatcher::interface()
{ {
QLatin1StringView needle = "abc123"_L1; QLatin1StringView needle = "abc123"_L1;
@ -286,6 +411,152 @@ void tst_QLatin1StringMatcher::haystacksWithMoreThan4GiBWork()
#endif #endif
} }
void tst_QLatin1StringMatcher::staticLatin1StringMatcher()
{
#ifdef QT_STATIC_BOYER_MOORE_NOT_SUPPORTED
QSKIP("Test is only valid on an OS that supports static latin1 string matcher");
#else
{
static constexpr auto smatcher = qMakeStaticCaseSensitiveLatin1StringMatcher("Hello");
QCOMPARE(smatcher.indexIn("Hello"_L1), 0);
QCOMPARE(smatcher.indexIn("Hello, World!"_L1), 0);
QCOMPARE(smatcher.indexIn("Hello, World!"_L1, 0), 0);
QCOMPARE(smatcher.indexIn("Hello, World!"_L1, 1), -1);
QCOMPARE(smatcher.indexIn("aHello, World!"_L1), 1);
QCOMPARE(smatcher.indexIn("aaHello, World!"_L1), 2);
QCOMPARE(smatcher.indexIn("aaaHello, World!"_L1), 3);
QCOMPARE(smatcher.indexIn("aaaaHello, World!"_L1), 4);
QCOMPARE(smatcher.indexIn("aaaaaHello, World!"_L1), 5);
QCOMPARE(smatcher.indexIn("aaaaaaHello, World!"_L1), 6);
QCOMPARE(smatcher.indexIn("HHello, World!"_L1), 1);
QCOMPARE(smatcher.indexIn("HeHello, World!"_L1), 2);
QCOMPARE(smatcher.indexIn("HelHello, World!"_L1), 3);
QCOMPARE(smatcher.indexIn("HellHello, World!"_L1), 4);
QCOMPARE(smatcher.indexIn("HellaHello, World!"_L1), 5);
QCOMPARE(smatcher.indexIn("HellauHello, World!"_L1), 6);
QCOMPARE(smatcher.indexIn("aHella, World!"_L1), -1);
QCOMPARE(smatcher.indexIn("aaHella, World!"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaHella, World!"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaaHella, World!"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaaaHella, World!"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaaaaHella, World!"_L1), -1);
QCOMPARE(smatcher.indexIn("aHello"_L1), 1);
QCOMPARE(smatcher.indexIn("aaHello"_L1), 2);
QCOMPARE(smatcher.indexIn("aaaHello"_L1), 3);
QCOMPARE(smatcher.indexIn("aaaaHello"_L1), 4);
QCOMPARE(smatcher.indexIn("aaaaaHello"_L1), 5);
QCOMPARE(smatcher.indexIn("aaaaaaHello"_L1), 6);
QCOMPARE(smatcher.indexIn("HHello"_L1), 1);
QCOMPARE(smatcher.indexIn("HeHello"_L1), 2);
QCOMPARE(smatcher.indexIn("HelHello"_L1), 3);
QCOMPARE(smatcher.indexIn("HellHello"_L1), 4);
QCOMPARE(smatcher.indexIn("HellaHello"_L1), 5);
QCOMPARE(smatcher.indexIn("HellauHello"_L1), 6);
QCOMPARE(smatcher.indexIn("aHella"_L1), -1);
QCOMPARE(smatcher.indexIn("aaHella"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaHella"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaaHella"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaaaHella"_L1), -1);
QCOMPARE(smatcher.indexIn("aaaaaaHella"_L1), -1);
constexpr qsizetype found = smatcher.indexIn("Oh Hello"_L1);
static_assert(found == 3);
static_assert(smatcher.indexIn("Hello"_L1) == 0);
static_assert(smatcher.indexIn("Hello, World!"_L1) == 0);
static_assert(smatcher.indexIn("Hello, World!"_L1, 0) == 0);
static_assert(smatcher.indexIn("Hello, World!"_L1, 1) == -1);
static_assert(smatcher.indexIn("aHello, World!"_L1) == 1);
static_assert(smatcher.indexIn("aaHello, World!"_L1) == 2);
static_assert(smatcher.indexIn("aaaHello, World!"_L1) == 3);
static_assert(smatcher.indexIn("aaaaHello, World!"_L1) == 4);
static_assert(smatcher.indexIn("aaaaaHello, World!"_L1) == 5);
static_assert(smatcher.indexIn("aaaaaaHello, World!"_L1) == 6);
static_assert(smatcher.indexIn("HHello, World!"_L1) == 1);
static_assert(smatcher.indexIn("HeHello, World!"_L1) == 2);
static_assert(smatcher.indexIn("HelHello, World!"_L1) == 3);
static_assert(smatcher.indexIn("HellHello, World!"_L1) == 4);
static_assert(smatcher.indexIn("HellaHello, World!"_L1) == 5);
static_assert(smatcher.indexIn("HellauHello, World!"_L1) == 6);
static_assert(smatcher.indexIn("aHella, World!"_L1) == -1);
static_assert(smatcher.indexIn("aaHella, World!"_L1) == -1);
static_assert(smatcher.indexIn("aaaHella, World!"_L1) == -1);
static_assert(smatcher.indexIn("aaaaHella, World!"_L1) == -1);
static_assert(smatcher.indexIn("aaaaaHella, World!"_L1) == -1);
static_assert(smatcher.indexIn("aaaaaaHella, World!"_L1) == -1);
static_assert(smatcher.indexIn("aHello"_L1) == 1);
static_assert(smatcher.indexIn("aaHello"_L1) == 2);
static_assert(smatcher.indexIn("aaaHello"_L1) == 3);
static_assert(smatcher.indexIn("aaaaHello"_L1) == 4);
static_assert(smatcher.indexIn("aaaaaHello"_L1) == 5);
static_assert(smatcher.indexIn("aaaaaaHello"_L1) == 6);
static_assert(smatcher.indexIn("HHello"_L1) == 1);
static_assert(smatcher.indexIn("HeHello"_L1) == 2);
static_assert(smatcher.indexIn("HelHello"_L1) == 3);
static_assert(smatcher.indexIn("HellHello"_L1) == 4);
static_assert(smatcher.indexIn("HellaHello"_L1) == 5);
static_assert(smatcher.indexIn("HellauHello"_L1) == 6);
static_assert(smatcher.indexIn("aHella"_L1) == -1);
static_assert(smatcher.indexIn("aaHella"_L1) == -1);
static_assert(smatcher.indexIn("aaaHella"_L1) == -1);
static_assert(smatcher.indexIn("aaaaHella"_L1) == -1);
static_assert(smatcher.indexIn("aaaaaHella"_L1) == -1);
static_assert(smatcher.indexIn("aaaaaaHella"_L1) == -1);
static_assert(smatcher.indexIn("aHello"_L1) == 1);
static_assert(smatcher.indexIn("no"_L1) == -1);
static_assert(smatcher.indexIn("miss"_L1) == -1);
static_assert(smatcher.indexIn("amiss"_L1) == -1);
static_assert(smatcher.indexIn("olleH"_L1) == -1);
static_assert(smatcher.indexIn("HellNo"_L1) == -1);
static_assert(smatcher.indexIn("lloHello"_L1) == 3);
static_assert(smatcher.indexIn("lHello"_L1) == 1);
static_assert(smatcher.indexIn("oHello"_L1) == 1);
}
{
static constexpr auto smatcher =
qMakeStaticCaseSensitiveLatin1StringMatcher(LONG_STRING_256);
QCOMPARE(smatcher.indexIn(QLatin1StringView("a" LONG_STRING_256)), 1);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aa" LONG_STRING_256)), 2);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaa" LONG_STRING_256)), 3);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaaa" LONG_STRING_256)), 4);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaaaa" LONG_STRING_256)), 5);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaaaaa" LONG_STRING_256)), 6);
QCOMPARE(smatcher.indexIn(QLatin1StringView("a" LONG_STRING_256 "a")), 1);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aa" LONG_STRING_256 "a")), 2);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaa" LONG_STRING_256 "a")), 3);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaaa" LONG_STRING_256 "a")), 4);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaaaa" LONG_STRING_256 "a")), 5);
QCOMPARE(smatcher.indexIn(QLatin1StringView("aaaaaa" LONG_STRING_256 "a")), 6);
QCOMPARE(smatcher.indexIn(QLatin1StringView(LONG_STRING__32 "x" LONG_STRING_256)), 33);
QCOMPARE(smatcher.indexIn(QLatin1StringView(LONG_STRING__64 "x" LONG_STRING_256)), 65);
QCOMPARE(smatcher.indexIn(QLatin1StringView(LONG_STRING_128 "x" LONG_STRING_256)), 129);
static_assert(smatcher.indexIn(QLatin1StringView("a" LONG_STRING_256)) == 1);
static_assert(smatcher.indexIn(QLatin1StringView("aa" LONG_STRING_256)) == 2);
static_assert(smatcher.indexIn(QLatin1StringView("aaa" LONG_STRING_256)) == 3);
static_assert(smatcher.indexIn(QLatin1StringView("aaaa" LONG_STRING_256)) == 4);
static_assert(smatcher.indexIn(QLatin1StringView("aaaaa" LONG_STRING_256)) == 5);
static_assert(smatcher.indexIn(QLatin1StringView("aaaaaa" LONG_STRING_256)) == 6);
static_assert(smatcher.indexIn(QLatin1StringView("a" LONG_STRING_256 "a")) == 1);
static_assert(smatcher.indexIn(QLatin1StringView("aa" LONG_STRING_256 "a")) == 2);
static_assert(smatcher.indexIn(QLatin1StringView("aaa" LONG_STRING_256 "a")) == 3);
static_assert(smatcher.indexIn(QLatin1StringView("aaaa" LONG_STRING_256 "a")) == 4);
static_assert(smatcher.indexIn(QLatin1StringView("aaaaa" LONG_STRING_256 "a")) == 5);
static_assert(smatcher.indexIn(QLatin1StringView("aaaaaa" LONG_STRING_256 "a")) == 6);
static_assert(smatcher.indexIn(QLatin1StringView(LONG_STRING__32 "x" LONG_STRING_256))
== 33);
static_assert(smatcher.indexIn(QLatin1StringView(LONG_STRING__64 "x" LONG_STRING_256))
== 65);
static_assert(smatcher.indexIn(QLatin1StringView(LONG_STRING_128 "x" LONG_STRING_256))
== 129);
}
#endif
}
#undef LONG_STRING_512 #undef LONG_STRING_512
#undef LONG_STRING_256 #undef LONG_STRING_256
#undef LONG_STRING_128 #undef LONG_STRING_128