diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index f5c4ef6e7d..c638266256 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -222,6 +222,7 @@ qt_internal_add_module(Core text/qlocale.cpp text/qlocale.h text/qlocale_p.h text/qlocale_data_p.h text/qlocale_tools.cpp text/qlocale_tools_p.h + text/qstaticlatin1stringmatcher.h text/qstring.cpp text/qstring.h text/qstringalgorithms.h text/qstringalgorithms_p.h text/qstringbuilder.cpp text/qstringbuilder.h diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp new file mode 100644 index 0000000000..ae6e19e471 --- /dev/null +++ b/src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp @@ -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] diff --git a/src/corelib/text/qstaticlatin1stringmatcher.h b/src/corelib/text/qstaticlatin1stringmatcher.h new file mode 100644 index 0000000000..2a818a57a0 --- /dev/null +++ b/src/corelib/text/qstaticlatin1stringmatcher.h @@ -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 +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#ifdef Q_CC_GHS +# define QT_STATIC_BOYER_MOORE_NOT_SUPPORTED +#else +namespace QtPrivate { +template ::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::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 + 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 +class QStaticLatin1StringMatcher +{ + static_assert(N > 2, "QStaticLatin1Matcher makes no sense for finding a single-char pattern"); + + QLatin1StringView m_pattern; + using Hasher = std::conditional_t; + QtPrivate::q_boyer_moore_searcher 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 +constexpr auto qMakeStaticCaseSensitiveLatin1StringMatcher(const char (&patternToMatch)[N]) noexcept +{ + return QStaticLatin1StringMatcher( + QLatin1StringView(patternToMatch, qsizetype(N) - 1)); +} + +template +constexpr auto +qMakeStaticCaseInsensitiveLatin1StringMatcher(const char (&patternToMatch)[N]) noexcept +{ + return QStaticLatin1StringMatcher( + QLatin1StringView(patternToMatch, qsizetype(N) - 1)); +} +#endif + +QT_END_NAMESPACE + +#endif // QSTATICLATIN1STRINGMATCHER_H diff --git a/src/corelib/text/qstaticlatin1stringmatcher.qdoc b/src/corelib/text/qstaticlatin1stringmatcher.qdoc new file mode 100644 index 0000000000..88a0ec0091 --- /dev/null +++ b/src/corelib/text/qstaticlatin1stringmatcher.qdoc @@ -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 constexpr qsizetype QStaticLatin1StringMatcher::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 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 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 +*/ diff --git a/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp b/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp index 19613105dd..5264355d84 100644 --- a/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp +++ b/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -23,9 +24,11 @@ class tst_QLatin1StringMatcher : public QObject private slots: void overloads(); + void staticOverloads(); void interface(); void indexIn(); void haystacksWithMoreThan4GiBWork(); + void staticLatin1StringMatcher(); }; 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() { QLatin1StringView needle = "abc123"_L1; @@ -286,6 +411,152 @@ void tst_QLatin1StringMatcher::haystacksWithMoreThan4GiBWork() #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_256 #undef LONG_STRING_128