From f0c2c987e3e7eb046303892b1eee4f848759923a Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 23 Aug 2021 20:28:44 +0200 Subject: [PATCH] QBA(V)/QS(V)::lastIndexOf: fix the search of 1-char needles When a needle has length 1 (because it's a QChar/char16_t, or because it's a string-like of length 1) then an ad-hoc search algorithm is used. This algorithm had a off-by-one, by not allowing to match at the last position of a haystack (in case `from` was `haystack.size()`). That is inconsistent with the general search of substring needles (and what QByteArray does). Fix that case and amend wrong tests. This in turn unveiled the fact that the algorithm was unable to cope with 0-length haystacks (whops), so fix that as well. Drive-by, add a similar fix for QByteArray. Amends 6cee204d56205e250b0675c9c6d4dd8a2367f3c4. Pick-to: 6.2 Change-Id: I6b3effc4ecd74bcbcd33dd2e550da2df7bf05ae3 Reviewed-by: Qt CI Bot Reviewed-by: Edward Welbourne --- src/corelib/text/qbytearray.cpp | 2 ++ src/corelib/text/qstring.cpp | 6 ++++-- tests/auto/corelib/text/qstring/tst_qstring.cpp | 2 +- .../text/qstringapisymmetry/tst_qstringapisymmetry.cpp | 6 +++--- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 7fc783cea5..70526825f3 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -2506,6 +2506,8 @@ static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept { + if (haystack.size() == 0) + return -1; if (from < 0) from += haystack.size(); else if (from > haystack.size()) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 0ca5c7a2cb..640c1e4ee5 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -10344,10 +10344,12 @@ template static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept { + if (haystack.size() == 0) + return -1; if (from < 0) from += haystack.size(); - if (std::size_t(from) >= std::size_t(haystack.size())) - return -1; + else if (std::size_t(from) > std::size_t(haystack.size())) + from = haystack.size() - 1; if (from >= 0) { char16_t c = needle.unicode(); const auto b = haystack.data(); diff --git a/tests/auto/corelib/text/qstring/tst_qstring.cpp b/tests/auto/corelib/text/qstring/tst_qstring.cpp index 7ad218be96..c2a7b93c7d 100644 --- a/tests/auto/corelib/text/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/text/qstring/tst_qstring.cpp @@ -1723,7 +1723,7 @@ void tst_QString::lastIndexOf_data() QTest::newRow("10") << a << "G" << -1 << int(a.size())-1 << true; QTest::newRow("11") << a << "G" << int(a.size())-1 << int(a.size())-1 << true; - QTest::newRow("12") << a << "G" << int(a.size()) << -1 << true; + QTest::newRow("12") << a << "G" << int(a.size()) << int(a.size())-1 << true; QTest::newRow("13") << a << "A" << 0 << 0 << true; QTest::newRow("14") << a << "A" << -1*int(a.size()) << 0 << true; diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp index 88ccc8d3bf..3447af88eb 100644 --- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -2561,7 +2561,7 @@ void tst_QStringApiSymmetry::lastIndexOf_data(bool rhsHasVariableLength) } #define ROW(h, n, st, cs, cis) \ - QTest::addRow("haystack: %s, needle: %s", #h, #n) << h << QLatin1String(#h) \ + QTest::addRow("haystack: %s, needle: %s, start %d", #h, #n, st) << h << QLatin1String(#h) \ << n << QLatin1String(#n) \ << qsizetype(st) << qsizetype(cs) << qsizetype(cis) @@ -2578,8 +2578,8 @@ void tst_QStringApiSymmetry::lastIndexOf_data(bool rhsHasVariableLength) ROW(ABCDEFGHIEfGEFG, g, 14, -1, 14); ROW(ABCDEFGHIEfGEFG, G, 13, 11, 11); ROW(ABCDEFGHIEfGEFG, g, 13, -1, 11); - ROW(ABCDEFGHIEfGEFG, G, 15, -1, -1); - ROW(ABCDEFGHIEfGEFG, g, 15, -1, -1); + ROW(ABCDEFGHIEfGEFG, G, 15, 14, 14); + ROW(ABCDEFGHIEfGEFG, g, 15, -1, 14); ROW(ABCDEFGHIEfGEFG, B, 14, 1, 1); ROW(ABCDEFGHIEfGEFG, b, 14, -1, 1); ROW(ABCDEFGHIEfGEFG, B, -1, 1, 1);