QLatin1StringMatcher: add indexIn(QStringView) overload

Drive-by changes, remove a redundant typedef.

[ChangeLog][QtCore][QLatin1StringMatcher] Added indexIn(QStringView)
overload.

Task-number: QTBUG-117054
Change-Id: I5a8426cb0f9d9111f086015902ffe2185a267c86
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Øystein Heskestad <oystein.heskestad@qt.io>
This commit is contained in:
Ahmad Samir 2023-10-23 22:47:09 +03:00
parent 519a47e870
commit c878a51509
3 changed files with 101 additions and 19 deletions

View File

@ -160,6 +160,31 @@ Qt::CaseSensitivity QLatin1StringMatcher::caseSensitivity() const noexcept
*/
qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype from) const noexcept
{
return indexIn_helper(haystack, from);
}
/*!
\since 6.8
\overload
Searches for the pattern in the given \a haystack starting from index
position \a from.
\sa caseSensitivity(), pattern()
*/
qsizetype QLatin1StringMatcher::indexIn(QStringView haystack, qsizetype from) const noexcept
{
return indexIn_helper(haystack, from);
}
/*!
\internal
*/
template <typename String>
qsizetype QLatin1StringMatcher::indexIn_helper(String haystack, qsizetype from) const noexcept
{
static_assert(QtPrivate::isLatin1OrUtf16View<String>);
if (m_pattern.isEmpty() && from == haystack.size())
return from;
if (from < 0) // Historical behavior (see QString::indexOf and co.)
@ -167,8 +192,15 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
if (from >= haystack.size())
return -1;
auto begin = haystack.begin() + from;
auto end = haystack.end();
const auto start = [haystack] {
if constexpr (std::is_same_v<String, QStringView>)
return haystack.utf16();
else
return haystack.begin();
}();
auto begin = start + from;
auto end = start + haystack.size();
auto found = begin;
if (m_cs == Qt::CaseSensitive) {
found = m_caseSensitiveSearcher(begin, end, m_pattern.begin(), m_pattern.end()).begin;
@ -178,7 +210,7 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
const qsizetype bufferSize = std::min(m_pattern.size(), qsizetype(sizeof m_foldBuffer));
const QLatin1StringView restNeedle = m_pattern.sliced(bufferSize);
const bool needleLongerThanBuffer = restNeedle.size() > 0;
QLatin1StringView restHaystack = haystack;
String restHaystack = haystack;
do {
found = m_caseInsensitiveSearcher(found, end, m_foldBuffer, &m_foldBuffer[bufferSize])
.begin;
@ -189,13 +221,13 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
}
restHaystack = haystack.sliced(
qMin(haystack.size(),
bufferSize + qsizetype(std::distance(haystack.begin(), found))));
bufferSize + qsizetype(std::distance(start, found))));
if (restHaystack.startsWith(restNeedle, Qt::CaseInsensitive))
break;
++found;
} while (true);
}
return std::distance(haystack.begin(), found);
return std::distance(start, found);
}
QT_END_NAMESPACE

View File

@ -14,6 +14,10 @@
QT_BEGIN_NAMESPACE
namespace QtPrivate {
template <typename T>
constexpr inline bool isLatin1OrUtf16View =
std::disjunction_v<std::is_same<T, QLatin1StringView>, std::is_same<T, QStringView>>;
template<class RandomIt1,
class Hash = std::hash<typename std::iterator_traits<RandomIt1>::value_type>,
class BinaryPredicate = std::equal_to<>>
@ -147,6 +151,7 @@ public:
Q_CORE_EXPORT Qt::CaseSensitivity caseSensitivity() const noexcept;
Q_CORE_EXPORT qsizetype indexIn(QLatin1StringView haystack, qsizetype from = 0) const noexcept;
Q_CORE_EXPORT qsizetype indexIn(QStringView haystack, qsizetype from = 0) const noexcept;
private:
void setSearcher() noexcept;
@ -164,6 +169,10 @@ private:
CaseSensitiveSearcher m_caseSensitiveSearcher;
CaseInsensitiveSearcher m_caseInsensitiveSearcher;
};
template <typename String>
qsizetype indexIn_helper(String haystack, qsizetype from) const noexcept;
char m_foldBuffer[256];
};

View File

@ -44,6 +44,12 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("Hellohello"_L1), 5);
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1, 1), -1);
QCOMPARE(m.indexIn(u"hello"), 0);
QCOMPARE(m.indexIn(u"Hello"), -1);
QCOMPARE(m.indexIn(u"Hellohello"), 5);
QCOMPARE(m.indexIn(u"helloHello"), 0);
QCOMPARE(m.indexIn(u"helloHello", 1), -1);
}
{
QLatin1StringMatcher m("Hello"_L1, Qt::CaseSensitive);
@ -53,6 +59,12 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("Hellohello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
QCOMPARE(m.indexIn(u"hello"), -1);
QCOMPARE(m.indexIn(u"Hello"), 0);
QCOMPARE(m.indexIn(u"Hellohello"), 0);
QCOMPARE(m.indexIn(u"helloHello"), 5);
QCOMPARE(m.indexIn(u"helloHello", 6), -1);
}
{
QLatin1StringMatcher m("hello"_L1, Qt::CaseInsensitive);
@ -63,6 +75,13 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1, 1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
QCOMPARE(m.indexIn(u"hello"), 0);
QCOMPARE(m.indexIn(u"Hello"), 0);
QCOMPARE(m.indexIn(u"Hellohello"), 0);
QCOMPARE(m.indexIn(u"helloHello"), 0);
QCOMPARE(m.indexIn(u"helloHello", 1), 5);
QCOMPARE(m.indexIn(u"helloHello", 6), -1);
}
{
QLatin1StringMatcher m("Hello"_L1, Qt::CaseInsensitive);
@ -73,6 +92,13 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn("helloHello"_L1), 0);
QCOMPARE(m.indexIn("helloHello"_L1, 1), 5);
QCOMPARE(m.indexIn("helloHello"_L1, 6), -1);
QCOMPARE(m.indexIn(u"hello"), 0);
QCOMPARE(m.indexIn(u"Hello"), 0);
QCOMPARE(m.indexIn(u"Hellohello"), 0);
QCOMPARE(m.indexIn(u"helloHello"), 0);
QCOMPARE(m.indexIn(u"helloHello", 1), 5);
QCOMPARE(m.indexIn(u"helloHello", 6), -1);
}
{
QLatin1StringMatcher m(hello, Qt::CaseSensitive);
@ -81,6 +107,11 @@ void tst_QLatin1StringMatcher::overloads()
QCOMPARE(m.indexIn(hello, 1), -1);
QCOMPARE(m.indexIn(hello2, 1), hello.size());
QCOMPARE(m.indexIn(hello2, 6), -1);
QCOMPARE(m.indexIn(QString::fromLatin1(hello)), 0);
QCOMPARE(m.indexIn(QString::fromLatin1(hello), 1), -1);
QCOMPARE(m.indexIn(QString::fromLatin1(hello2), 1), hello.size());
QCOMPARE(m.indexIn(QString::fromLatin1(hello2), 6), -1);
}
}
@ -387,25 +418,35 @@ void tst_QLatin1StringMatcher::haystacksWithMoreThan4GiBWork()
QCOMPARE(large.size(), BaseSize + needle.size());
qDebug("created dataset in %lld ms", timer.elapsed());
using MaybeThread = std::thread;
{
//
// WHEN: trying to match an occurrence past the 4GiB mark
//
qsizetype dynamicResult;
auto t = std::thread{ [&] {
QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive);
dynamicResult = m.indexIn(QLatin1StringView(large));
} };
t.join();
//
// WHEN: trying to match an occurrence past the 4GiB mark
//
//
// THEN: the result index is not truncated
//
qsizetype dynamicResult;
QCOMPARE(dynamicResult, qsizetype(BaseSize));
}
auto t = MaybeThread{ [&] {
QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive);
dynamicResult = m.indexIn(QLatin1StringView(large));
} };
t.join();
{
qsizetype dynamicResult;
auto t = std::thread{ [&] {
QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive);
dynamicResult = m.indexIn(QStringView(QString::fromLatin1(large)));
} };
t.join();
//
// THEN: the result index is not trucated
//
QCOMPARE(dynamicResult, qsizetype(BaseSize));
}
QCOMPARE(dynamicResult, qsizetype(BaseSize));
#else
QSKIP("This test is 64-bit only.");
#endif