diff options
Diffstat (limited to 'src/corelib/tools/qstring.cpp')
-rw-r--r-- | src/corelib/tools/qstring.cpp | 1106 |
1 files changed, 702 insertions, 404 deletions
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index a0e33d4e45..47db97cdfc 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -2,6 +2,7 @@ ** ** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2018 Intel Corporation. +** Copyright (C) 2019 Mail.ru Group. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -142,19 +143,13 @@ extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const ushort *src, int leng #endif // internal -int qFindString(const QChar *haystack, int haystackLen, int from, - const QChar *needle, int needleLen, Qt::CaseSensitivity cs); -int qFindStringBoyerMoore(const QChar *haystack, int haystackLen, int from, - const QChar *needle, int needleLen, Qt::CaseSensitivity cs); -static inline int qt_last_index_of(const QChar *haystack, int haystackLen, QChar needle, - int from, Qt::CaseSensitivity cs); -static inline int qt_string_count(const QChar *haystack, int haystackLen, - const QChar *needle, int needleLen, - Qt::CaseSensitivity cs); -static inline int qt_string_count(const QChar *haystack, int haystackLen, - QChar needle, Qt::CaseSensitivity cs); -static inline int qt_find_latin1_string(const QChar *hay, int size, QLatin1String needle, - int from, Qt::CaseSensitivity cs); +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; +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); + static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs); static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs); static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs); @@ -162,7 +157,7 @@ static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::Ca static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs); static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs); -qsizetype QtPrivate::qustrlen(const ushort *str) Q_DECL_NOTHROW +qsizetype QtPrivate::qustrlen(const ushort *str) noexcept { qsizetype result = 0; @@ -208,7 +203,7 @@ qsizetype QtPrivate::qustrlen(const ushort *str) Q_DECL_NOTHROW return result; } -#if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__) +#if !defined(__OPTIMIZE_SIZE__) namespace { template <uint MaxCount> struct UnrollTailLoop { @@ -460,7 +455,7 @@ static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr) // Note: ptr on output may be off by one and point to a preceding US-ASCII // character. Usually harmless. -bool qt_is_ascii(const char *&ptr, const char *end) Q_DECL_NOTHROW +bool qt_is_ascii(const char *&ptr, const char *end) noexcept { #if defined(__SSE2__) // Testing for the high bit can be done efficiently with just PMOVMSKB @@ -520,7 +515,7 @@ bool qt_is_ascii(const char *&ptr, const char *end) Q_DECL_NOTHROW return true; } -bool QtPrivate::isAscii(QLatin1String s) Q_DECL_NOTHROW +bool QtPrivate::isAscii(QLatin1String s) noexcept { const char *ptr = s.begin(); const char *end = s.end(); @@ -547,7 +542,7 @@ static bool isAscii(const QChar *&ptr, const QChar *end) return true; } -bool QtPrivate::isAscii(QStringView s) Q_DECL_NOTHROW +bool QtPrivate::isAscii(QStringView s) noexcept { const QChar *ptr = s.begin(); const QChar *end = s.end(); @@ -555,7 +550,7 @@ bool QtPrivate::isAscii(QStringView s) Q_DECL_NOTHROW return isAscii(ptr, end); } -bool QtPrivate::isLatin1(QStringView s) Q_DECL_NOTHROW +bool QtPrivate::isLatin1(QStringView s) noexcept { const QChar *ptr = s.begin(); const QChar *end = s.end(); @@ -595,7 +590,7 @@ bool QtPrivate::isLatin1(QStringView s) Q_DECL_NOTHROW } // conversion between Latin 1 and UTF-16 -void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW +void qt_from_latin1(ushort *dst, const char *str, size_t size) noexcept { /* SIMD: * Unpacking with SSE has been shown to improve performance on recent CPUs @@ -638,7 +633,7 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW size = size % 8; dst += offset; str += offset; -# if defined(Q_COMPILER_LAMBDA) && !defined(__OPTIMIZE_SIZE__) +# if !defined(__OPTIMIZE_SIZE__) return UnrollTailLoop<7>::exec(int(size), [=](int i) { dst[i] = (uchar)str[i]; }); # endif #endif @@ -833,9 +828,9 @@ static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QCha uint alast = 0; uint blast = 0; while (a < e) { -// qDebug() << hex << alast << blast; -// qDebug() << hex << "*a=" << *a << "alast=" << alast << "folded=" << foldCase (*a, alast); -// qDebug() << hex << "*b=" << *b << "blast=" << blast << "folded=" << foldCase (*b, blast); +// qDebug() << Qt::hex << alast << blast; +// qDebug() << Qt::hex << "*a=" << *a << "alast=" << alast << "folded=" << foldCase (*a, alast); +// qDebug() << Qt::hex << "*b=" << *b << "blast=" << blast << "folded=" << foldCase (*b, blast); int diff = foldCase(a->unicode(), alast) - foldCase(b->unicode(), blast); if ((diff)) return diff; @@ -1152,7 +1147,7 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l) } template <typename Number> -Q_DECL_CONSTEXPR int lencmp(Number lhs, Number rhs) Q_DECL_NOTHROW +Q_DECL_CONSTEXPR int lencmp(Number lhs, Number rhs) noexcept { return lhs == rhs ? 0 : lhs > rhs ? 1 : @@ -1176,7 +1171,7 @@ static int ucstrcmp(const QChar *a, size_t alen, const char *b, size_t blen) return cmp ? cmp : lencmp(alen, blen); } -static int qt_compare_strings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +static int qt_compare_strings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept { if (cs == Qt::CaseSensitive) return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size()); @@ -1184,7 +1179,7 @@ static int qt_compare_strings(QStringView lhs, QStringView rhs, Qt::CaseSensitiv return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } -static int qt_compare_strings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +static int qt_compare_strings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept { if (cs == Qt::CaseSensitive) return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size()); @@ -1192,12 +1187,12 @@ static int qt_compare_strings(QStringView lhs, QLatin1String rhs, Qt::CaseSensit return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } -static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept { return -qt_compare_strings(rhs, lhs, cs); } -static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept { if (cs == Qt::CaseInsensitive) return qstrnicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size()); @@ -1222,7 +1217,7 @@ static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSens of the characters and is very fast, but is not what a human would expect. Consider sorting user-visible strings with QString::localeAwareCompare(). */ -int QtPrivate::compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +int QtPrivate::compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept { return qt_compare_strings(lhs, rhs, cs); } @@ -1242,7 +1237,7 @@ int QtPrivate::compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitiv of the characters and is very fast, but is not what a human would expect. Consider sorting user-visible strings with QString::localeAwareCompare(). */ -int QtPrivate::compareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +int QtPrivate::compareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept { return qt_compare_strings(lhs, rhs, cs); } @@ -1262,7 +1257,7 @@ int QtPrivate::compareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensit of the characters and is very fast, but is not what a human would expect. Consider sorting user-visible strings with QString::localeAwareCompare(). */ -int QtPrivate::compareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +int QtPrivate::compareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept { return qt_compare_strings(lhs, rhs, cs); } @@ -1282,47 +1277,14 @@ int QtPrivate::compareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensit of the characters and is very fast, but is not what a human would expect. Consider sorting user-visible strings with QString::localeAwareCompare(). */ -int QtPrivate::compareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +int QtPrivate::compareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept { return qt_compare_strings(lhs, rhs, cs); } -/*! - \internal - - Returns the index position of the first occurrence of the - character \a ch in the string given by \a str and \a len, - searching forward from index - position \a from. Returns -1 if \a ch could not be found. -*/ -static int findChar(const QChar *str, int len, QChar ch, int from, - Qt::CaseSensitivity cs) -{ - const ushort *s = (const ushort *)str; - ushort c = ch.unicode(); - if (from < 0) - from = qMax(from + len, 0); - if (from < len) { - const ushort *n = s + from; - const ushort *e = s + len; - if (cs == Qt::CaseSensitive) { - n = QtPrivate::qustrchr(QStringView(n, e), c); - if (n != e) - return n - s; - } else { - c = foldCase(c); - --n; - while (++n != e) - if (foldCase(*n) == c) - return n - s; - } - } - return -1; -} - #define REHASH(a) \ - if (sl_minus_1 < sizeof(uint) * CHAR_BIT) \ - hashHaystack -= uint(a) << sl_minus_1; \ + if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \ + hashHaystack -= std::size_t(a) << sl_minus_1; \ hashHaystack <<= 1 inline bool qIsUpper(char ch) @@ -2107,7 +2069,7 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out) \note This function does not append a null character to the array. - \sa utf16(), toUcs4(), toLatin1(), toUtf8(), toLocal8Bit(), toStdWString() + \sa utf16(), toUcs4(), toLatin1(), toUtf8(), toLocal8Bit(), toStdWString(), QStringView::toWCharArray() */ /*! \fn QString::QString(const QString &other) @@ -2428,7 +2390,7 @@ void QString::expand(int i) string. */ -QString &QString::operator=(const QString &other) Q_DECL_NOTHROW +QString &QString::operator=(const QString &other) noexcept { other.d->ref.ref(); if (!d->ref.deref()) @@ -3101,7 +3063,7 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar { // Copy after if it lies inside our own d->data() area (which we could // possibly invalidate via a realloc or modify by replacement). - QChar *afterBuffer = 0; + QChar *afterBuffer = nullptr; if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original: after = afterBuffer = textCopy(after, alen); @@ -3186,7 +3148,7 @@ QString &QString::replace(const QChar *before, int blen, return *this; QStringMatcher matcher(before, blen, cs); - QChar *beforeBuffer = 0, *afterBuffer = 0; + QChar *beforeBuffer = nullptr, *afterBuffer = nullptr; int index = 0; while (1) { @@ -3414,7 +3376,7 @@ QString &QString::replace(QChar c, QLatin1String after, Qt::CaseSensitivity cs) expect. Consider sorting user-interface strings with localeAwareCompare(). */ -bool operator==(const QString &s1, const QString &s2) Q_DECL_NOTHROW +bool operator==(const QString &s1, const QString &s2) noexcept { if (s1.d->size != s2.d->size) return false; @@ -3427,7 +3389,7 @@ bool operator==(const QString &s1, const QString &s2) Q_DECL_NOTHROW Returns \c true if this string is equal to \a other; otherwise returns \c false. */ -bool QString::operator==(QLatin1String other) const Q_DECL_NOTHROW +bool QString::operator==(QLatin1String other) const noexcept { if (d->size != other.size()) return false; @@ -3479,7 +3441,7 @@ bool QString::operator==(QLatin1String other) const Q_DECL_NOTHROW expect. Consider sorting user-interface strings using the QString::localeAwareCompare() function. */ -bool operator<(const QString &s1, const QString &s2) Q_DECL_NOTHROW +bool operator<(const QString &s1, const QString &s2) noexcept { return qt_compare_strings(s1, s2, Qt::CaseSensitive) < 0; } @@ -3490,7 +3452,7 @@ bool operator<(const QString &s1, const QString &s2) Q_DECL_NOTHROW Returns \c true if this string is lexically less than the parameter string called \a other; otherwise returns \c false. */ -bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW +bool QString::operator<(QLatin1String other) const noexcept { return qt_compare_strings(*this, other, Qt::CaseSensitive) < 0; } @@ -3599,7 +3561,7 @@ bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW Returns \c true if this string is lexically greater than the parameter string \a other; otherwise returns \c false. */ -bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW +bool QString::operator>(QLatin1String other) const noexcept { return qt_compare_strings(*this, other, Qt::CaseSensitive) > 0; } @@ -3737,6 +3699,7 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW \sa QT_NO_CAST_FROM_ASCII */ +#if QT_STRINGVIEW_LEVEL < 2 /*! Returns the index position of the first occurrence of the string \a str in this string, searching forward from index position \a @@ -3756,8 +3719,28 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW */ int QString::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { - return qFindString(unicode(), length(), from, str.unicode(), str.length(), cs); + // ### Qt6: qsizetype + return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } +#endif // QT_STRINGVIEW_LEVEL < 2 + +/*! + \fn int QString::indexOf(QStringView str, int from, Qt::CaseSensitivity cs) const + \since 5.14 + \overload indexOf() + + Returns the index position of the first occurrence of the string view \a str + in this string, searching forward from index position \a from. + 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. + + If \a from is -1, the search starts at the last character; if it is + -2, at the next to last character and so on. + + \sa QStringView::indexOf(), lastIndexOf(), contains(), count() +*/ /*! \since 4.5 @@ -3780,85 +3763,8 @@ int QString::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const int QString::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - return qt_find_latin1_string(unicode(), size(), str, from, cs); -} - -int qFindString( - const QChar *haystack0, int haystackLen, int from, - const QChar *needle0, int needleLen, Qt::CaseSensitivity cs) -{ - const int l = haystackLen; - const int sl = needleLen; - if (from < 0) - from += l; - if (uint(sl + from) > (uint)l) - return -1; - if (!sl) - return from; - if (!l) - return -1; - - if (sl == 1) - return findChar(haystack0, haystackLen, needle0[0], from, cs); - - /* - We use the Boyer-Moore algorithm in cases where the overhead - for the skip table should pay off, otherwise we use a simple - hash function. - */ - if (l > 500 && sl > 5) - return qFindStringBoyerMoore(haystack0, haystackLen, from, - needle0, needleLen, cs); - - auto sv = [sl](const ushort *v) { return QStringView(v, sl); }; - /* - We use some hashing for efficiency's sake. Instead of - comparing strings, we compare the hash value of str with that - of a part of this QString. Only if that matches, we call - qt_string_compare(). - */ - const ushort *needle = (const ushort *)needle0; - const ushort *haystack = (const ushort *)haystack0 + from; - const ushort *end = (const ushort *)haystack0 + (l-sl); - const uint sl_minus_1 = sl - 1; - uint hashNeedle = 0, hashHaystack = 0; - int idx; - - if (cs == Qt::CaseSensitive) { - for (idx = 0; idx < sl; ++idx) { - hashNeedle = ((hashNeedle<<1) + needle[idx]); - hashHaystack = ((hashHaystack<<1) + haystack[idx]); - } - hashHaystack -= haystack[sl_minus_1]; - - while (haystack <= end) { - hashHaystack += haystack[sl_minus_1]; - if (hashHaystack == hashNeedle - && qt_compare_strings(sv(needle), sv(haystack), Qt::CaseSensitive) == 0) - return haystack - (const ushort *)haystack0; - - REHASH(*haystack); - ++haystack; - } - } else { - const ushort *haystack_start = (const ushort *)haystack0; - for (idx = 0; idx < sl; ++idx) { - hashNeedle = (hashNeedle<<1) + foldCase(needle + idx, needle); - hashHaystack = (hashHaystack<<1) + foldCase(haystack + idx, haystack_start); - } - hashHaystack -= foldCase(haystack + sl_minus_1, haystack_start); - - while (haystack <= end) { - hashHaystack += foldCase(haystack + sl_minus_1, haystack_start); - if (hashHaystack == hashNeedle - && qt_compare_strings(sv(needle), sv(haystack), Qt::CaseInsensitive) == 0) - return haystack - (const ushort *)haystack0; - - REHASH(foldCase(haystack, haystack_start)); - ++haystack; - } - } - return -1; + // ### Qt6: qsizetype + return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs)); } /*! @@ -3870,9 +3776,11 @@ int qFindString( */ int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - return findChar(unicode(), length(), ch, from, cs); + // ### Qt6: qsizetype + return int(qFindChar(QStringView(unicode(), length()), ch, from, cs)); } +#if QT_STRINGVIEW_LEVEL < 2 /*! \since 4.8 @@ -3887,74 +3795,8 @@ int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const */ int QString::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const { - return qFindString(unicode(), length(), from, str.unicode(), str.length(), cs); -} - -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); + // ### Qt6: qsizetype + return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } /*! @@ -3975,9 +3817,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: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } +#endif // QT_STRINGVIEW_LEVEL < 2 + /*! \since 4.5 \overload lastIndexOf() @@ -3999,7 +3844,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: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! @@ -4010,9 +3856,11 @@ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) co */ int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - return qt_last_index_of(unicode(), size(), ch, from, cs); + // ### Qt6: qsizetype + return int(qLastIndexOf(*this, ch, from, cs)); } +#if QT_STRINGVIEW_LEVEL < 2 /*! \since 4.8 \overload lastIndexOf() @@ -4030,8 +3878,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: qsizetype + 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)) @@ -4343,7 +4210,8 @@ QString &QString::replace(const QRegularExpression &re, const QString &after) int QString::count(const QString &str, Qt::CaseSensitivity cs) const { - return qt_string_count(unicode(), size(), str.unicode(), str.size(), cs); + // ### Qt6: qsizetype + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } /*! @@ -4359,8 +4227,9 @@ int QString::count(const QString &str, Qt::CaseSensitivity cs) const int QString::count(QChar ch, Qt::CaseSensitivity cs) const { - return qt_string_count(unicode(), size(), ch, cs); - } + // ### Qt6: qsizetype + return int(qt_string_count(QStringView(unicode(), size()), ch, cs)); +} /*! \since 4.8 @@ -4375,10 +4244,11 @@ int QString::count(QChar ch, Qt::CaseSensitivity cs) const */ int QString::count(const QStringRef &str, Qt::CaseSensitivity cs) const { - return qt_string_count(unicode(), size(), str.unicode(), str.size(), cs); + // ### Qt6: qsizetype + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } - +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QString::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const Returns \c true if this string contains an occurrence of the string @@ -4392,6 +4262,7 @@ int QString::count(const QStringRef &str, Qt::CaseSensitivity cs) const \sa indexOf(), count() */ +#endif // QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QString::contains(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const \since 5.3 @@ -4410,6 +4281,7 @@ int QString::count(const QStringRef &str, Qt::CaseSensitivity cs) const character \a ch; otherwise returns \c false. */ +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QString::contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const \since 4.8 @@ -4421,6 +4293,20 @@ int QString::count(const QStringRef &str, Qt::CaseSensitivity cs) const \sa indexOf(), count() */ +#endif // QT_STRINGVIEW_LEVEL < 2 + +/*! \fn bool QString::contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 5.14 + \overload contains() + + Returns \c true if this string contains an occurrence of the string view + \a str; otherwise returns \c false. + + If \a cs is Qt::CaseSensitive (default), the search is + case sensitive; otherwise the search is case insensitive. + + \sa indexOf(), count() +*/ /*! \fn bool QString::contains(const QRegExp &rx) const @@ -4589,7 +4475,7 @@ int QString::indexOf(const QRegularExpression &re, int from, QRegularExpressionM if (match.hasMatch()) { const int ret = match.capturedStart(); if (rmatch) - *rmatch = qMove(match); + *rmatch = std::move(match); return ret; } @@ -4645,7 +4531,7 @@ int QString::lastIndexOf(const QRegularExpression &re, int from, QRegularExpress if (start < endpos) { lastIndex = start; if (rmatch) - *rmatch = qMove(match); + *rmatch = std::move(match); } else { break; } @@ -4688,7 +4574,7 @@ bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *rm QRegularExpressionMatch m = re.match(*this); bool hasMatch = m.hasMatch(); if (hasMatch && rmatch) - *rmatch = qMove(m); + *rmatch = std::move(m); return hasMatch; } @@ -4848,7 +4734,7 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl class qt_section_chunk { public: qt_section_chunk() {} - qt_section_chunk(int l, QStringRef s) : length(l), string(qMove(s)) {} + qt_section_chunk(int l, QStringRef s) : length(l), string(std::move(s)) {} int length; QStringRef string; }; @@ -5680,7 +5566,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) while (unicode[size] != 0) ++size; } - return QUtf16::convertToUnicode((const char *)unicode, size*2, 0); + return QUtf16::convertToUnicode((const char *)unicode, size*2, nullptr); } /*! @@ -5734,7 +5620,7 @@ QString QString::fromUcs4(const uint *unicode, int size) while (unicode[size] != 0) ++size; } - return QUtf32::convertToUnicode((const char *)unicode, size*4, 0); + return QUtf32::convertToUnicode((const char *)unicode, size*4, nullptr); } @@ -5799,7 +5685,7 @@ QString QString::simplified_helper(QString &str) namespace { template <typename StringView> - StringView qt_trimmed(StringView s) Q_DECL_NOTHROW + StringView qt_trimmed(StringView s) noexcept { auto begin = s.begin(); auto end = s.end(); @@ -5823,12 +5709,12 @@ namespace { \sa QString::trimmed(), QStringView::trimmed(), QLatin1String::trimmed() */ -QStringView QtPrivate::trimmed(QStringView s) Q_DECL_NOTHROW +QStringView QtPrivate::trimmed(QStringView s) noexcept { return qt_trimmed(s); } -QLatin1String QtPrivate::trimmed(QLatin1String s) Q_DECL_NOTHROW +QLatin1String QtPrivate::trimmed(QLatin1String s) noexcept { return qt_trimmed(s); } @@ -5887,6 +5773,15 @@ QString QString::trimmed_helper(QString &str) were a QChar &. If you assign to it, the assignment will apply to the character in the QString from which you got the reference. + \note Before Qt 5.14 it was possible to use this operator to access + a character at an out-of-bounds position in the string, and + then assign to such a position, causing the string to be + automatically resized. Furthermore, assigning a value to the + returned QCharRef would cause a detach of the string, even if the + string has been copied in the meanwhile (and the QCharRef kept + alive while the copy was taken). These behaviors are deprecated, + and will be changed in a future version of Qt. + \sa at() */ @@ -6366,7 +6261,7 @@ QString& QString::fill(QChar ch, int size) Same as compare(*this, \a other, \a cs). */ -int QString::compare(const QString &other, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW +int QString::compare(const QString &other, Qt::CaseSensitivity cs) const noexcept { return qt_compare_strings(*this, other, cs); } @@ -6377,7 +6272,7 @@ int QString::compare(const QString &other, Qt::CaseSensitivity cs) const Q_DECL_ \since 4.5 */ int QString::compare_helper(const QChar *data1, int length1, const QChar *data2, int length2, - Qt::CaseSensitivity cs) Q_DECL_NOTHROW + Qt::CaseSensitivity cs) noexcept { Q_ASSERT(length1 >= 0); Q_ASSERT(length2 >= 0); @@ -6392,7 +6287,7 @@ int QString::compare_helper(const QChar *data1, int length1, const QChar *data2, Same as compare(*this, \a other, \a cs). */ -int QString::compare(QLatin1String other, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW +int QString::compare(QLatin1String other, Qt::CaseSensitivity cs) const noexcept { return qt_compare_strings(*this, other, cs); } @@ -6438,7 +6333,7 @@ int QString::compare_helper(const QChar *data1, int length1, const char *data2, \since 4.5 */ int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2, - Qt::CaseSensitivity cs) Q_DECL_NOTHROW + Qt::CaseSensitivity cs) noexcept { Q_ASSERT(length1 >= 0); Q_ASSERT(data1 || length1 == 0); @@ -6740,7 +6635,7 @@ Q_NEVER_INLINE static QString detachAndConvertCase(T &str, QStringIterator it) { Q_ASSERT(!str.isEmpty()); - QString s = qMove(str); // will copy if T is const QString + QString s = std::move(str); // will copy if T is const QString QChar *pp = s.begin() + it.index(); // will detach if necessary do { @@ -6798,7 +6693,7 @@ static QString convertCase(T &str) return detachAndConvertCase<Traits>(str, it); } } - return qMove(str); + return std::move(str); } } // namespace QUnicodeTables @@ -6852,6 +6747,7 @@ QString QString::toUpper_helper(QString &str) return QUnicodeTables::convertCase<QUnicodeTables::UppercaseTraits>(str); } +#if QT_DEPRECATED_SINCE(5, 14) /*! \obsolete @@ -6865,6 +6761,7 @@ QString &QString::sprintf(const char *cformat, ...) va_end(ap); return *this; } +#endif // ### Qt 6: Consider whether this function shouldn't be removed See task 202871. /*! @@ -6910,6 +6807,7 @@ QString QString::asprintf(const char *cformat, ...) return s; } +#if QT_DEPRECATED_SINCE(5, 14) /*! \obsolete @@ -6919,6 +6817,7 @@ QString &QString::vsprintf(const char *cformat, va_list ap) { return *this = vasprintf(cformat, ap); } +#endif static void append_utf8(QString &qs, const char *cs, int len) { @@ -6928,7 +6827,7 @@ static void append_utf8(QString &qs, const char *cs, int len) qs.resize(newEnd - qs.constData()); } -static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW +static uint parse_flag_characters(const char * &c) noexcept { uint flags = QLocaleData::ZeroPadExponent; while (true) { @@ -6965,7 +6864,7 @@ static int parse_field_width(const char * &c) enum LengthMod { lm_none, lm_hh, lm_h, lm_l, lm_ll, lm_L, lm_j, lm_z, lm_t }; -static inline bool can_consume(const char * &c, char ch) Q_DECL_NOTHROW +static inline bool can_consume(const char * &c, char ch) noexcept { if (*c == ch) { ++c; @@ -6974,7 +6873,7 @@ static inline bool can_consume(const char * &c, char ch) Q_DECL_NOTHROW return false; } -static LengthMod parse_length_modifier(const char * &c) Q_DECL_NOTHROW +static LengthMod parse_length_modifier(const char * &c) noexcept { switch (*c++) { case 'h': return can_consume(c, 'h') ? lm_hh : lm_h; @@ -7799,10 +7698,10 @@ static ResultList splitString(const StringSource &source, const QChar *sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs, const int separatorSize) { ResultList list; - int start = 0; - int end; - int extra = 0; - while ((end = qFindString(source.constData(), source.size(), start + extra, sep, separatorSize, cs)) != -1) { + typename StringSource::size_type start = 0; + typename StringSource::size_type end; + typename StringSource::size_type extra = 0; + while ((end = QtPrivate::findString(QStringView(source.constData(), source.size()), start + extra, QStringView(sep, separatorSize), cs)) != -1) { if (start != end || behavior == QString::KeepEmptyParts) list.append(source.mid(start, end - start)); start = end + separatorSize; @@ -8136,7 +8035,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar:: version = QChar::currentUnicodeVersion(); } else if (int(version) <= NormalizationCorrectionsVersionMax) { const QString &s = *data; - QChar *d = 0; + QChar *d = nullptr; for (int i = 0; i < NumNormalizationCorrections; ++i) { const NormalizationCorrection &n = uc_normalization_corrections[i]; if (n.version > version) { @@ -8873,19 +8772,23 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar); } -static int getEscape(const QChar *uc, int *pos, int len, int maxNumber = 999) +static inline ushort to_unicode(const QChar c) { return c.unicode(); } +static inline ushort to_unicode(const char c) { return QLatin1Char{c}.unicode(); } + +template <typename Char> +static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999) { int i = *pos; ++i; if (i < len && uc[i] == QLatin1Char('L')) ++i; if (i < len) { - int escape = uc[i].unicode() - '0'; + int escape = to_unicode(uc[i]) - '0'; if (uint(escape) >= 10U) return -1; ++i; while (i < len) { - int digit = uc[i].unicode() - '0'; + int digit = to_unicode(uc[i]) - '0'; if (uint(digit) >= 10U) break; escape = (escape * 10) + digit; @@ -8936,18 +8839,23 @@ static int getEscape(const QChar *uc, int *pos, int len, int maxNumber = 999) namespace { struct Part { - Part() : stringRef(), number(0) {} - Part(const QString &s, int pos, int len, int num = -1) Q_DECL_NOTHROW - : stringRef(&s, pos, len), number(num) {} + Part() = default; // for QVarLengthArray; do not use + Q_DECL_CONSTEXPR Part(QStringView s, int num = -1) + : tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {} + Q_DECL_CONSTEXPR Part(QLatin1String s, int num = -1) + : tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {} - QStringRef stringRef; + void reset(QStringView s) noexcept { *this = {s, number}; } + void reset(QLatin1String s) noexcept { *this = {s, number}; } + + QtPrivate::ArgBase::Tag tag; int number; + const void *data; + qsizetype size; }; } // unnamed namespace -template <> -class QTypeInfo<Part> : public QTypeInfoMerger<Part, QStringRef, int> {}; // Q_DECLARE_METATYPE - +Q_DECLARE_TYPEINFO(Part, Q_PRIMITIVE_TYPE); namespace { @@ -8956,24 +8864,25 @@ enum { ExpectedParts = 32 }; typedef QVarLengthArray<Part, ExpectedParts> ParseResult; typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap; -static ParseResult parseMultiArgFormatString(const QString &s) +template <typename StringView> +static ParseResult parseMultiArgFormatString(StringView s) { ParseResult result; - const QChar *uc = s.constData(); - const int len = s.size(); - const int end = len - 1; - int i = 0; - int last = 0; + const auto uc = s.data(); + const auto len = s.size(); + const auto end = len - 1; + qsizetype i = 0; + qsizetype last = 0; while (i < end) { if (uc[i] == QLatin1Char('%')) { - int percent = i; + qsizetype percent = i; int number = getEscape(uc, &i, len); if (number != -1) { if (last != percent) - result.push_back(Part(s, last, percent - last)); // literal text (incl. failed placeholders) - result.push_back(Part(s, percent, i - percent, number)); // parsed placeholder + result.push_back(Part{s.mid(last, percent - last)}); // literal text (incl. failed placeholders) + result.push_back(Part{s.mid(percent, i - percent), number}); // parsed placeholder last = i; continue; } @@ -8982,7 +8891,7 @@ static ParseResult parseMultiArgFormatString(const QString &s) } if (last < len) - result.push_back(Part(s, last, len - last)); // trailing literal text + result.push_back(Part{s.mid(last, len - last)}); // trailing literal text return result; } @@ -8991,9 +8900,9 @@ static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult & { ArgIndexToPlaceholderMap result; - for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) { - if (it->number >= 0) - result.push_back(it->number); + for (Part part : parts) { + if (part.number >= 0) + result.push_back(part.number); } std::sort(result.begin(), result.end()); @@ -9003,54 +8912,107 @@ static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult & return result; } -static int resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QString *args[]) +static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QtPrivate::ArgBase *args[]) { - int totalSize = 0; - for (ParseResult::iterator pit = parts.begin(), end = parts.end(); pit != end; ++pit) { - if (pit->number != -1) { - const ArgIndexToPlaceholderMap::const_iterator ait - = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), pit->number); - if (ait != argIndexToPlaceholderMap.end()) - pit->stringRef = QStringRef(args[ait - argIndexToPlaceholderMap.begin()]); + using namespace QtPrivate; + qsizetype totalSize = 0; + for (Part &part : parts) { + if (part.number != -1) { + const auto it = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), part.number); + if (it != argIndexToPlaceholderMap.end()) { + const auto &arg = *args[it - argIndexToPlaceholderMap.begin()]; + switch (arg.tag) { + case ArgBase::L1: + part.reset(static_cast<const QLatin1StringArg&>(arg).string); + break; + case ArgBase::U8: + Q_UNREACHABLE(); // waiting for QUtf8String... + break; + case ArgBase::U16: + part.reset(static_cast<const QStringViewArg&>(arg).string); + break; + } + } } - totalSize += pit->stringRef.size(); + totalSize += part.size; } return totalSize; } } // unnamed namespace +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QString QString::multiArg(int numArgs, const QString **args) const { + QVarLengthArray<QtPrivate::QStringViewArg, 9> sva; + sva.reserve(numArgs); + QVarLengthArray<const QtPrivate::ArgBase *, 9> pointers; + pointers.reserve(numArgs); + for (int i = 0; i < numArgs; ++i) { + sva.push_back(QtPrivate::qStringLikeToArg(*args[i])); + pointers.push_back(&sva.back()); + } + return QtPrivate::argToQString(qToStringViewIgnoringNull(*this), static_cast<size_t>(numArgs), pointers.data()); +} +#endif + +Q_ALWAYS_INLINE QString to_string(QLatin1String s) noexcept { return s; } +Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); } + +template <typename StringView> +static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args) +{ // Step 1-2 above - ParseResult parts = parseMultiArgFormatString(*this); + ParseResult parts = parseMultiArgFormatString(pattern); // 3-4 ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts); - if (argIndexToPlaceholderMap.size() > numArgs) // 3a - argIndexToPlaceholderMap.resize(numArgs); - else if (argIndexToPlaceholderMap.size() < numArgs) // 3b - qWarning("QString::arg: %d argument(s) missing in %s", - numArgs - argIndexToPlaceholderMap.size(), toLocal8Bit().data()); + if (static_cast<size_t>(argIndexToPlaceholderMap.size()) > numArgs) // 3a + argIndexToPlaceholderMap.resize(int(numArgs)); + else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b + qWarning("QString::arg: %d argument(s) missing in %ls", + int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern))); // 5 - const int totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args); + const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args); // 6: QString result(totalSize, Qt::Uninitialized); - QChar *out = result.data(); - - for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) { - if (const int sz = it->stringRef.size()) { - memcpy(out, it->stringRef.constData(), sz * sizeof(QChar)); - out += sz; + auto out = const_cast<QChar*>(result.constData()); + + for (Part part : parts) { + switch (part.tag) { + case QtPrivate::ArgBase::L1: + if (part.size) { + qt_from_latin1(reinterpret_cast<ushort*>(out), + reinterpret_cast<const char*>(part.data), part.size); + } + break; + case QtPrivate::ArgBase::U8: + Q_UNREACHABLE(); // waiting for QUtf8String + break; + case QtPrivate::ArgBase::U16: + if (part.size) + memcpy(out, part.data, part.size * sizeof(QChar)); + break; } + out += part.size; } return result; } +QString QtPrivate::argToQString(QStringView pattern, size_t n, const ArgBase **args) +{ + return argToQStringImpl(pattern, n, args); +} + +QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase **args) +{ + return argToQStringImpl(pattern, n, args); +} + /*! \fn bool QString::isSimpleText() const \internal @@ -9604,6 +9566,58 @@ QString &QString::setRawData(const QChar *unicode, int size) */ /*! + \fn int QLatin1String::indexOf(QStringView str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn int QLatin1String::indexOf(QLatin1String l1, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \fn int QLatin1String::indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 5.14 + + Returns the index position of the first occurrence of the string-view \a str, + Latin-1 string \a l1, or character \a ch, respectively, in this Latin-1 string, + searching forward from index position \a from. 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. + + If \a from is -1, the search starts at the last character; if it is + -2, at the next to last character and so on. + + \sa QString::indexOf() +*/ + +/*! + \fn bool QLatin1String::contains(QStringView str, Qt::CaseSensitivity cs) const + \fn bool QLatin1String::contains(QLatin1String l1, Qt::CaseSensitivity cs) const + \fn bool QLatin1String::contains(QChar c, Qt::CaseSensitivity cs) const + \since 5.14 + + Returns \c true if this Latin-1 string contains an occurrence of the string-view + \a str, Latin-1 string \a l1, or character \a ch; otherwise returns \c false. + + If \a cs is Qt::CaseSensitive (the default), the search is + case-sensitive; otherwise the search is case-insensitive. + + \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 @@ -10506,7 +10520,7 @@ QString QStringRef::toString() const { Returns \c true if string reference \a s1 is lexically equal to string reference \a s2; otherwise returns \c false. */ -bool operator==(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW +bool operator==(const QStringRef &s1,const QStringRef &s2) noexcept { return s1.size() == s2.size() && qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0; } @@ -10516,7 +10530,7 @@ bool operator==(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if string \a s1 is lexically equal to string reference \a s2; otherwise returns \c false. */ -bool operator==(const QString &s1,const QStringRef &s2) Q_DECL_NOTHROW +bool operator==(const QString &s1,const QStringRef &s2) noexcept { return s1.size() == s2.size() && qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0; } @@ -10526,7 +10540,7 @@ bool operator==(const QString &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if string \a s1 is lexically equal to string reference \a s2; otherwise returns \c false. */ -bool operator==(QLatin1String s1, const QStringRef &s2) Q_DECL_NOTHROW +bool operator==(QLatin1String s1, const QStringRef &s2) noexcept { if (s1.size() != s2.size()) return false; @@ -10545,7 +10559,7 @@ bool operator==(QLatin1String s1, const QStringRef &s2) Q_DECL_NOTHROW expect. Consider sorting user-interface strings using the QString::localeAwareCompare() function. */ -bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW +bool operator<(const QStringRef &s1,const QStringRef &s2) noexcept { return qt_compare_strings(s1, s2, Qt::CaseSensitive) < 0; } @@ -11158,6 +11172,7 @@ QStringRef QString::midRef(int position, int n) const \sa QString::chop(), truncate() */ +#if QT_STRINGVIEW_LEVEL < 2 /*! \since 4.8 @@ -11175,8 +11190,28 @@ QStringRef QString::midRef(int position, int n) const */ int QStringRef::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { - return qFindString(unicode(), length(), from, str.unicode(), str.length(), cs); + // ### Qt6: qsizetype + return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } +#endif // QT_STRINGVIEW_LEVEL < 2 + +/*! + \fn int QStringRef::indexOf(QStringView str, int from, Qt::CaseSensitivity cs) const + \since 5.14 + \overload indexOf() + + Returns the index position of the first occurrence of the string view \a str + in this string reference, searching forward from index position \a from. + 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. + + If \a from is -1, the search starts at the last character; if it is + -2, at the next to last character and so on. + + \sa QString::indexOf(), QStringView::indexOf(), lastIndexOf(), contains(), count() +*/ /*! \since 4.8 @@ -11190,7 +11225,8 @@ int QStringRef::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) co */ int QStringRef::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - return findChar(unicode(), length(), ch, from, cs); + // ### Qt6: qsizetype + return int(qFindChar(QStringView(unicode(), length()), ch, from, cs)); } /*! @@ -11210,9 +11246,11 @@ int QStringRef::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const */ int QStringRef::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const { - return qt_find_latin1_string(unicode(), size(), str, from, cs); + // ### Qt6: qsizetype + return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs)); } +#if QT_STRINGVIEW_LEVEL < 2 /*! \since 4.8 @@ -11229,8 +11267,10 @@ int QStringRef::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) con */ int QStringRef::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const { - return qFindString(unicode(), size(), from, str.unicode(), str.size(), cs); + // ### Qt6: qsizetype + return int(QtPrivate::findString(QStringView(unicode(), size()), from, QStringView(str.unicode(), str.size()), cs)); } +#endif // QT_STRINGVIEW_LEVEL < 2 /*! \since 4.8 @@ -11248,7 +11288,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: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! @@ -11262,28 +11303,8 @@ int QStringRef::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs */ int QStringRef::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - return qt_last_index_of(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); + // ### Qt6: qsizetype + return int(qLastIndexOf(*this, ch, from, cs)); } /*! @@ -11303,7 +11324,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: qsizetype + return int(QtPrivate::lastIndexOf(*this, from, str, cs)); } /*! @@ -11323,10 +11345,28 @@ 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: qsizetype + 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 the string \a str in this string reference. @@ -11338,7 +11378,8 @@ int QStringRef::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity */ int QStringRef::count(const QString &str, Qt::CaseSensitivity cs) const { - return qt_string_count(unicode(), size(), str.unicode(), str.size(), cs); + // ### Qt6: qsizetype + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } /*! @@ -11355,7 +11396,8 @@ int QStringRef::count(const QString &str, Qt::CaseSensitivity cs) const */ int QStringRef::count(QChar ch, Qt::CaseSensitivity cs) const { - return qt_string_count(unicode(), size(), ch, cs); + // ### Qt6: qsizetype + return int(qt_string_count(QStringView(unicode(), size()), ch, cs)); } /*! @@ -11372,7 +11414,8 @@ int QStringRef::count(QChar ch, Qt::CaseSensitivity cs) const */ int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const { - return qt_string_count(unicode(), size(), str.unicode(), str.size(), cs); + // ### Qt6: qsizetype + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } /*! @@ -11557,7 +11600,7 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const return qt_ends_with(*this, str, cs); } - +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QStringRef::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const \since 4.8 @@ -11569,6 +11612,7 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const \sa indexOf(), count() */ +#endif // QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QStringRef::contains(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const @@ -11583,6 +11627,7 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const */ +#if QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QStringRef::contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const \overload contains() \since 4.8 @@ -11595,6 +11640,7 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const \sa indexOf(), count() */ +#endif // QT_STRINGVIEW_LEVEL < 2 /*! \fn bool QStringRef::contains(QLatin1String str, Qt::CaseSensitivity cs) const \since 4.8 @@ -11609,57 +11655,41 @@ bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const \sa indexOf(), count() */ -static inline int qt_last_index_of(const QChar *haystack, int haystackLen, QChar needle, - int from, Qt::CaseSensitivity cs) -{ - ushort c = needle.unicode(); - if (from < 0) - from += haystackLen; - if (uint(from) >= uint(haystackLen)) - return -1; - if (from >= 0) { - const ushort *b = reinterpret_cast<const ushort*>(haystack); - 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; +/*! \fn bool QStringRef::contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const + \since 5.14 + \overload contains() + Returns \c true if this string reference contains an occurrence of + the string view \a str; otherwise returns \c false. -} + If \a cs is Qt::CaseSensitive (default), the search is + case sensitive; otherwise the search is case insensitive. -static inline int qt_string_count(const QChar *haystack, int haystackLen, - const QChar *needle, int needleLen, - Qt::CaseSensitivity cs) + \sa indexOf(), count() +*/ + +static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) { - int num = 0; - int i = -1; - if (haystackLen > 500 && needleLen > 5) { - QStringMatcher matcher(needle, needleLen, cs); - while ((i = matcher.indexIn(haystack, haystackLen, i + 1)) != -1) + qsizetype num = 0; + qsizetype i = -1; + if (haystack.size() > 500 && needle.size() > 5) { + QStringMatcher matcher(needle, cs); + while ((i = matcher.indexIn(haystack, i + 1)) != -1) ++num; } else { - while ((i = qFindString(haystack, haystackLen, i + 1, needle, needleLen, cs)) != -1) + while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1) ++num; } return num; } -static inline int qt_string_count(const QChar *unicode, int size, QChar ch, +static inline qsizetype qt_string_count(QStringView haystack, QChar ch, Qt::CaseSensitivity cs) { ushort c = ch.unicode(); - int num = 0; - const ushort *b = reinterpret_cast<const ushort*>(unicode); - const ushort *i = b + size; + qsizetype num = 0; + const ushort *b = reinterpret_cast<const ushort*>(haystack.data()); + const ushort *i = b + haystack.size(); if (cs == Qt::CaseSensitive) { while (i != b) if (*--i == c) @@ -11673,24 +11703,8 @@ static inline int qt_string_count(const QChar *unicode, int size, QChar ch, return num; } -static inline int qt_find_latin1_string(const QChar *haystack, int size, - QLatin1String needle, - int from, Qt::CaseSensitivity cs) -{ - if (size < needle.size()) - return -1; - - const char *latin1 = needle.latin1(); - int len = needle.size(); - QVarLengthArray<ushort> s(len); - qt_from_latin1(s.data(), latin1, len); - - return qFindString(haystack, size, from, - reinterpret_cast<const QChar*>(s.constData()), len, cs); -} - template <typename Haystack, typename Needle> -bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept { if (haystack.isNull()) return needle.isNull(); // historical behavior, consider changing in ### Qt 6. @@ -11742,28 +11756,28 @@ static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSe \sa QtPrivate::endsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1String::endsWith() */ -bool QtPrivate::startsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::startsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept { return qt_starts_with_impl(haystack, needle, cs); } -bool QtPrivate::startsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::startsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept { return qt_starts_with_impl(haystack, needle, cs); } -bool QtPrivate::startsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::startsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept { return qt_starts_with_impl(haystack, needle, cs); } -bool QtPrivate::startsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::startsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept { return qt_starts_with_impl(haystack, needle, cs); } template <typename Haystack, typename Needle> -bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept { if (haystack.isNull()) return needle.isNull(); // historical behavior, consider changing in ### Qt 6. @@ -11815,26 +11829,310 @@ static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSens \sa QtPrivate::startsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1String::endsWith() */ -bool QtPrivate::endsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::endsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept { return qt_ends_with_impl(haystack, needle, cs); } -bool QtPrivate::endsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::endsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept { return qt_ends_with_impl(haystack, needle, cs); } -bool QtPrivate::endsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::endsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept { return qt_ends_with_impl(haystack, needle, cs); } -bool QtPrivate::endsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) Q_DECL_NOTHROW +bool QtPrivate::endsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept { 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 + + Returns the index position of the first occurrence of the + character \a ch in the string given by \a str and \a len, + searching forward from index + position \a from. Returns -1 if \a ch could not be found. +*/ + +static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept +{ + if (from < 0) + from = qMax(from + str.size(), qsizetype(0)); + if (from < str.size()) { + const ushort *s = (const ushort *)str.data(); + ushort c = ch.unicode(); + const ushort *n = s + from; + const ushort *e = s + str.size(); + if (cs == Qt::CaseSensitive) { + n = QtPrivate::qustrchr(QStringView(n, e), c); + if (n != e) + return n - s; + } else { + c = foldCase(c); + --n; + while (++n != e) + if (foldCase(*n) == c) + return n - s; + } + } + return -1; +} + +qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringView needle0, Qt::CaseSensitivity cs) noexcept +{ + const qsizetype l = haystack0.size(); + const qsizetype sl = needle0.size(); + if (from < 0) + from += l; + if (std::size_t(sl + from) > std::size_t(l)) + return -1; + if (!sl) + return from; + if (!l) + return -1; + + if (sl == 1) + return qFindChar(haystack0, needle0[0], from, cs); + + /* + We use the Boyer-Moore algorithm in cases where the overhead + for the skip table should pay off, otherwise we use a simple + hash function. + */ + if (l > 500 && sl > 5) + return qFindStringBoyerMoore(haystack0, from, needle0, cs); + + auto sv = [sl](const ushort *v) { return QStringView(v, sl); }; + /* + We use some hashing for efficiency's sake. Instead of + comparing strings, we compare the hash value of str with that + of a part of this QString. Only if that matches, we call + qt_string_compare(). + */ + const ushort *needle = (const ushort *)needle0.data(); + const ushort *haystack = (const ushort *)(haystack0.data()) + from; + const ushort *end = (const ushort *)(haystack0.data()) + (l - sl); + const std::size_t sl_minus_1 = sl - 1; + std::size_t hashNeedle = 0, hashHaystack = 0; + qsizetype idx; + + if (cs == Qt::CaseSensitive) { + for (idx = 0; idx < sl; ++idx) { + hashNeedle = ((hashNeedle<<1) + needle[idx]); + hashHaystack = ((hashHaystack<<1) + haystack[idx]); + } + hashHaystack -= haystack[sl_minus_1]; + + while (haystack <= end) { + hashHaystack += haystack[sl_minus_1]; + if (hashHaystack == hashNeedle + && qt_compare_strings(needle0, sv(haystack), Qt::CaseSensitive) == 0) + return haystack - (const ushort *)haystack0.data(); + + REHASH(*haystack); + ++haystack; + } + } else { + const ushort *haystack_start = (const ushort *)haystack0.data(); + for (idx = 0; idx < sl; ++idx) { + hashNeedle = (hashNeedle<<1) + foldCase(needle + idx, needle); + hashHaystack = (hashHaystack<<1) + foldCase(haystack + idx, haystack_start); + } + hashHaystack -= foldCase(haystack + sl_minus_1, haystack_start); + + while (haystack <= end) { + hashHaystack += foldCase(haystack + sl_minus_1, haystack_start); + if (hashHaystack == hashNeedle + && qt_compare_strings(needle0, sv(haystack), Qt::CaseInsensitive) == 0) + return haystack - (const ushort *)haystack0.data(); + + REHASH(foldCase(haystack, haystack_start)); + ++haystack; + } + } + 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()) + return -1; + + QVarLengthArray<ushort> s(needle.size()); + qt_from_latin1(s.data(), needle.latin1(), needle.size()); + return QtPrivate::findString(haystack, from, QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), cs); +} + +qsizetype QtPrivate::findString(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept +{ + if (haystack.size() < needle.size()) + return -1; + + QVarLengthArray<ushort> s(haystack.size()); + qt_from_latin1(s.data(), haystack.latin1(), haystack.size()); + return QtPrivate::findString(QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), from, needle, cs); +} + +qsizetype QtPrivate::findString(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept +{ + if (haystack.size() < needle.size()) + return -1; + + QVarLengthArray<ushort> h(haystack.size()); + qt_from_latin1(h.data(), haystack.latin1(), haystack.size()); + QVarLengthArray<ushort> n(needle.size()); + qt_from_latin1(n.data(), needle.latin1(), needle.size()); + return QtPrivate::findString(QStringView(reinterpret_cast<const QChar*>(h.constData()), h.size()), from, + 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 @@ -12287,7 +12585,7 @@ QString QString::toHtmlEscaped() const /*! \internal */ -void QAbstractConcatenable::appendLatin1To(const char *a, int len, QChar *out) Q_DECL_NOTHROW +void QAbstractConcatenable::appendLatin1To(const char *a, int len, QChar *out) noexcept { qt_from_latin1(reinterpret_cast<ushort *>(out), a, uint(len)); } |