QStringView, QLatin1String: add lastIndexOf methods

While touching the code, factor out internal methods
to avoid needlees latin1->utf16 conversion.

[ChangeLog][QtCore][QLatin1String] Added lastIndexOf().

[ChangeLog][QtCore][QStringView] Added lastIndexOf().

Change-Id: I1c624f00e4ed10111e0d00b86daff7904eeed176
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Anton Kudryavtsev 2019-04-02 16:24:44 +03:00
parent eed9a8fbd3
commit 55240bcdf3
6 changed files with 418 additions and 127 deletions

View File

@ -145,7 +145,8 @@ extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const ushort *src, int leng
// internal
qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs);
static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept;
static inline qsizetype qt_last_index_of(QStringView haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs);
template <typename Haystack>
static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept;
static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
static inline qsizetype qt_string_count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
@ -3779,74 +3780,6 @@ int QString::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) co
// ### Qt6: qsize
return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs));
}
#endif // QT_STRINGVIEW_LEVEL < 2
static int lastIndexOfHelper(const ushort *haystack, int from, const ushort *needle, int sl, Qt::CaseSensitivity cs)
{
/*
See indexOf() for explanations.
*/
auto sv = [sl](const ushort *v) { return QStringView(v, sl); };
const ushort *end = haystack;
haystack += from;
const uint sl_minus_1 = sl - 1;
const ushort *n = needle+sl_minus_1;
const ushort *h = haystack+sl_minus_1;
uint hashNeedle = 0, hashHaystack = 0;
int idx;
if (cs == Qt::CaseSensitive) {
for (idx = 0; idx < sl; ++idx) {
hashNeedle = ((hashNeedle<<1) + *(n-idx));
hashHaystack = ((hashHaystack<<1) + *(h-idx));
}
hashHaystack -= *haystack;
while (haystack >= end) {
hashHaystack += *haystack;
if (hashHaystack == hashNeedle
&& qt_compare_strings(sv(needle), sv(haystack), Qt::CaseSensitive) == 0)
return haystack - end;
--haystack;
REHASH(haystack[sl]);
}
} else {
for (idx = 0; idx < sl; ++idx) {
hashNeedle = ((hashNeedle<<1) + foldCase(n-idx, needle));
hashHaystack = ((hashHaystack<<1) + foldCase(h-idx, end));
}
hashHaystack -= foldCase(haystack, end);
while (haystack >= end) {
hashHaystack += foldCase(haystack, end);
if (hashHaystack == hashNeedle
&& qt_compare_strings(sv(haystack), sv(needle), Qt::CaseInsensitive) == 0)
return haystack - end;
--haystack;
REHASH(foldCase(haystack + sl, end));
}
}
return -1;
}
static inline int lastIndexOfHelper(
const QStringRef &haystack, int from, const QStringRef &needle, Qt::CaseSensitivity cs)
{
return lastIndexOfHelper(reinterpret_cast<const ushort*>(haystack.unicode()), from,
reinterpret_cast<const ushort*>(needle.unicode()), needle.size(), cs);
}
static inline int lastIndexOfHelper(
const QStringRef &haystack, int from, QLatin1String needle, Qt::CaseSensitivity cs)
{
const int size = needle.size();
QVarLengthArray<ushort> s(size);
qt_from_latin1(s.data(), needle.latin1(), size);
return lastIndexOfHelper(reinterpret_cast<const ushort*>(haystack.unicode()), from,
s.data(), size, cs);
}
/*!
Returns the index position of the last occurrence of the string \a
@ -3866,9 +3799,12 @@ static inline int lastIndexOfHelper(
*/
int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
{
return QStringRef(this).lastIndexOf(QStringRef(&str), from, cs);
// ### Qt6: qsize
return int(QtPrivate::lastIndexOf(*this, from, str, cs));
}
#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.5
\overload lastIndexOf()
@ -3890,7 +3826,8 @@ int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) c
*/
int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
{
return QStringRef(this).lastIndexOf(str, from, cs);
// ### Qt6: qsize
return int(QtPrivate::lastIndexOf(*this, from, str, cs));
}
/*!
@ -3902,9 +3839,10 @@ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) co
int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
{
// ### Qt6: qsize
return int(qt_last_index_of(QStringView(unicode(), size()), ch, from, cs));
return int(qLastIndexOf(*this, ch, from, cs));
}
#if QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.8
\overload lastIndexOf()
@ -3922,8 +3860,27 @@ int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
*/
int QString::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const
{
return QStringRef(this).lastIndexOf(str, from, cs);
// ### Qt6: qsize
return int(QtPrivate::lastIndexOf(*this, from, str, cs));
}
#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\fn int QString::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
\since 5.14
\overload lastIndexOf()
Returns the index position of the last occurrence of the string view \a
str in this string, searching backward from index position \a
from. If \a from is -1 (default), the search starts at the last
character; if \a from is -2, at the next to last character and so
on. Returns -1 if \a str is not found.
If \a cs is Qt::CaseSensitive (default), the search is case
sensitive; otherwise the search is case insensitive.
\sa indexOf(), contains(), count()
*/
#if !(defined(QT_NO_REGEXP) && !QT_CONFIG(regularexpression))
@ -9560,6 +9517,24 @@ QString &QString::setRawData(const QChar *unicode, int size)
\sa indexOf(), QStringView::contains(), QStringView::indexOf(), QString::indexOf()
*/
/*!
\fn int QLatin1String::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
\fn int QLatin1String::lastIndexOf(QLatin1String l1, int from, Qt::CaseSensitivity cs) const
\fn int QLatin1String::lastIndexOf(QChar c, int from, Qt::CaseSensitivity cs) const
\since 5.14
Returns the index position of the last occurrence of the string-view \a str,
Latin-1 string \a l1, or character \a ch, respectively, in this Latin-1 string,
searching backward from index position \a from. If \a from is -1 (default),
the search starts at the last character; if \a from is -2, at the next to last
character and so on. Returns -1 if \a str is not found.
If \a cs is Qt::CaseSensitive (default), the search is case
sensitive; otherwise the search is case insensitive.
\sa indexOf(), QStringView::lastIndexOf(), QStringView::indexOf(), QString::indexOf()
*/
/*!
\fn QLatin1String::const_iterator QLatin1String::begin() const
\since 5.10
@ -11231,7 +11206,8 @@ int QStringRef::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs)
*/
int QStringRef::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
{
return lastIndexOf(QStringRef(&str), from, cs);
// ### Qt6: qsize
return int(QtPrivate::lastIndexOf(*this, from, str, cs));
}
/*!
@ -11246,28 +11222,7 @@ int QStringRef::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs
int QStringRef::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
{
// ### Qt6: qsize
return int(qt_last_index_of(QStringView(unicode(), size()), ch, from, cs));
}
template<typename T>
static int last_index_of_impl(const QStringRef &haystack, int from, const T &needle, Qt::CaseSensitivity cs)
{
const int sl = needle.size();
if (sl == 1)
return haystack.lastIndexOf(needle.at(0), from, cs);
const int l = haystack.size();
if (from < 0)
from += l;
int delta = l - sl;
if (from == l && sl == 0)
return from;
if (uint(from) >= uint(l) || delta < 0)
return -1;
if (from > delta)
from = delta;
return lastIndexOfHelper(haystack, from, needle, cs);
return int(qLastIndexOf(*this, ch, from, cs));
}
/*!
@ -11287,7 +11242,8 @@ static int last_index_of_impl(const QStringRef &haystack, int from, const T &nee
*/
int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
{
return last_index_of_impl(*this, from, str, cs);
// ### Qt6: qsize
return int(QtPrivate::lastIndexOf(*this, from, str, cs));
}
/*!
@ -11307,9 +11263,27 @@ int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs)
*/
int QStringRef::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const
{
return last_index_of_impl(*this, from, str, cs);
// ### Qt6: qsize
return int(QtPrivate::lastIndexOf(*this, from, str, cs));
}
/*!
\fn int QStringRef::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
\since 5.14
\overload lastIndexOf()
Returns the index position of the last occurrence of the string view \a
str in this string, searching backward from index position \a
from. If \a from is -1 (default), the search starts at the last
character; if \a from is -2, at the next to last character and so
on. Returns -1 if \a str is not found.
If \a cs is Qt::CaseSensitive (default), the search is case
sensitive; otherwise the search is case insensitive.
\sa indexOf(), contains(), count()
*/
/*!
\since 4.8
Returns the number of (potentially overlapping) occurrences of
@ -11612,33 +11586,6 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const
\sa indexOf(), count()
*/
static inline qsizetype qt_last_index_of(QStringView haystack, QChar needle,
qsizetype from, Qt::CaseSensitivity cs)
{
if (from < 0)
from += haystack.size();
if (std::size_t(from) >= std::size_t(haystack.size()))
return -1;
if (from >= 0) {
ushort c = needle.unicode();
const ushort *b = reinterpret_cast<const ushort*>(haystack.data());
const ushort *n = b + from;
if (cs == Qt::CaseSensitive) {
for (; n >= b; --n)
if (*n == c)
return n - b;
} else {
c = foldCase(c);
for (; n >= b; --n)
if (foldCase(*n) == c)
return n - b;
}
}
return -1;
}
static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
{
qsizetype num = 0;
@ -11820,6 +11767,38 @@ bool QtPrivate::endsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseS
return qt_ends_with_impl(haystack, needle, cs);
}
namespace {
template <typename Pointer>
uint foldCaseHelper(Pointer ch, Pointer start) = delete;
template <>
uint foldCaseHelper<const QChar*>(const QChar* ch, const QChar* start)
{
return foldCase(reinterpret_cast<const ushort*>(ch), reinterpret_cast<const ushort*>(start));
}
template <>
uint foldCaseHelper<const char*>(const char* ch, const char*)
{
return foldCase(ushort(uchar(*ch)));
}
template <typename T>
ushort valueTypeToUtf16(T t) = delete;
template <>
ushort valueTypeToUtf16<QChar>(QChar t)
{
return t.unicode();
}
template <>
ushort valueTypeToUtf16<char>(char t)
{
return ushort(uchar(t));
}
}
/*!
\internal
@ -11928,6 +11907,97 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
return -1;
}
template <typename Haystack>
static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
qsizetype from, Qt::CaseSensitivity cs) noexcept
{
if (from < 0)
from += haystack.size();
if (std::size_t(from) >= std::size_t(haystack.size()))
return -1;
if (from >= 0) {
ushort c = needle.unicode();
const auto b = haystack.data();
auto n = b + from;
if (cs == Qt::CaseSensitive) {
for (; n >= b; --n)
if (valueTypeToUtf16(*n) == c)
return n - b;
} else {
c = foldCase(c);
for (; n >= b; --n)
if (foldCase(valueTypeToUtf16(*n)) == c)
return n - b;
}
}
return -1;
}
template<typename Haystack, typename Needle>
static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from,
Needle needle0, Qt::CaseSensitivity cs) noexcept
{
const qsizetype sl = needle0.size();
if (sl == 1)
return qLastIndexOf(haystack0, needle0.front(), from, cs);
const qsizetype l = haystack0.size();
if (from < 0)
from += l;
if (from == l && sl == 0)
return from;
const qsizetype delta = l - sl;
if (std::size_t(from) >= std::size_t(l) || delta < 0)
return -1;
if (from > delta)
from = delta;
auto sv = [sl](const typename Haystack::value_type *v) { return Haystack(v, sl); };
auto haystack = haystack0.data();
const auto needle = needle0.data();
const auto *end = haystack;
haystack += from;
const std::size_t sl_minus_1 = sl - 1;
const auto *n = needle + sl_minus_1;
const auto *h = haystack + sl_minus_1;
std::size_t hashNeedle = 0, hashHaystack = 0;
qsizetype idx;
if (cs == Qt::CaseSensitive) {
for (idx = 0; idx < sl; ++idx) {
hashNeedle = (hashNeedle << 1) + valueTypeToUtf16(*(n - idx));
hashHaystack = (hashHaystack << 1) + valueTypeToUtf16(*(h - idx));
}
hashHaystack -= valueTypeToUtf16(*haystack);
while (haystack >= end) {
hashHaystack += valueTypeToUtf16(*haystack);
if (hashHaystack == hashNeedle
&& qt_compare_strings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
return haystack - end;
--haystack;
REHASH(valueTypeToUtf16(haystack[sl]));
}
} else {
for (idx = 0; idx < sl; ++idx) {
hashNeedle = (hashNeedle << 1) + foldCaseHelper(n - idx, needle);
hashHaystack = (hashHaystack << 1) + foldCaseHelper(h - idx, end);
}
hashHaystack -= foldCaseHelper(haystack, end);
while (haystack >= end) {
hashHaystack += foldCaseHelper(haystack, end);
if (hashHaystack == hashNeedle
&& qt_compare_strings(sv(haystack), needle0, Qt::CaseInsensitive) == 0)
return haystack - end;
--haystack;
REHASH(foldCaseHelper(haystack + sl, end));
}
}
return -1;
}
qsizetype QtPrivate::findString(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
{
if (haystack.size() < needle.size())
@ -11961,6 +12031,26 @@ qsizetype QtPrivate::findString(QLatin1String haystack, qsizetype from, QLatin1S
QStringView(reinterpret_cast<const QChar*>(n.constData()), n.size()), cs);
}
qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
/*!
\since 4.8

View File

@ -145,6 +145,13 @@ public:
Q_REQUIRED_RESULT inline bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return indexOf(QStringView(&c, 1), 0, cs) != -1; }
Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsize
Q_REQUIRED_RESULT int lastIndexOf(QLatin1String s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsize
Q_REQUIRED_RESULT inline int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return int(QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs)); } // ### Qt6: qsize
using value_type = const char;
using reference = value_type&;
using const_reference = reference;
@ -235,6 +242,8 @@ qsizetype QStringView::indexOf(QLatin1String s, qsizetype from, Qt::CaseSensitiv
{ return QtPrivate::findString(*this, from, s, cs); }
bool QStringView::contains(QLatin1String s, Qt::CaseSensitivity cs) const noexcept
{ return indexOf(s, 0, cs) != qsizetype(-1); }
qsizetype QStringView::lastIndexOf(QLatin1String s, qsizetype from, Qt::CaseSensitivity cs) const noexcept
{ return QtPrivate::lastIndexOf(*this, from, s, cs); }
class Q_CORE_EXPORT QString
{
@ -357,9 +366,14 @@ public:
Q_REQUIRED_RESULT int indexOf(QStringView s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsize
int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int lastIndexOf(QLatin1String s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#if QT_STRINGVIEW_LEVEL < 2
int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int lastIndexOf(const QStringRef &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#endif
Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsize
inline bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#if QT_STRINGVIEW_LEVEL < 2
@ -1541,10 +1555,14 @@ public:
{ return int(QtPrivate::findString(*this, from, s, cs)); } // ### Qt6: qsize
int indexOf(QChar ch, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int indexOf(QLatin1String str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#if QT_STRINGVIEW_LEVEL < 2
int lastIndexOf(const QStringRef &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int lastIndexOf(const QString &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
#endif
int lastIndexOf(QChar ch, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int lastIndexOf(QLatin1String str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int lastIndexOf(const QStringRef &str, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
Q_REQUIRED_RESULT int lastIndexOf(QStringView s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return int(QtPrivate::lastIndexOf(*this, from, s, cs)); } // ### Qt6: qsize
#if QT_STRINGVIEW_LEVEL < 2
inline bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;

View File

@ -80,6 +80,11 @@ Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStrin
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QStringView trimmed(QStringView s) noexcept;
Q_REQUIRED_RESULT Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QLatin1String trimmed(QLatin1String s) noexcept;

View File

@ -754,6 +754,24 @@ QT_BEGIN_NAMESPACE
\sa indexOf()
*/
/*!
\fn qsizetype QStringView::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
\fn qsizetype QStringView::lastIndexOf(QLatin1String l1, qsizetype from, Qt::CaseSensitivity cs) const
\fn qsizetype QStringView::lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const
\since 5.14
Returns the index position of the last occurrence of the string-view \a str,
Latin-1 string \a l1, or character \a ch, respectively, in this string-view,
searching backward from index position \a from. If \a from is -1 (default),
the search starts at the last character; if \a from is -2, at the next to last
character and so on. Returns -1 if \a str is not found.
If \a cs is Qt::CaseSensitive (default), the search is case
sensitive; otherwise the search is case insensitive.
\sa QString::lastIndexOf()
*/
/*!
\fn QByteArray QStringView::toLatin1() const

View File

@ -282,6 +282,12 @@ public:
{ return indexOf(s, 0, cs) != qsizetype(-1); }
Q_REQUIRED_RESULT inline bool contains(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
Q_REQUIRED_RESULT qsizetype lastIndexOf(QChar c, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); }
Q_REQUIRED_RESULT qsizetype lastIndexOf(QStringView s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::lastIndexOf(*this, from, s, cs); }
Q_REQUIRED_RESULT inline qsizetype lastIndexOf(QLatin1String s, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
Q_REQUIRED_RESULT bool isRightToLeft() const noexcept
{ return QtPrivate::isRightToLeft(*this); }

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
** Copyright (C) 2019 Mail.ru Group.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@ -526,6 +527,47 @@ private Q_SLOTS:
void contains_QStringView_QStringRef() { contains_impl<QStringView, QStringRef>(); }
void contains_QStringView_QStringView_data() { contains_data(); }
void contains_QStringView_QStringView() { contains_impl<QStringView, QStringView>(); }
private:
template <typename Haystack, typename Needle> void lastIndexOf_impl() const;
void lastIndexOf_data();
private Q_SLOTS:
void lastIndexOf_QString_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QString_QString() { lastIndexOf_impl<QString, QString>(); }
void lastIndexOf_QString_QLatin1String_data() { lastIndexOf_data(); }
void lastIndexOf_QString_QLatin1String() { lastIndexOf_impl<QString, QLatin1String>(); }
void lastIndexOf_QString_QStringRef_data() { lastIndexOf_data(); }
void lastIndexOf_QString_QStringRef() { lastIndexOf_impl<QString, QStringRef>(); }
void lastIndexOf_QString_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QString_QStringView() { lastIndexOf_impl<QString, QStringView>(); }
void lastIndexOf_QLatin1String_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QLatin1String_QString() { lastIndexOf_impl<QLatin1String, QString>(); }
void lastIndexOf_QLatin1String_QLatin1String_data() { lastIndexOf_data(); }
void lastIndexOf_QLatin1String_QLatin1String() { lastIndexOf_impl<QLatin1String, QLatin1String>(); }
void lastIndexOf_QLatin1String_QStringRef_data() { lastIndexOf_data(); }
void lastIndexOf_QLatin1String_QStringRef() { lastIndexOf_impl<QLatin1String, QStringRef>(); }
void lastIndexOf_QLatin1String_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QLatin1String_QStringView() { lastIndexOf_impl<QLatin1String, QStringView>(); }
void lastIndexOf_QStringRef_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QStringRef_QString() { lastIndexOf_impl<QStringRef, QString>(); }
void lastIndexOf_QStringRef_QLatin1String_data() { lastIndexOf_data(); }
void lastIndexOf_QStringRef_QLatin1String() { lastIndexOf_impl<QStringRef, QLatin1String>(); }
void lastIndexOf_QStringRef_QStringRef_data() { lastIndexOf_data(); }
void lastIndexOf_QStringRef_QStringRef() { lastIndexOf_impl<QStringRef, QStringRef>(); }
void lastIndexOf_QStringRef_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QStringRef_QStringView() { lastIndexOf_impl<QStringRef, QStringView>(); }
void lastIndexOf_QStringView_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QStringView_QString() { lastIndexOf_impl<QStringView, QString>(); }
void lastIndexOf_QStringView_QLatin1String_data() { lastIndexOf_data(); }
void lastIndexOf_QStringView_QLatin1String() { lastIndexOf_impl<QStringView, QLatin1String>(); }
void lastIndexOf_QStringView_QStringRef_data() { lastIndexOf_data(); }
void lastIndexOf_QStringView_QStringRef() { lastIndexOf_impl<QStringView, QStringRef>(); }
void lastIndexOf_QStringView_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QStringView_QStringView() { lastIndexOf_impl<QStringView, QStringView>(); }
};
void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty)
@ -1626,6 +1668,118 @@ void tst_QStringApiSymmetry::contains_impl() const
}
}
void tst_QStringApiSymmetry::lastIndexOf_data()
{
QTest::addColumn<QString>("haystackU16");
QTest::addColumn<QLatin1String>("haystackL1");
QTest::addColumn<QString>("needleU16");
QTest::addColumn<QLatin1String>("needleL1");
QTest::addColumn<qsizetype>("startpos");
QTest::addColumn<qsizetype>("resultCS");
QTest::addColumn<qsizetype>("resultCIS");
constexpr qsizetype zeroPos = 0;
constexpr qsizetype minus1Pos = -1;
QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
<< null << QLatin1String() << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
<< null << QLatin1String() << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << minus1Pos << zeroPos << zeroPos;
QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
<< empty << QLatin1String("") << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << minus1Pos << zeroPos << zeroPos;
QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
<< empty << QLatin1String("") << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("")
<< a << QLatin1String("a") << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: null, needle: a") << null << QLatin1String()
<< a << QLatin1String("a") << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << qsizetype(1) << qsizetype(1) << qsizetype(1);
QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << qsizetype(1) << qsizetype(1) << qsizetype(1);
QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << qsizetype(2) << minus1Pos << minus1Pos;
QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << qsizetype(2) << minus1Pos << minus1Pos;
#define ROW(h, n, st, cs, cis) \
QTest::addRow("haystack: %s, needle: %s", #h, #n) << h << QLatin1String(#h) \
<< n << QLatin1String(#n) \
<< qsizetype(st) << qsizetype(cs) << qsizetype(cis)
ROW(asd, asdf, -1, -1, -1);
ROW(ABCDEFGHIEfGEFG, G, -1, 14, 14);
ROW(ABCDEFGHIEfGEFG, g, -1, -1, 14);
ROW(ABCDEFGHIEfGEFG, G, -3, 11, 11);
ROW(ABCDEFGHIEfGEFG, g, -3, -1, 11);
ROW(ABCDEFGHIEfGEFG, G, -5, 6, 6);
ROW(ABCDEFGHIEfGEFG, g, -5, -1, 6);
ROW(ABCDEFGHIEfGEFG, G, 14, 14, 14);
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, B, 14, 1, 1);
ROW(ABCDEFGHIEfGEFG, b, 14, -1, 1);
ROW(ABCDEFGHIEfGEFG, B, -1, 1, 1);
ROW(ABCDEFGHIEfGEFG, b, -1, -1, 1);
ROW(ABCDEFGHIEfGEFG, B, 1, 1, 1);
ROW(ABCDEFGHIEfGEFG, b, 1, -1, 1);
ROW(ABCDEFGHIEfGEFG, B, 0, -1, -1);
ROW(ABCDEFGHIEfGEFG, b, 0, -1, -1);
ROW(ABCDEFGHIEfGEFG, A, 0, 0, 0);
ROW(ABCDEFGHIEfGEFG, a, 0, -1, 0);
ROW(ABCDEFGHIEfGEFG, A, -15, 0, 0);
ROW(ABCDEFGHIEfGEFG, a, -15, -1, 0);
ROW(ABCDEFGHIEfGEFG, efg, 0, -1, -1);
ROW(ABCDEFGHIEfGEFG, efg, 15, -1, -1);
ROW(ABCDEFGHIEfGEFG, efg, -15, -1, -1);
ROW(ABCDEFGHIEfGEFG, efg, 14, -1, 12);
ROW(ABCDEFGHIEfGEFG, efg, 12, -1, 12);
ROW(ABCDEFGHIEfGEFG, efg, -12, -1, -1);
ROW(ABCDEFGHIEfGEFG, efg, 11, -1, 9);
#undef ROW
}
template <typename Haystack, typename Needle>
void tst_QStringApiSymmetry::lastIndexOf_impl() const
{
QFETCH(const QString, haystackU16);
QFETCH(const QLatin1String, haystackL1);
QFETCH(const QString, needleU16);
QFETCH(const QLatin1String, needleL1);
QFETCH(const qsizetype, startpos);
QFETCH(const qsizetype, resultCS);
QFETCH(const qsizetype, resultCIS);
const auto haystackU8 = haystackU16.toUtf8();
const auto needleU8 = needleU16.toUtf8();
const auto haystack = make<Haystack>(QStringRef(&haystackU16), haystackL1, haystackU8);
const auto needle = make<Needle>(QStringRef(&needleU16), needleL1, needleU8);
using size_type = typename Haystack::size_type;
QCOMPARE(haystack.lastIndexOf(needle, startpos), size_type(resultCS));
QCOMPARE(haystack.lastIndexOf(needle, startpos, Qt::CaseSensitive), size_type(resultCS));
QCOMPARE(haystack.lastIndexOf(needle, startpos, Qt::CaseInsensitive), size_type(resultCIS));
if (needle.size() == 1)
{
QCOMPARE(haystack.lastIndexOf(needle[0], startpos), size_type(resultCS));
QCOMPARE(haystack.lastIndexOf(needle[0], startpos, Qt::CaseSensitive), size_type(resultCS));
QCOMPARE(haystack.lastIndexOf(needle[0], startpos, Qt::CaseInsensitive), size_type(resultCIS));
}
}
QTEST_APPLESS_MAIN(tst_QStringApiSymmetry)
#include "tst_qstringapisymmetry.moc"