diff options
-rw-r--r-- | src/corelib/text/qlatin1stringmatcher.cpp | 42 | ||||
-rw-r--r-- | src/corelib/text/qlatin1stringmatcher.h | 9 | ||||
-rw-r--r-- | tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp | 75 |
3 files changed, 104 insertions, 22 deletions
diff --git a/src/corelib/text/qlatin1stringmatcher.cpp b/src/corelib/text/qlatin1stringmatcher.cpp index 68bf97db5c..9036048fff 100644 --- a/src/corelib/text/qlatin1stringmatcher.cpp +++ b/src/corelib/text/qlatin1stringmatcher.cpp @@ -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 diff --git a/src/corelib/text/qlatin1stringmatcher.h b/src/corelib/text/qlatin1stringmatcher.h index 3b8c24fc92..dd3414fc6d 100644 --- a/src/corelib/text/qlatin1stringmatcher.h +++ b/src/corelib/text/qlatin1stringmatcher.h @@ -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]; }; diff --git a/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp b/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp index 82e12bdfca..23ea54658b 100644 --- a/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp +++ b/tests/auto/corelib/text/qlatin1stringmatcher/tst_qlatin1stringmatcher.cpp @@ -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 = MaybeThread{ [&] { - QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive); - dynamicResult = m.indexIn(QLatin1StringView(large)); - } }; - t.join(); + { + // + // 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(); + + // + // THEN: the result index is not truncated + // + + QCOMPARE(dynamicResult, qsizetype(BaseSize)); + } - // - // THEN: the result index is not trucated - // + { + qsizetype dynamicResult; + auto t = std::thread{ [&] { + QLatin1StringMatcher m(QLatin1StringView(needle), Qt::CaseSensitive); + dynamicResult = m.indexIn(QStringView(QString::fromLatin1(large))); + } }; + t.join(); + + QCOMPARE(dynamicResult, qsizetype(BaseSize)); + } - QCOMPARE(dynamicResult, qsizetype(BaseSize)); #else QSKIP("This test is 64-bit only."); #endif |