diff options
Diffstat (limited to 'src/corelib/tools/qstring.cpp')
-rw-r--r-- | src/corelib/tools/qstring.cpp | 834 |
1 files changed, 485 insertions, 349 deletions
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 20cc799d31..029499039c 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. @@ -44,7 +45,7 @@ #include "qregularexpression.h" #endif #include "qunicodetables_p.h" -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) #include <qtextcodec.h> #endif #include <private/qutfcodec_p.h> @@ -142,19 +143,11 @@ 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 qt_last_index_of(QStringView haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs); +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 +155,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 +201,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 { @@ -254,7 +247,7 @@ inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, /*! * \internal * - * Searches for character \a \c in the string \a str and returns a pointer to + * Searches for character \a c in the string \a str and returns a pointer to * it. Unlike strchr() and wcschr() (but like glibc's strchrnul()), if the * character is not found, this function returns a pointer to the end of the * string -- that is, \c{str.end()}. @@ -265,16 +258,46 @@ const ushort *QtPrivate::qustrchr(QStringView str, ushort c) noexcept const ushort *e = reinterpret_cast<const ushort *>(str.end()); #ifdef __SSE2__ + bool loops = true; + // Using the PMOVMSKB instruction, we get two bits for each character + // we compare. +# if defined(__AVX2__) && !defined(__OPTIMIZE_SIZE__) + // we're going to read n[0..15] (32 bytes) + __m256i mch256 = _mm256_set1_epi32(c | (c << 16)); + for (const ushort *next = n + 16; next <= e; n = next, next += 16) { + __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n)); + __m256i result = _mm256_cmpeq_epi16(data, mch256); + uint mask = uint(_mm256_movemask_epi8(result)); + if (mask) { + uint idx = qCountTrailingZeroBits(mask); + return n + idx / 2; + } + } + loops = false; + __m128i mch = _mm256_castsi256_si128(mch256); +# else __m128i mch = _mm_set1_epi32(c | (c << 16)); +# endif + + auto hasMatch = [mch, &n](__m128i data, ushort validityMask) { + __m128i result = _mm_cmpeq_epi16(data, mch); + uint mask = uint(_mm_movemask_epi8(result)); + if ((mask & validityMask) == 0) + return false; + uint idx = qCountTrailingZeroBits(mask); + n += idx / 2; + return true; + }; // we're going to read n[0..7] (16 bytes) for (const ushort *next = n + 8; next <= e; n = next, next += 8) { __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(n)); - __m128i result = _mm_cmpeq_epi16(data, mch); - uint mask = _mm_movemask_epi8(result); - if (ushort(mask)) { - // found a match - return n + (qCountTrailingZeroBits(mask) >> 1); + if (hasMatch(data, 0xffff)) + return n; + + if (!loops) { + n += 8; + break; } } @@ -282,12 +305,8 @@ const ushort *QtPrivate::qustrchr(QStringView str, ushort c) noexcept // we're going to read n[0..3] (8 bytes) if (e - n > 3) { __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(n)); - __m128i result = _mm_cmpeq_epi16(data, mch); - uint mask = _mm_movemask_epi8(result); - if (uchar(mask)) { - // found a match - return n + (qCountTrailingZeroBits(mask) >> 1); - } + if (hasMatch(data, 0xff)) + return n; n += 4; } @@ -415,11 +434,26 @@ static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval) return true; } + +static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr) +{ + const __m128i *dataptr = static_cast<const __m128i *>(ptr); +#if defined(__SSE4_1__) + // use a MOVQ followed by PMOVZXBW + // if AVX2 is present, these should combine into a single VPMOVZXBW instruction + __m128i data = _mm_loadl_epi64(dataptr); + return _mm_cvtepu8_epi16(data); +# else + // use MOVQ followed by PUNPCKLBW + __m128i data = _mm_loadl_epi64(dataptr); + return _mm_unpacklo_epi8(data, _mm_setzero_si128()); +# endif +} #endif // 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 @@ -460,7 +494,11 @@ bool qt_is_ascii(const char *&ptr, const char *end) Q_DECL_NOTHROW while (ptr + 4 <= end) { quint32 data = qFromUnaligned<quint32>(ptr); if (data &= 0x80808080U) { +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + uint idx = qCountLeadingZeroBits(data); +#else uint idx = qCountTrailingZeroBits(data); +#endif ptr += idx / 8; return false; } @@ -475,7 +513,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(); @@ -502,7 +540,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(); @@ -510,7 +548,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(); @@ -550,7 +588,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 @@ -585,8 +623,7 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW // we're going to read str[offset..offset+7] (8 bytes) if (str + offset + 7 < e) { - const __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(str + offset)); - const __m128i unpacked = _mm_unpacklo_epi8(chunk, _mm_setzero_si128()); + const __m128i unpacked = mm_load8_zero_extend(str + offset); _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), unpacked); offset += 8; } @@ -594,7 +631,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 @@ -711,9 +748,15 @@ static void qt_to_latin1_internal(uchar *dst, const ushort *src, qsizetype lengt } length = length % 4; +# else + length = length % 16; +# endif // optimize size + + // advance dst, src for tail processing dst += offset; src += offset; +# if !defined(__OPTIMIZE_SIZE__) return UnrollTailLoop<3>::exec(length, [=](int i) { if (Checked) dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i]; @@ -854,6 +897,19 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) const QChar *end = a + l; qptrdiff offset = 0; + // Using the PMOVMSKB instruction, we get two bits for each character + // we compare. + int retval; + auto isDifferent = [a, b, &offset, &retval](__m128i a_data, __m128i b_data) { + __m128i result = _mm_cmpeq_epi16(a_data, b_data); + uint mask = ~uint(_mm_movemask_epi8(result)); + if (ushort(mask) == 0) + return false; + uint idx = qCountTrailingZeroBits(mask); + retval = a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode(); + return true; + }; + // we're going to read a[0..15] and b[0..15] (32 bytes) for ( ; a + offset + 16 <= end; offset += 16) { #ifdef __AVX2__ @@ -882,13 +938,8 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) if (a + offset + 8 <= end) { __m128i a_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset)); __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset)); - __m128i result = _mm_cmpeq_epi16(a_data, b_data); - uint mask = ~_mm_movemask_epi8(result); - if (ushort(mask)) { - // found a different character - uint idx = qCountTrailingZeroBits(mask); - return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode(); - } + if (isDifferent(a_data, b_data)) + return retval; offset += 8; } @@ -897,13 +948,8 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) if (a + offset + 4 <= end) { __m128i a_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(a + offset)); __m128i b_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(b + offset)); - __m128i result = _mm_cmpeq_epi16(a_data, b_data); - uint mask = ~_mm_movemask_epi8(result); - if (uchar(mask)) { - // found a different character - uint idx = qCountTrailingZeroBits(mask); - return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode(); - } + if (isDifferent(a_data, b_data)) + return retval; offset += 4; } @@ -998,6 +1044,21 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l) __m128i nullmask = _mm_setzero_si128(); qptrdiff offset = 0; +# if !defined(__OPTIMIZE_SIZE__) + // Using the PMOVMSKB instruction, we get two bits for each character + // we compare. + int retval; + auto isDifferent = [uc, c, &offset, &retval](__m128i a_data, __m128i b_data) { + __m128i result = _mm_cmpeq_epi16(a_data, b_data); + uint mask = ~uint(_mm_movemask_epi8(result)); + if (ushort(mask) == 0) + return false; + uint idx = qCountTrailingZeroBits(mask); + retval = uc[offset + idx / 2] - c[offset + idx / 2]; + return true; + }; +# endif + // we're going to read uc[offset..offset+15] (32 bytes) // and c[offset..offset+15] (16 bytes) for ( ; uc + offset + 15 < e; offset += 16) { @@ -1038,17 +1099,11 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l) // we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes) if (uc + offset + 7 < e) { // same, but we're using an 8-byte load - __m128i chunk = _mm_loadl_epi64((const __m128i*)(c + offset)); - __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask); + __m128i secondHalf = mm_load8_zero_extend(c + offset); __m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset)); - __m128i result = _mm_cmpeq_epi16(secondHalf, ucdata); - uint mask = ~_mm_movemask_epi8(result); - if (ushort(mask)) { - // found a different character - uint idx = qCountTrailingZeroBits(mask); - return uc[offset + idx / 2] - c[offset + idx / 2]; - } + if (isDifferent(ucdata, secondHalf)) + return retval; // still matched offset += 8; @@ -1061,22 +1116,19 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l) __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask); __m128i ucdata = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(uc + offset)); - __m128i result = _mm_cmpeq_epi8(secondHalf, ucdata); - uint mask = ~_mm_movemask_epi8(result); - if (uchar(mask)) { - // found a different character - uint idx = qCountTrailingZeroBits(mask); - return uc[offset + idx / 2] - c[offset + idx / 2]; - } + if (isDifferent(ucdata, secondHalf)) + return retval; // still matched offset += 4; } +# endif // optimize size // reset uc and c uc += offset; c += offset; +# if !defined(__OPTIMIZE_SIZE__) const auto lambda = [=](size_t i) { return uc[i] - ushort(c[i]); }; return UnrollTailLoop<MaxTailLength>::exec(e - uc, 0, lambda, lambda); # endif @@ -1093,7 +1145,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 : @@ -1117,7 +1169,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()); @@ -1125,7 +1177,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()); @@ -1133,12 +1185,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()); @@ -1163,7 +1215,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); } @@ -1183,7 +1235,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); } @@ -1203,7 +1255,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); } @@ -1223,47 +1275,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) @@ -1297,7 +1316,7 @@ const QString::Null QString::null = { }; literals and 8-bit data to unicode QStrings, but allows the use of the \c{QChar(char)} and \c{QString(const char (&ch)[N]} constructors, and the \c{QString::operator=(const char (&ch)[N])} assignment operator - giving most of the type-safety benefits of QT_NO_CAST_FROM_ASCII + giving most of the type-safety benefits of \c QT_NO_CAST_FROM_ASCII but does not require user code to wrap character and string literals with QLatin1Char, QLatin1String or similar. @@ -1413,7 +1432,7 @@ const QString::Null QString::null = { }; In all of the QString functions that take \c{const char *} parameters, the \c{const char *} is interpreted as a classic C-style '\\0'-terminated string encoded in UTF-8. It is legal for - the \c{const char *} parameter to be 0. + the \c{const char *} parameter to be \nullptr. You can also provide string data as an array of \l{QChar}s: @@ -1952,13 +1971,13 @@ const QString::Null QString::null = { }; can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. - \note Defining QT_RESTRICTED_CAST_FROM_ASCII also disables + \note Defining \c QT_RESTRICTED_CAST_FROM_ASCII also disables this constructor, but enables a \c{QString(const char (&ch)[N])} constructor instead. Using non-literal input, or input with embedded NUL characters, or non-7-bit characters is undefined in this case. - \sa fromLatin1(), fromLocal8Bit(), fromUtf8() + \sa fromLatin1(), fromLocal8Bit(), fromUtf8(), QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII */ /*! \fn QString QString::fromStdString(const std::string &str) @@ -1986,7 +2005,7 @@ const QString::Null QString::null = { }; the size of wchar. If wchar is 4 bytes, the \a string is interpreted as UCS-4, if wchar is 2 bytes it is interpreted as UTF-16. - If \a size is -1 (default), the \a string has to be 0 terminated. + If \a size is -1 (default), the \a string has to be \\0'-terminated. \sa fromUtf16(), fromLatin1(), fromLocal8Bit(), fromUtf8(), fromUcs4(), fromStdWString() */ @@ -2031,7 +2050,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) @@ -2052,7 +2071,7 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out) If \a unicode is 0, a null string is constructed. - If \a size is negative, \a unicode is assumed to point to a nul-terminated + If \a size is negative, \a unicode is assumed to point to a \\0'-terminated array and its length is determined dynamically. The terminating nul-character is not considered part of the string. @@ -2151,7 +2170,7 @@ QString::QString(QChar ch) can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. - \sa fromLatin1(), fromLocal8Bit(), fromUtf8() + \sa fromLatin1(), fromLocal8Bit(), fromUtf8(), QT_NO_CAST_FROM_ASCII */ /*! \fn QString::QString(const Null &) @@ -2352,7 +2371,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()) @@ -2399,6 +2418,8 @@ QString &QString::operator=(QLatin1String other) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::operator=(const char *str) @@ -2413,6 +2434,7 @@ QString &QString::operator=(QLatin1String other) This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII */ /*! \fn QString &QString::operator=(char ch) @@ -2427,6 +2449,8 @@ QString &QString::operator=(QLatin1String other) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -2489,8 +2513,10 @@ QString &QString::operator=(QChar ch) If the given \a position is greater than size(), the array is first extended using resize(). - This function is not available when QT_NO_CAST_FROM_ASCII is + This function is not available when \c QT_NO_CAST_FROM_ASCII is defined. + + \sa QT_NO_CAST_FROM_ASCII */ @@ -2505,8 +2531,10 @@ QString &QString::operator=(QChar ch) If the given \a position is greater than size(), the array is first extended using resize(). - This function is not available when QT_NO_CAST_FROM_ASCII is + This function is not available when \c QT_NO_CAST_FROM_ASCII is defined. + + \sa QT_NO_CAST_FROM_ASCII */ @@ -2671,6 +2699,8 @@ QString &QString::append(QLatin1String str) when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::append(const char *str) @@ -2684,6 +2714,8 @@ QString &QString::append(QLatin1String str) when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -2746,6 +2778,8 @@ QString &QString::append(QChar ch) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::prepend(const char *str) @@ -2759,6 +2793,8 @@ QString &QString::append(QChar ch) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::prepend(QChar ch) @@ -3321,7 +3357,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; @@ -3334,7 +3370,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; @@ -3357,6 +3393,8 @@ bool QString::operator==(QLatin1String other) const Q_DECL_NOTHROW Returns \c true if this string is lexically equal to the parameter string \a other. Otherwise returns \c false. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QString::operator==(const char *other) const @@ -3370,6 +3408,8 @@ bool QString::operator==(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -3382,7 +3422,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; } @@ -3393,7 +3433,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; } @@ -3410,6 +3450,8 @@ bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QString::operator<(const char *other) const @@ -3426,6 +3468,8 @@ bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool operator<=(const QString &s1, const QString &s2) @@ -3461,6 +3505,8 @@ bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QString::operator<=(const char *other) const @@ -3474,6 +3520,8 @@ bool QString::operator<(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool operator>(const QString &s1, const QString &s2) @@ -3494,7 +3542,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; } @@ -3511,6 +3559,8 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QString::operator>(const char *other) const @@ -3524,6 +3574,8 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool operator>=(const QString &s1, const QString &s2) @@ -3558,6 +3610,8 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QString::operator>=(const char *other) const @@ -3571,6 +3625,8 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool operator!=(const QString &s1, const QString &s2) @@ -3605,6 +3661,8 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QString::operator!=(const char *other) const @@ -3618,6 +3676,8 @@ bool QString::operator>(QLatin1String other) const Q_DECL_NOTHROW QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -3639,7 +3699,8 @@ 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: qsize + return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } /*! @@ -3663,85 +3724,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: qsize + return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs)); } /*! @@ -3753,7 +3737,8 @@ int qFindString( */ int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { - return findChar(unicode(), length(), ch, from, cs); + // ### Qt6: qsize + return int(QtPrivate::findChar(QStringView(unicode(), length()), ch, from, cs)); } /*! @@ -3770,7 +3755,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); + // ### Qt6: qsize + return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } static int lastIndexOfHelper(const ushort *haystack, int from, const ushort *needle, int sl, Qt::CaseSensitivity cs) @@ -3893,7 +3879,8 @@ 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: qsize + return int(qt_last_index_of(QStringView(unicode(), size()), ch, from, cs)); } /*! @@ -4226,7 +4213,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: qsize + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } /*! @@ -4242,8 +4230,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: qsize + return int(qt_string_count(QStringView(unicode(), size()), ch, cs)); +} /*! \since 4.8 @@ -4258,7 +4247,8 @@ 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: qsize + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } @@ -4472,7 +4462,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; } @@ -4528,7 +4518,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; } @@ -4571,7 +4561,7 @@ bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *ma QRegularExpressionMatch m = re.match(*this); bool hasMatch = m.hasMatch(); if (hasMatch && match) - *match = qMove(m); + *match = std::move(m); return hasMatch; } @@ -4731,7 +4721,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; }; @@ -5269,11 +5259,11 @@ static QByteArray qt_convert_to_local_8bit(QStringView string) { if (string.isNull()) return QByteArray(); -#ifndef QT_NO_TEXTCODEC +#if QT_CONFIG(textcodec) QTextCodec *localeCodec = QTextCodec::codecForLocale(); if (localeCodec) return localeCodec->fromUnicode(string); -#endif // QT_NO_TEXTCODEC +#endif // textcodec return qt_convert_to_latin1(string); } @@ -5352,7 +5342,7 @@ static QVector<uint> qt_convert_to_ucs4(QStringView string); this string is replaced by the Unicode's replacement character (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}). - The returned vector is not NUL terminated. + The returned vector is not \\0'-terminated. \sa fromUtf8(), toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec, fromUcs4(), toWCharArray() */ @@ -5384,7 +5374,7 @@ static QVector<uint> qt_convert_to_ucs4(QStringView string) this string is replaced by the Unicode's replacement character (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}). - The returned vector is not NUL terminated. + The returned vector is not \\0'-terminated. \sa QString::toUcs4(), QStringView::toUcs4(), QtPrivate::convertToLatin1(), QtPrivate::convertToLocal8Bit(), QtPrivate::convertToUtf8() @@ -5467,13 +5457,13 @@ QString QString::fromLocal8Bit_helper(const char *str, int size) QStringDataPtr empty = { Data::allocate(0) }; return QString(empty); } -#if !defined(QT_NO_TEXTCODEC) +#if QT_CONFIG(textcodec) if (size < 0) size = qstrlen(str); QTextCodec *codec = QTextCodec::codecForLocale(); if (codec) return codec->toUnicode(str, size); -#endif // !QT_NO_TEXTCODEC +#endif // textcodec return fromLatin1(str, size); } @@ -5542,8 +5532,7 @@ QString QString::fromUtf8_helper(const char *str, int size) Returns a QString initialized with the first \a size characters of the Unicode string \a unicode (ISO-10646-UTF-16 encoded). - If \a size is -1 (default), \a unicode must be terminated - with a 0. + If \a size is -1 (default), \a unicode must be \\0'-terminated. This function checks for a Byte Order Mark (BOM). If it is missing, host byte order is assumed. @@ -5574,8 +5563,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) Returns a QString initialized with the first \a size characters of the Unicode string \a str (ISO-10646-UTF-16 encoded). - If \a size is -1 (default), \a str must be terminated - with a 0. + If \a size is -1 (default), \a str must be \\0'-terminated. This function checks for a Byte Order Mark (BOM). If it is missing, host byte order is assumed. @@ -5595,8 +5583,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) Returns a QString initialized with the first \a size characters of the Unicode string \a str (ISO-10646-UCS-4 encoded). - If \a size is -1 (default), \a str must be terminated - with a 0. + If \a size is -1 (default), \a str must be \\0'-terminated. \sa toUcs4(), fromUtf16(), utf16(), setUtf16(), fromWCharArray(), fromStdU32String() */ @@ -5607,8 +5594,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) Returns a QString initialized with the first \a size characters of the Unicode string \a unicode (ISO-10646-UCS-4 encoded). - If \a size is -1 (default), \a unicode must be terminated - with a 0. + If \a size is -1 (default), \a unicode must be \\0'-terminated. \sa toUcs4(), fromUtf16(), utf16(), setUtf16(), fromWCharArray(), fromStdU32String() */ @@ -5686,7 +5672,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(); @@ -5710,12 +5696,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); } @@ -6011,6 +5997,8 @@ QString& QString::fill(QChar ch, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::operator+=(const char *str) @@ -6024,6 +6012,8 @@ QString& QString::fill(QChar ch, int size) when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::operator+=(const QStringRef &str) @@ -6045,6 +6035,8 @@ QString& QString::fill(QChar ch, int size) when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn QString &QString::operator+=(QChar ch) @@ -6247,7 +6239,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); } @@ -6258,7 +6250,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); @@ -6273,7 +6265,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); } @@ -6319,7 +6311,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); @@ -6621,7 +6613,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 { @@ -6679,7 +6671,7 @@ static QString convertCase(T &str) return detachAndConvertCase<Traits>(str, it); } } - return qMove(str); + return std::move(str); } } // namespace QUnicodeTables @@ -6733,6 +6725,7 @@ QString QString::toUpper_helper(QString &str) return QUnicodeTables::convertCase<QUnicodeTables::UppercaseTraits>(str); } +#if QT_DEPRECATED_SINCE(5, 14) /*! \obsolete @@ -6746,6 +6739,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. /*! @@ -6791,6 +6785,7 @@ QString QString::asprintf(const char *cformat, ...) return s; } +#if QT_DEPRECATED_SINCE(5, 14) /*! \obsolete @@ -6800,6 +6795,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) { @@ -6809,7 +6805,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) { @@ -6846,7 +6842,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; @@ -6855,7 +6851,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; @@ -7131,7 +7127,7 @@ QString QString::vasprintf(const char *cformat, va_list ap) base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7173,7 +7169,7 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7217,7 +7213,7 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7248,7 +7244,7 @@ long QString::toLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7278,7 +7274,7 @@ ulong QString::toULong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7307,7 +7303,7 @@ int QString::toInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7336,7 +7332,7 @@ uint QString::toUInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7365,7 +7361,7 @@ short QString::toShort(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -7393,9 +7389,10 @@ ushort QString::toUShort(bool *ok, int base) const /*! Returns the string converted to a \c double value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. \snippet qstring/main.cpp 66 @@ -7431,9 +7428,10 @@ double QString::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. \warning The QString content may only contain valid numerical characters @@ -7678,10 +7676,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; @@ -7966,10 +7964,7 @@ QVector<QStringRef> QString::splitRef(const QRegularExpression &re, SplitBehavio Example: - \code - QString str("ab"); - str.repeated(4); // returns "abababab" - \endcode + \snippet code/src_corelib_tools_qstring.cpp 8 */ QString QString::repeated(int times) const { @@ -8819,7 +8814,7 @@ namespace { struct Part { Part() : stringRef(), number(0) {} - Part(const QString &s, int pos, int len, int num = -1) Q_DECL_NOTHROW + Part(const QString &s, int pos, int len, int num = -1) noexcept : stringRef(&s, pos, len), number(num) {} QStringRef stringRef; @@ -9223,7 +9218,7 @@ QString &QString::setRawData(const QChar *unicode, int size) in the first place. In those cases, using QStringLiteral may be the better option. - \sa QString, QLatin1Char, {QStringLiteral()}{QStringLiteral} + \sa QString, QLatin1Char, {QStringLiteral()}{QStringLiteral}, QT_NO_CAST_FROM_ASCII */ /*! @@ -9341,11 +9336,11 @@ QString &QString::setRawData(const QChar *unicode, int size) The range \c{[first,last)} must remain valid for the lifetime of this Latin-1 string object. - Passing \c nullptr as \a first is safe if \a last is \c nullptr, + Passing \nullptr as \a first is safe if \a last is \nullptr, too, and results in a null Latin-1 string. The behavior is undefined if \a last precedes \a first, \a first - is \c nullptr and \a last is not, or if \c{last - first > + is \nullptr and \a last is not, or if \c{last - first > INT_MAX}. */ @@ -9700,6 +9695,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9714,6 +9711,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QLatin1String::operator!=(const QString &other) const @@ -9739,6 +9738,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9753,6 +9754,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9779,6 +9782,8 @@ QString &QString::setRawData(const QChar *unicode, int size) when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9793,6 +9798,8 @@ QString &QString::setRawData(const QChar *unicode, int size) when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9819,6 +9826,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9833,6 +9842,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9859,6 +9870,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9873,6 +9886,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \fn bool QLatin1String::operator<=(const QString &other) const @@ -9898,6 +9913,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -9912,6 +9929,8 @@ QString &QString::setRawData(const QChar *unicode, int size) QT_NO_CAST_FROM_ASCII when you compile your applications. This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + + \sa QT_NO_CAST_FROM_ASCII */ @@ -10229,7 +10248,7 @@ ownership of it, no memory is freed when instances are destroyed. Returns a Unicode representation of the string reference. Since the data stems directly from the referenced string, it is not - null-terminated unless the string reference includes the string's + \\0'-terminated unless the string reference includes the string's null terminator. \sa string() @@ -10364,7 +10383,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; } @@ -10374,7 +10393,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; } @@ -10384,7 +10403,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; @@ -10403,7 +10422,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; } @@ -10540,6 +10559,7 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if this string is lexically equal to the parameter string \a s. Otherwise returns \c false. + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -10557,6 +10577,8 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if this string is not lexically equal to the parameter string \a s. Otherwise returns \c false. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -10574,6 +10596,8 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if this string is lexically smaller than the parameter string \a s. Otherwise returns \c false. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -10591,6 +10615,8 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if this string is lexically smaller than or equal to the parameter string \a s. Otherwise returns \c false. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -10609,6 +10635,8 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if this string is lexically greater than the parameter string \a s. Otherwise returns \c false. + + \sa QT_NO_CAST_FROM_ASCII */ /*! @@ -10626,6 +10654,8 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) Q_DECL_NOTHROW Returns \c true if this string is lexically greater than or equal to the parameter string \a s. Otherwise returns \c false. + + \sa QT_NO_CAST_FROM_ASCII */ /*! \typedef QString::Data @@ -11022,7 +11052,8 @@ 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: qsize + return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs)); } /*! @@ -11037,7 +11068,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: qsize + return int(QtPrivate::findChar(QStringView(unicode(), length()), ch, from, cs)); } /*! @@ -11057,7 +11089,8 @@ 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: qsize + return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs)); } /*! @@ -11076,7 +11109,8 @@ 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: qsize + return int(QtPrivate::findString(QStringView(unicode(), size()), from, QStringView(str.unicode(), str.size()), cs)); } /*! @@ -11109,7 +11143,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); + // ### Qt6: qsize + return int(qt_last_index_of(QStringView(unicode(), size()), ch, from, cs)); } template<typename T> @@ -11185,7 +11220,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: qsize + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } /*! @@ -11202,7 +11238,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: qsize + return int(qt_string_count(QStringView(unicode(), size()), ch, cs)); } /*! @@ -11219,7 +11256,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: qsize + return int(qt_string_count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs)); } /*! @@ -11456,16 +11494,16 @@ 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) +static inline qsizetype qt_last_index_of(QStringView haystack, QChar needle, + qsizetype from, Qt::CaseSensitivity cs) { - ushort c = needle.unicode(); if (from < 0) - from += haystackLen; - if (uint(from) >= uint(haystackLen)) + from += haystack.size(); + if (std::size_t(from) >= std::size_t(haystack.size())) return -1; if (from >= 0) { - const ushort *b = reinterpret_cast<const ushort*>(haystack); + 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) @@ -11483,30 +11521,28 @@ static inline int qt_last_index_of(const QChar *haystack, int haystackLen, QChar } -static inline int qt_string_count(const QChar *haystack, int haystackLen, - const QChar *needle, int needleLen, - Qt::CaseSensitivity cs) +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) @@ -11520,24 +11556,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. @@ -11589,28 +11609,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. @@ -11662,27 +11682,148 @@ 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); } /*! + \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. +*/ + +qsizetype QtPrivate::findChar(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 QtPrivate::findChar(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; +} + +qsizetype QtPrivate::findString(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept +{ + if (haystack.size() < needle.size()) + return -1; + + const char *latin1 = needle.latin1(); + const qsizetype len = needle.size(); + QVarLengthArray<ushort> s(len); + qt_from_latin1(s.data(), latin1, len); + + return QtPrivate::findString(haystack, from, QStringView(reinterpret_cast<const QChar*>(s.constData()), len), cs); +} + +/*! \since 4.8 Returns a Latin-1 representation of the string as a QByteArray. @@ -11760,7 +11901,7 @@ QByteArray QStringRef::toUtf8() const this string is replaced by the Unicode's replacement character (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}). - The returned vector is not NUL terminated. + The returned vector is not \\0'-terminated. \sa toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec */ @@ -11799,7 +11940,7 @@ QStringRef QStringRef::trimmed() const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11824,7 +11965,7 @@ qint64 QStringRef::toLongLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11851,7 +11992,7 @@ quint64 QStringRef::toULongLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11878,7 +12019,7 @@ long QStringRef::toLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11904,7 +12045,7 @@ ulong QStringRef::toULong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11929,7 +12070,7 @@ int QStringRef::toInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11954,7 +12095,7 @@ uint QStringRef::toUInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -11979,7 +12120,7 @@ short QStringRef::toShort(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string @@ -12003,9 +12144,10 @@ ushort QStringRef::toUShort(bool *ok, int base) const /*! Returns the string converted to a \c double value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. The string conversion will always happen in the 'C' locale. For locale @@ -12028,9 +12170,10 @@ double QStringRef::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - Returns 0.0 if the conversion fails. + Returns an infinity if the conversion overflows or 0.0 if the + conversion fails for other reasons (e.g. underflow). - If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + If \a ok is not \nullptr, failure is reported by setting *\a{ok} to \c false, and success by setting *\a{ok} to \c true. The string conversion will always happen in the 'C' locale. For locale @@ -12096,10 +12239,7 @@ QString QString::toHtmlEscaped() const If you have code that looks like this: - \code - // hasAttribute takes a QString argument - if (node.hasAttribute("http-contents-length")) //... - \endcode + \snippet code/src_corelib_tools_qstring.cpp 9 then a temporary QString will be created to be passed as the \c{hasAttribute} function parameter. This can be quite expensive, as it involves a memory @@ -12108,9 +12248,7 @@ QString QString::toHtmlEscaped() const This cost can be avoided by using QStringLiteral instead: - \code - if (node.hasAttribute(QStringLiteral(u"http-contents-length"))) //... - \endcode + \snippet code/src_corelib_tools_qstring.cpp 10 In this case, QString's internal data will be generated at compile time; no conversion or allocation will occur at runtime. @@ -12125,9 +12263,7 @@ QString QString::toHtmlEscaped() const instance, QString::operator==() can compare to a QLatin1String directly: - \code - if (attribute.name() == QLatin1String("http-contents-length")) //... - \endcode + \snippet code/src_corelib_tools_qstring.cpp 11 \note Some compilers have bugs encoding strings containing characters outside the US-ASCII character set. Make sure you prefix your string with \c{u} in @@ -12139,7 +12275,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)); } |