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 6cee204d56.

Pick-to: 6.2
Change-Id: I6b3effc4ecd74bcbcd33dd2e550da2df7bf05ae3
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
bb10
Giuseppe D'Angelo 2021-08-23 20:28:44 +02:00
parent a2abb01451
commit f0c2c987e3
4 changed files with 10 additions and 6 deletions

View File

@ -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())

View File

@ -10344,10 +10344,12 @@ template <typename Haystack>
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();

View File

@ -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;

View File

@ -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);