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:
parent
f18082bbed
commit
d83aabad0f
@ -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
|
||||||
|
@ -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]
|
139
src/corelib/text/qstaticlatin1stringmatcher.h
Normal file
139
src/corelib/text/qstaticlatin1stringmatcher.h
Normal 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
|
86
src/corelib/text/qstaticlatin1stringmatcher.qdoc
Normal file
86
src/corelib/text/qstaticlatin1stringmatcher.qdoc
Normal 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
|
||||||
|
*/
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user