Add QLatin1String::count(needle)

[ChangeLog][QtCore][QLatin1String] Added QLatin1String::count(needle).

Task-number: QTBUG-98433
Change-Id: I31c9fdf14fd81500722ff9f5998eadf0e6cedc5c
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
Sona Kurazyan 2022-03-02 09:30:34 +01:00
parent 567c31e8ee
commit 30d28810ee
5 changed files with 139 additions and 0 deletions

View File

@ -9490,6 +9490,22 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
\overload
*/
/*!
\fn qsizetype QLatin1String::count(QStringView str, Qt::CaseSensitivity cs) const
\fn qsizetype QLatin1String::count(QLatin1String l1, Qt::CaseSensitivity cs) const
\fn qsizetype QLatin1String::count(QChar ch, Qt::CaseSensitivity cs) const
\since 6.4
Returns the number of (potentially overlapping) occurrences of the
string-view \a str, Latin-1 string \a l1, or character \a ch,
respectively, in this Latin-1 string.
If \a cs is Qt::CaseSensitive (default), the search is
case sensitive; otherwise the search is case insensitive.
\sa contains(), indexOf()
*/
/*!
\fn QLatin1String::const_iterator QLatin1String::begin() const
\since 5.10
@ -10380,6 +10396,75 @@ qsizetype QtPrivate::count(QStringView haystack, QChar ch, Qt::CaseSensitivity c
return num;
}
qsizetype QtPrivate::count(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs)
{
qsizetype num = 0;
qsizetype i = -1;
// TODO: use Boyer-Moore searcher for case-insensitive search too
// when QTBUG-100236 is done
if (cs == Qt::CaseSensitive) {
QByteArrayMatcher matcher(needle);
while ((i = matcher.indexIn(haystack, i + 1)) != -1)
++num;
} else {
while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1)
++num;
}
return num;
}
qsizetype QtPrivate::count(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs)
{
if (haystack.size() < needle.size())
return 0;
if (!QtPrivate::isLatin1(needle)) // won't find non-L1 UTF-16 needles in a L1 haystack!
return 0;
qsizetype num = 0;
qsizetype i = -1;
// TODO: use Boyer-Moore searcher for case-insensitive search too
// when QTBUG-100236 is done
if (cs == Qt::CaseSensitive) {
QVarLengthArray<uchar> s(needle.size());
qt_to_latin1_unchecked(s.data(), needle.utf16(), needle.size());
QByteArrayMatcher matcher(s);
while ((i = matcher.indexIn(haystack, i + 1)) != -1)
++num;
} else {
while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1)
++num;
}
return num;
}
qsizetype QtPrivate::count(QLatin1String haystack, QChar needle, Qt::CaseSensitivity cs) noexcept
{
// non-L1 needles cannot possibly match in L1-only haystacks
if (needle.unicode() > 0xff)
return 0;
qsizetype num = 0;
if (cs == Qt::CaseSensitive) {
const char needleL1 = needle.toLatin1();
for (char c : haystack) {
if (c == needleL1)
++num;
}
} else {
auto toLower = [](char ch) { return latin1Lower[uchar(ch)]; };
const uchar ch = toLower(needle.toLatin1());
for (char c : haystack) {
if (toLower(c) == ch)
++num;
}
}
return num;
}
template <typename Haystack, typename Needle>
bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
{

View File

@ -177,6 +177,13 @@ public:
[[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); }
[[nodiscard]] qsizetype count(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return QtPrivate::count(*this, str, cs); }
[[nodiscard]] qsizetype count(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return QtPrivate::count(*this, str, cs); }
[[nodiscard]] qsizetype count(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::count(*this, ch, cs); }
[[nodiscard]] short toShort(bool *ok = nullptr, int base = 10) const
{ return QtPrivate::toIntegral<short>(QByteArrayView(*this), ok, base); }
[[nodiscard]] ushort toUShort(bool *ok = nullptr, int base = 10) const

View File

@ -123,6 +123,9 @@ namespace QtPrivate {
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive);
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive);
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QLatin1String haystack, QChar needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
#if QT_CONFIG(regularexpression)
[[nodiscard]] Q_CORE_EXPORT qsizetype indexOf(QStringView haystack,

View File

@ -55,6 +55,7 @@ private Q_SLOTS:
void iterators();
void relationalOperators_data();
void relationalOperators();
void count();
};
void tst_QLatin1String::constExpr()
@ -398,6 +399,36 @@ void tst_QLatin1String::relationalOperators()
#undef CHECK
}
void tst_QLatin1String::count()
{
QLatin1String a("ABCDEFGHIEfGEFG");
QCOMPARE(a.size(), 15);
QCOMPARE(a.count('A'), 1);
QCOMPARE(a.count('Z'), 0);
QCOMPARE(a.count('E'), 3);
QCOMPARE(a.count('F'), 2);
QCOMPARE(a.count('F', Qt::CaseInsensitive), 3);
QCOMPARE(a.count(QLatin1String("FG")), 2);
QCOMPARE(a.count(QLatin1String("FG"), Qt::CaseInsensitive), 3);
QCOMPARE(a.count(QLatin1String(), Qt::CaseInsensitive), 16);
QCOMPARE(a.count(QLatin1String(""), Qt::CaseInsensitive), 16);
QLatin1String nullStr;
QCOMPARE(nullStr.count('A'), 0);
QCOMPARE(nullStr.count(QLatin1String("AB")), 0);
QCOMPARE(nullStr.count(QLatin1String()), 1);
QCOMPARE(nullStr.count(QLatin1String("")), 1);
QLatin1String emptyStr("");
QCOMPARE(emptyStr.count('A'), 0);
QCOMPARE(emptyStr.count(QLatin1String("AB")), 0);
QCOMPARE(emptyStr.count(QLatin1String()), 1);
QCOMPARE(emptyStr.count(QLatin1String("")), 1);
using namespace Qt::Literals::StringLiterals;
QCOMPARE("a\0b"_L1.count(QChar::SpecialCharacter::LineSeparator), 0);
}
QTEST_APPLESS_MAIN(tst_QLatin1String)
#include "tst_qlatin1string.moc"

View File

@ -748,6 +748,19 @@ private Q_SLOTS:
void count_QStringView_char16_t_data() { count_data(); }
void count_QStringView_char16_t() { count_impl<QStringView, char16_t>(); }
void count_QLatin1String_QString_data() { count_data(); }
void count_QLatin1String_QString() { count_impl<QLatin1String, QString>(); }
void count_QLatin1String_QLatin1String_data() { count_data(); }
void count_QLatin1String_QLatin1String() { count_impl<QLatin1String, QLatin1String>(); }
void count_QLatin1String_QStringView_data() { count_data(); }
void count_QLatin1String_QStringView() { count_impl<QLatin1String, QStringView>(); }
void count_QLatin1String_QChar_data() { count_data(); }
void count_QLatin1String_QChar() { count_impl<QLatin1String, QChar>(); }
void count_QLatin1String_char16_t_data() { count_data(); }
void count_QLatin1String_char16_t() { count_impl<QLatin1String, char16_t>(); }
void count_QLatin1String_QLatin1Char_data() { count_data(); }
void count_QLatin1String_QLatin1Char() { count_impl<QLatin1String, QLatin1Char>(); }
//
// UTF-16-only checks:
//