summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qstring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/text/qstring.cpp')
-rw-r--r--src/corelib/text/qstring.cpp5072
1 files changed, 2198 insertions, 2874 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 1694ea8dbe..fe9790403f 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -17,14 +17,16 @@
#include <qlist.h>
#include "qlocale.h"
#include "qlocale_p.h"
+#include "qspan.h"
#include "qstringbuilder.h"
#include "qstringmatcher.h"
#include "qvarlengtharray.h"
#include "qdebug.h"
#include "qendian.h"
#include "qcollator.h"
+#include "qttypetraits.h"
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
#include <private/qcore_mac_p.h>
#endif
@@ -38,35 +40,28 @@
#include <wchar.h>
#include "qchar.cpp"
+#include "qlatin1stringmatcher.h"
#include "qstringmatcher.cpp"
#include "qstringiterator_p.h"
#include "qstringalgorithms_p.h"
#include "qthreadstorage.h"
-#include "qbytearraymatcher.h" // Helper for comparison of QLatin1StringView
-
#include <algorithm>
#include <functional>
#ifdef Q_OS_WIN
# include <qt_windows.h>
+# if !defined(QT_BOOTSTRAPPED) && (defined(QT_NO_CAST_FROM_ASCII) || defined(QT_NO_CAST_TO_ASCII))
+// MSVC requires this, but let's apply it to MinGW compilers too, just in case
+# error "This file cannot be compiled with QT_NO_CAST_{TO,FROM}_ASCII, " \
+ "otherwise some QString functions will not get exported."
+# endif
#endif
#ifdef truncate
# undef truncate
#endif
-#ifndef LLONG_MAX
-#define LLONG_MAX qint64_C(9223372036854775807)
-#endif
-#ifndef LLONG_MIN
-#define LLONG_MIN (-LLONG_MAX - qint64_C(1))
-#endif
-#ifndef ULLONG_MAX
-#define ULLONG_MAX quint64_C(18446744073709551615)
-#endif
-
-#define IS_RAW_DATA(d) ((d.d)->flags & QArrayData::RawDataType)
#define REHASH(a) \
if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
hashHaystack -= std::size_t(a) << sl_minus_1; \
@@ -75,6 +70,7 @@
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
const char16_t QString::_empty = 0;
@@ -87,16 +83,6 @@ enum StringComparisonMode {
CompareStringsForOrdering
};
-inline bool qIsUpper(char ch)
-{
- return ch >= 'A' && ch <= 'Z';
-}
-
-inline bool qIsDigit(char ch)
-{
- return ch >= '0' && ch <= '9';
-}
-
template <typename Pointer>
char32_t foldCaseHelper(Pointer ch, Pointer start) = delete;
@@ -128,6 +114,12 @@ char16_t valueTypeToUtf16<char>(char t)
return char16_t{uchar(t)};
}
+template <typename T>
+static inline bool foldAndCompare(const T a, const T b)
+{
+ return foldCase(a) == b;
+}
+
/*!
\internal
@@ -136,32 +128,6 @@ char16_t valueTypeToUtf16<char>(char t)
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 > str.size())
- return -1;
- if (from < 0)
- from = qMax(from + str.size(), qsizetype(0));
- if (from < str.size()) {
- const char16_t *s = str.utf16();
- char16_t c = ch.unicode();
- const char16_t *n = s + from;
- const char16_t *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;
-}
-
template <typename Haystack>
static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
qsizetype from, Qt::CaseSensitivity cs) noexcept
@@ -268,7 +234,7 @@ bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity c
if (needleLen > haystackLen)
return false;
- return QtPrivate::compareStrings(haystack.left(needleLen), needle, cs) == 0;
+ return QtPrivate::compareStrings(haystack.first(needleLen), needle, cs) == 0;
}
template <typename Haystack, typename Needle>
@@ -283,7 +249,75 @@ bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs)
if (haystackLen < needleLen)
return false;
- return QtPrivate::compareStrings(haystack.right(needleLen), needle, cs) == 0;
+ return QtPrivate::compareStrings(haystack.last(needleLen), needle, cs) == 0;
+}
+
+template <typename T>
+static void append_helper(QString &self, T view)
+{
+ const auto strData = view.data();
+ const qsizetype strSize = view.size();
+ auto &d = self.data_ptr();
+ if (strData && strSize > 0) {
+ // the number of UTF-8 code units is always at a minimum equal to the number
+ // of equivalent UTF-16 code units
+ d.detachAndGrow(QArrayData::GrowsAtEnd, strSize, nullptr, nullptr);
+ Q_CHECK_PTR(d.data());
+ Q_ASSERT(strSize <= d.freeSpaceAtEnd());
+
+ auto dst = std::next(d.data(), d.size);
+ if constexpr (std::is_same_v<T, QUtf8StringView>) {
+ dst = QUtf8::convertToUnicode(dst, view);
+ } else if constexpr (std::is_same_v<T, QLatin1StringView>) {
+ QLatin1::convertToUnicode(dst, view);
+ dst += strSize;
+ } else {
+ static_assert(QtPrivate::type_dependent_false<T>(),
+ "Can only operate on UTF-8 and Latin-1");
+ }
+ self.resize(std::distance(d.begin(), dst));
+ } else if (d.isNull() && !view.isNull()) { // special case
+ self = QLatin1StringView("");
+ }
+}
+
+template <uint MaxCount> struct UnrollTailLoop
+{
+ template <typename RetType, typename Functor1, typename Functor2, typename Number>
+ static inline RetType exec(Number count, RetType returnIfExited, Functor1 loopCheck, Functor2 returnIfFailed, Number i = 0)
+ {
+ /* equivalent to:
+ * while (count--) {
+ * if (loopCheck(i))
+ * return returnIfFailed(i);
+ * }
+ * return returnIfExited;
+ */
+
+ if (!count)
+ return returnIfExited;
+
+ bool check = loopCheck(i);
+ if (check)
+ return returnIfFailed(i);
+
+ return UnrollTailLoop<MaxCount - 1>::exec(count - 1, returnIfExited, loopCheck, returnIfFailed, i + 1);
+ }
+
+ template <typename Functor, typename Number>
+ static inline void exec(Number count, Functor code)
+ {
+ /* equivalent to:
+ * for (Number i = 0; i < count; ++i)
+ * code(i);
+ */
+ exec(count, 0, [=](Number i) -> bool { code(i); return false; }, [](Number) { return 0; });
+ }
+};
+template <> template <typename RetType, typename Functor1, typename Functor2, typename Number>
+inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, Functor2, Number)
+{
+ return returnIfExited;
}
} // unnamed namespace
@@ -325,22 +359,37 @@ extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const char16_t *src, int le
#endif
#if defined(__SSE2__) && defined(Q_CC_GNU)
-# if defined(__SANITIZE_ADDRESS__) && Q_CC_GNU < 800 && !defined(Q_CC_CLANG)
-# warning "The __attribute__ on below will likely cause a build failure with your GCC version. Your choices are:"
-# warning "1) disable ASan;"
-# warning "2) disable the optimized code in qustrlen (change __SSE2__ to anything else);"
-# warning "3) upgrade your compiler (preferred)."
-# endif
-
// We may overrun the buffer, but that's a false positive:
// this won't crash nor produce incorrect results
-__attribute__((__no_sanitize_address__))
+# define ATTRIBUTE_NO_SANITIZE __attribute__((__no_sanitize_address__))
+#else
+# define ATTRIBUTE_NO_SANITIZE
#endif
-qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
+
+#ifdef __SSE2__
+static constexpr bool UseSse4_1 = bool(qCompilerCpuFeatures & CpuFeatureSSE4_1);
+static constexpr bool UseAvx2 = UseSse4_1 &&
+ (qCompilerCpuFeatures & CpuFeatureArchHaswell) == CpuFeatureArchHaswell;
+
+[[maybe_unused]]
+static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr)
{
- qsizetype result = 0;
+ const __m128i *dataptr = static_cast<const __m128i *>(ptr);
+ if constexpr (UseSse4_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);
+ }
-#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
+ // use MOVQ followed by PUNPCKLBW
+ __m128i data = _mm_loadl_epi64(dataptr);
+ return _mm_unpacklo_epi8(data, _mm_setzero_si128());
+}
+
+[[maybe_unused]] ATTRIBUTE_NO_SANITIZE
+static qsizetype qustrlen_sse2(const char16_t *str) noexcept
+{
// find the 16-byte alignment immediately prior or equal to str
quintptr misalignment = quintptr(str) & 0xf;
Q_ASSERT((misalignment & 1) == 0);
@@ -351,7 +400,7 @@ qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
const __m128i zeroes = _mm_setzero_si128();
__m128i data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr));
__m128i comparison = _mm_cmpeq_epi16(data, zeroes);
- quint32 mask = _mm_movemask_epi8(comparison);
+ uint mask = _mm_movemask_epi8(comparison);
// ignore the result prior to the beginning of str
mask >>= misalignment;
@@ -359,71 +408,272 @@ qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
// Have we found something in the first block? Need to handle it now
// because of the left shift above.
if (mask)
- return qCountTrailingZeroBits(quint32(mask)) / 2;
+ return qCountTrailingZeroBits(mask) / sizeof(char16_t);
+ constexpr qsizetype Step = sizeof(__m128i) / sizeof(char16_t);
+ qsizetype size = Step - misalignment / sizeof(char16_t);
+
+ size -= Step;
do {
- ptr += 8;
- data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr));
+ size += Step;
+ data = _mm_load_si128(reinterpret_cast<const __m128i *>(str + size));
comparison = _mm_cmpeq_epi16(data, zeroes);
mask = _mm_movemask_epi8(comparison);
} while (mask == 0);
// found a null
- uint idx = qCountTrailingZeroBits(quint32(mask));
- return ptr - str + idx / 2;
-#endif
+ return size + qCountTrailingZeroBits(mask) / sizeof(char16_t);
+}
- if (sizeof(wchar_t) == sizeof(char16_t))
- return wcslen(reinterpret_cast<const wchar_t *>(str));
+// Scans from \a ptr to \a end until \a maskval is non-zero. Returns true if
+// the no non-zero was found. Returns false and updates \a ptr to point to the
+// first 16-bit word that has any bit set (note: if the input is 8-bit, \a ptr
+// may be updated to one byte short).
+static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
+{
+ auto updatePtr = [&](uint result) {
+ // found a character matching the mask
+ uint idx = qCountTrailingZeroBits(~result);
+ ptr += idx;
+ return false;
+ };
- while (*str++)
- ++result;
- return result;
+ if constexpr (UseSse4_1) {
+# ifndef Q_OS_QNX // compiler fails in the code below
+ __m128i mask;
+ auto updatePtrSimd = [&](__m128i data) -> bool {
+ __m128i masked = _mm_and_si128(mask, data);
+ __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
+ uint result = _mm_movemask_epi8(comparison);
+ return updatePtr(result);
+ };
+
+ if constexpr (UseAvx2) {
+ // AVX2 implementation: test 32 bytes at a time
+ const __m256i mask256 = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(maskval));
+ while (ptr + 32 <= end) {
+ __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
+ if (!_mm256_testz_si256(mask256, data)) {
+ // found a character matching the mask
+ __m256i masked256 = _mm256_and_si256(mask256, data);
+ __m256i comparison256 = _mm256_cmpeq_epi16(masked256, _mm256_setzero_si256());
+ return updatePtr(_mm256_movemask_epi8(comparison256));
+ }
+ ptr += 32;
+ }
+
+ mask = _mm256_castsi256_si128(mask256);
+ } else {
+ // SSE 4.1 implementation: test 32 bytes at a time (two 16-byte
+ // comparisons, unrolled)
+ mask = _mm_set1_epi32(maskval);
+ while (ptr + 32 <= end) {
+ __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16));
+ if (!_mm_testz_si128(mask, data1))
+ return updatePtrSimd(data1);
+
+ ptr += 16;
+ if (!_mm_testz_si128(mask, data2))
+ return updatePtrSimd(data2);
+ ptr += 16;
+ }
+ }
+
+ // AVX2 and SSE4.1: final 16-byte comparison
+ if (ptr + 16 <= end) {
+ __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ if (!_mm_testz_si128(mask, data1))
+ return updatePtrSimd(data1);
+ ptr += 16;
+ }
+
+ // and final 8-byte comparison
+ if (ptr + 8 <= end) {
+ __m128i data1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ if (!_mm_testz_si128(mask, data1))
+ return updatePtrSimd(data1);
+ ptr += 8;
+ }
+
+ return true;
+# endif // QNX
+ }
+
+ // SSE2 implementation: test 16 bytes at a time.
+ const __m128i mask = _mm_set1_epi32(maskval);
+ while (ptr + 16 <= end) {
+ __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ __m128i masked = _mm_and_si128(mask, data);
+ __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
+ quint16 result = _mm_movemask_epi8(comparison);
+ if (result != 0xffff)
+ return updatePtr(result);
+ ptr += 16;
+ }
+
+ // and one 8-byte comparison
+ if (ptr + 8 <= end) {
+ __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ __m128i masked = _mm_and_si128(mask, data);
+ __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
+ quint8 result = _mm_movemask_epi8(comparison);
+ if (result != 0xff)
+ return updatePtr(result);
+ ptr += 8;
+ }
+
+ return true;
}
-#if !defined(__OPTIMIZE_SIZE__)
-namespace {
-template <uint MaxCount> struct UnrollTailLoop
+template <StringComparisonMode Mode, typename Char> [[maybe_unused]]
+static int ucstrncmp_sse2(const char16_t *a, const Char *b, size_t l)
{
- template <typename RetType, typename Functor1, typename Functor2, typename Number>
- static inline RetType exec(Number count, RetType returnIfExited, Functor1 loopCheck, Functor2 returnIfFailed, Number i = 0)
- {
- /* equivalent to:
- * while (count--) {
- * if (loopCheck(i))
- * return returnIfFailed(i);
- * }
- * return returnIfExited;
- */
+ static_assert(std::is_unsigned_v<Char>);
- if (!count)
- return returnIfExited;
+ // Using the PMOVMSKB instruction, we get two bits for each UTF-16 character
+ // we compare. This lambda helps extract the code unit.
+ static const auto codeUnitAt = [](const auto *n, qptrdiff idx) -> int {
+ constexpr int Stride = 2;
+ // this is the same as:
+ // return n[idx / Stride];
+ // but using pointer arithmetic to avoid the compiler dividing by two
+ // and multiplying by two in the case of char16_t (we know idx is even,
+ // but the compiler does not). This is not UB.
- bool check = loopCheck(i);
- if (check)
- return returnIfFailed(i);
+ auto ptr = reinterpret_cast<const uchar *>(n);
+ ptr += idx / (Stride / sizeof(*n));
+ return *reinterpret_cast<decltype(n)>(ptr);
+ };
+ auto difference = [a, b](uint mask, qptrdiff offset) {
+ if (Mode == CompareStringsForEquality)
+ return 1;
+ uint idx = qCountTrailingZeroBits(mask);
+ return codeUnitAt(a + offset, idx) - codeUnitAt(b + offset, idx);
+ };
- return UnrollTailLoop<MaxCount - 1>::exec(count - 1, returnIfExited, loopCheck, returnIfFailed, i + 1);
- }
+ static const auto load8Chars = [](const auto *ptr) {
+ if (sizeof(*ptr) == 2)
+ return _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ return _mm_unpacklo_epi8(chunk, _mm_setzero_si128());
+ };
+ static const auto load4Chars = [](const auto *ptr) {
+ if (sizeof(*ptr) == 2)
+ return _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
+ __m128i chunk = _mm_cvtsi32_si128(qFromUnaligned<quint32>(ptr));
+ return _mm_unpacklo_epi8(chunk, _mm_setzero_si128());
+ };
- template <typename Functor, typename Number>
- static inline void exec(Number count, Functor code)
- {
- /* equivalent to:
- * for (Number i = 0; i < count; ++i)
- * code(i);
- */
- exec(count, 0, [=](Number i) -> bool { code(i); return false; }, [](Number) { return 0; });
+ // we're going to read a[0..15] and b[0..15] (32 bytes)
+ auto processChunk16Chars = [a, b](qptrdiff offset) -> uint {
+ if constexpr (UseAvx2) {
+ __m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset));
+ __m256i b_data;
+ if (sizeof(Char) == 1) {
+ // expand to UTF-16 via zero-extension
+ __m128i chunk = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
+ b_data = _mm256_cvtepu8_epi16(chunk);
+ } else {
+ b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset));
+ }
+ __m256i result = _mm256_cmpeq_epi16(a_data, b_data);
+ return _mm256_movemask_epi8(result);
+ }
+
+ __m128i a_data1 = load8Chars(a + offset);
+ __m128i a_data2 = load8Chars(a + offset + 8);
+ __m128i b_data1, b_data2;
+ if (sizeof(Char) == 1) {
+ // expand to UTF-16 via unpacking
+ __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
+ b_data1 = _mm_unpacklo_epi8(b_data, _mm_setzero_si128());
+ b_data2 = _mm_unpackhi_epi8(b_data, _mm_setzero_si128());
+ } else {
+ b_data1 = load8Chars(b + offset);
+ b_data2 = load8Chars(b + offset + 8);
+ }
+ __m128i result1 = _mm_cmpeq_epi16(a_data1, b_data1);
+ __m128i result2 = _mm_cmpeq_epi16(a_data2, b_data2);
+ return _mm_movemask_epi8(result1) | _mm_movemask_epi8(result2) << 16;
+ };
+
+ if (l >= sizeof(__m256i) / sizeof(char16_t)) {
+ qptrdiff offset = 0;
+ for ( ; l >= offset + sizeof(__m256i) / sizeof(char16_t); offset += sizeof(__m256i) / sizeof(char16_t)) {
+ uint mask = ~processChunk16Chars(offset);
+ if (mask)
+ return difference(mask, offset);
+ }
+
+ // maybe overlap the last 32 bytes
+ if (size_t(offset) < l) {
+ offset = l - sizeof(__m256i) / sizeof(char16_t);
+ uint mask = ~processChunk16Chars(offset);
+ return mask ? difference(mask, offset) : 0;
+ }
+ } else if (l >= 4) {
+ __m128i a_data1, b_data1;
+ __m128i a_data2, b_data2;
+ int width;
+ if (l >= 8) {
+ width = 8;
+ a_data1 = load8Chars(a);
+ b_data1 = load8Chars(b);
+ a_data2 = load8Chars(a + l - width);
+ b_data2 = load8Chars(b + l - width);
+ } else {
+ // we're going to read a[0..3] and b[0..3] (8 bytes)
+ width = 4;
+ a_data1 = load4Chars(a);
+ b_data1 = load4Chars(b);
+ a_data2 = load4Chars(a + l - width);
+ b_data2 = load4Chars(b + l - width);
+ }
+
+ __m128i result = _mm_cmpeq_epi16(a_data1, b_data1);
+ ushort mask = ~_mm_movemask_epi8(result);
+ if (mask)
+ return difference(mask, 0);
+
+ result = _mm_cmpeq_epi16(a_data2, b_data2);
+ mask = ~_mm_movemask_epi8(result);
+ if (mask)
+ return difference(mask, l - width);
+ } else {
+ // reset l
+ l &= 3;
+
+ const auto lambda = [=](size_t i) -> int {
+ return a[i] - b[i];
+ };
+ return UnrollTailLoop<3>::exec(l, 0, lambda, lambda);
}
-};
-template <> template <typename RetType, typename Functor1, typename Functor2, typename Number>
-inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, Functor2, Number)
+ return 0;
+}
+#endif
+
+Q_NEVER_INLINE
+qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
{
- return returnIfExited;
+#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
+ return qustrlen_sse2(str);
+#endif
+
+ if (sizeof(wchar_t) == sizeof(char16_t))
+ return wcslen(reinterpret_cast<const wchar_t *>(str));
+
+ qsizetype result = 0;
+ while (*str++)
+ ++result;
+ return result;
}
+
+qsizetype QtPrivate::qustrnlen(const char16_t *str, qsizetype maxlen) noexcept
+{
+ return qustrchr({ str, maxlen }, u'\0') - str;
}
-#endif
/*!
* \internal
@@ -433,6 +683,7 @@ inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1,
* character is not found, this function returns a pointer to the end of the
* string -- that is, \c{str.end()}.
*/
+Q_NEVER_INLINE
const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
{
const char16_t *n = str.utf16();
@@ -442,23 +693,24 @@ const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
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 char16_t *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;
+ __m128i mch;
+ if constexpr (UseAvx2) {
+ // we're going to read n[0..15] (32 bytes)
+ __m256i mch256 = _mm256_set1_epi32(c | (c << 16));
+ for (const char16_t *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;
+ mch = _mm256_castsi256_si128(mch256);
+ } else {
+ mch = _mm_set1_epi32(c | (c << 16));
}
- 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);
@@ -493,8 +745,8 @@ const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
}
return UnrollTailLoop<3>::exec(e - n, e,
- [=](int i) { return n[i] == c; },
- [=](int i) { return n + i; });
+ [=](qsizetype i) { return n[i] == c; },
+ [=](qsizetype i) { return n + i; });
# endif
#elif defined(__ARM_NEON__)
const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
@@ -509,128 +761,25 @@ const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
}
#endif // aarch64
- --n;
- while (++n != e)
- if (*n == c)
- return n;
-
- return n;
-}
-
-#ifdef __SSE2__
-// Scans from \a ptr to \a end until \a maskval is non-zero. Returns true if
-// the no non-zero was found. Returns false and updates \a ptr to point to the
-// first 16-bit word that has any bit set (note: if the input is 8-bit, \a ptr
-// may be updated to one byte short).
-static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
-{
- auto updatePtr = [&](uint result) {
- // found a character matching the mask
- uint idx = qCountTrailingZeroBits(~result);
- ptr += idx;
- return false;
- };
-
-# if defined(__SSE4_1__)
- __m128i mask;
- auto updatePtrSimd = [&](__m128i data) {
- __m128i masked = _mm_and_si128(mask, data);
- __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
- uint result = _mm_movemask_epi8(comparison);
- return updatePtr(result);
- };
-
-# if defined(__AVX2__)
- // AVX2 implementation: test 32 bytes at a time
- const __m256i mask256 = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(maskval));
- while (ptr + 32 <= end) {
- __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
- if (!_mm256_testz_si256(mask256, data)) {
- // found a character matching the mask
- __m256i masked256 = _mm256_and_si256(mask256, data);
- __m256i comparison256 = _mm256_cmpeq_epi16(masked256, _mm256_setzero_si256());
- return updatePtr(_mm256_movemask_epi8(comparison256));
- }
- ptr += 32;
- }
-
- mask = _mm256_castsi256_si128(mask256);
-# else
- // SSE 4.1 implementation: test 32 bytes at a time (two 16-byte
- // comparisons, unrolled)
- mask = _mm_set1_epi32(maskval);
- while (ptr + 32 <= end) {
- __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
- __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16));
- if (!_mm_testz_si128(mask, data1))
- return updatePtrSimd(data1);
-
- ptr += 16;
- if (!_mm_testz_si128(mask, data2))
- return updatePtrSimd(data2);
- ptr += 16;
- }
-# endif
-
- // AVX2 and SSE4.1: final 16-byte comparison
- if (ptr + 16 <= end) {
- __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
- if (!_mm_testz_si128(mask, data1))
- return updatePtrSimd(data1);
- ptr += 16;
- }
-
- // and final 8-byte comparison
- if (ptr + 8 <= end) {
- __m128i data1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
- if (!_mm_testz_si128(mask, data1))
- return updatePtrSimd(data1);
- ptr += 8;
- }
-
-# else
- // SSE2 implementation: test 16 bytes at a time.
- const __m128i mask = _mm_set1_epi32(maskval);
- while (ptr + 16 <= end) {
- __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
- __m128i masked = _mm_and_si128(mask, data);
- __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
- quint16 result = _mm_movemask_epi8(comparison);
- if (result != 0xffff)
- return updatePtr(result);
- ptr += 16;
- }
-
- // and one 8-byte comparison
- if (ptr + 8 <= end) {
- __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
- __m128i masked = _mm_and_si128(mask, data);
- __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
- quint8 result = _mm_movemask_epi8(comparison);
- if (result != 0xff)
- return updatePtr(result);
- ptr += 8;
- }
-# endif
-
- return true;
+ return std::find(n, e, c);
}
-static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr)
+/*!
+ * \internal
+ *
+ * Searches case-insensitively for character \a c in the string \a str and
+ * returns a pointer to it. Iif the character is not found, this function
+ * returns a pointer to the end of the string -- that is, \c{str.end()}.
+ */
+Q_NEVER_INLINE
+const char16_t *QtPrivate::qustrcasechr(QStringView str, char16_t c) noexcept
{
- 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
+ const QChar *n = str.begin();
+ const QChar *e = str.end();
+ c = foldCase(c);
+ auto it = std::find_if(n, e, [c](auto ch) { return foldAndCompare(ch, QChar(c)); });
+ return reinterpret_cast<const char16_t *>(it);
}
-#endif
// Note: ptr on output may be off by one and point to a preceding US-ASCII
// character. Usually harmless.
@@ -639,19 +788,19 @@ 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
bool loops = true;
-# if defined(__AVX2__)
- while (ptr + 32 <= end) {
- __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
- quint32 mask = _mm256_movemask_epi8(data);
- if (mask) {
- uint idx = qCountTrailingZeroBits(mask);
- ptr += idx;
- return false;
+ if constexpr (UseAvx2) {
+ while (ptr + 32 <= end) {
+ __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
+ quint32 mask = _mm256_movemask_epi8(data);
+ if (mask) {
+ uint idx = qCountTrailingZeroBits(mask);
+ ptr += idx;
+ return false;
+ }
+ ptr += 32;
}
- ptr += 32;
+ loops = false;
}
- loops = false;
-# endif
while (ptr + 16 <= end) {
__m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
@@ -776,46 +925,63 @@ Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) n
* itself in exactly the same way as one would do it with intrinsics.
*/
#if defined(__SSE2__)
- const char *e = str + size;
- qptrdiff offset = 0;
-
// we're going to read str[offset..offset+15] (16 bytes)
- for ( ; str + offset + 15 < e; offset += 16) {
+ const __m128i nullMask = _mm_setzero_si128();
+ auto processOneChunk = [=](qptrdiff offset) {
const __m128i chunk = _mm_loadu_si128((const __m128i*)(str + offset)); // load
-#ifdef __AVX2__
- // zero extend to an YMM register
- const __m256i extended = _mm256_cvtepu8_epi16(chunk);
-
- // store
- _mm256_storeu_si256((__m256i*)(dst + offset), extended);
-#else
- const __m128i nullMask = _mm_set1_epi32(0);
+ if constexpr (UseAvx2) {
+ // zero extend to an YMM register
+ const __m256i extended = _mm256_cvtepu8_epi16(chunk);
- // unpack the first 8 bytes, padding with zeros
- const __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullMask);
- _mm_storeu_si128((__m128i*)(dst + offset), firstHalf); // store
+ // store
+ _mm256_storeu_si256((__m256i*)(dst + offset), extended);
+ } else {
+ // unpack the first 8 bytes, padding with zeros
+ const __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullMask);
+ _mm_storeu_si128((__m128i*)(dst + offset), firstHalf); // store
- // unpack the last 8 bytes, padding with zeros
- const __m128i secondHalf = _mm_unpackhi_epi8 (chunk, nullMask);
- _mm_storeu_si128((__m128i*)(dst + offset + 8), secondHalf); // store
-#endif
- }
+ // unpack the last 8 bytes, padding with zeros
+ const __m128i secondHalf = _mm_unpackhi_epi8 (chunk, nullMask);
+ _mm_storeu_si128((__m128i*)(dst + offset + 8), secondHalf); // store
+ }
+ };
- // we're going to read str[offset..offset+7] (8 bytes)
- if (str + offset + 7 < e) {
- const __m128i unpacked = mm_load8_zero_extend(str + offset);
- _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), unpacked);
- offset += 8;
+ const char *e = str + size;
+ if (size >= sizeof(__m128i)) {
+ qptrdiff offset = 0;
+ for ( ; str + offset + sizeof(__m128i) <= e; offset += sizeof(__m128i))
+ processOneChunk(offset);
+ if (str + offset < e)
+ processOneChunk(size - sizeof(__m128i));
+ return;
}
- size = size % 8;
- dst += offset;
- str += offset;
# if !defined(__OPTIMIZE_SIZE__)
- return UnrollTailLoop<7>::exec(int(size), [=](int i) { dst[i] = (uchar)str[i]; });
+ if (size >= 4) {
+ // two overlapped loads & stores, of either 64-bit or of 32-bit
+ if (size >= 8) {
+ const __m128i unpacked1 = mm_load8_zero_extend(str);
+ const __m128i unpacked2 = mm_load8_zero_extend(str + size - 8);
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), unpacked1);
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + size - 8), unpacked2);
+ } else {
+ const __m128i chunk1 = _mm_cvtsi32_si128(qFromUnaligned<quint32>(str));
+ const __m128i chunk2 = _mm_cvtsi32_si128(qFromUnaligned<quint32>(str + size - 4));
+ const __m128i unpacked1 = _mm_unpacklo_epi8(chunk1, nullMask);
+ const __m128i unpacked2 = _mm_unpacklo_epi8(chunk2, nullMask);
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), unpacked1);
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + size - 4), unpacked2);
+ }
+ return;
+ } else {
+ size = size % 4;
+ return UnrollTailLoop<3>::exec(qsizetype(size), [=](qsizetype i) { dst[i] = uchar(str[i]); });
+ }
# endif
#endif
#if defined(__mips_dsp)
+ static_assert(sizeof(qsizetype) == sizeof(int),
+ "oops, the assembler implementation needs to be called in a loop");
if (size > 20)
qt_fromlatin1_mips_asm_unroll8(dst, str, size);
else
@@ -826,31 +992,51 @@ Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) n
#endif
}
+static QVarLengthArray<char16_t> qt_from_latin1_to_qvla(QLatin1StringView str)
+{
+ const qsizetype len = str.size();
+ QVarLengthArray<char16_t> arr(len);
+ qt_from_latin1(arr.data(), str.data(), len);
+ return arr;
+}
+
template <bool Checked>
static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype length)
{
#if defined(__SSE2__)
- uchar *e = dst + length;
- qptrdiff offset = 0;
-
-# ifdef __AVX2__
- const __m256i questionMark256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128('?'));
- const __m256i outOfRange256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128(0x100));
- const __m128i questionMark = _mm256_castsi256_si128(questionMark256);
- const __m128i outOfRange = _mm256_castsi256_si128(outOfRange256);
-# else
- const __m128i questionMark = _mm_set1_epi16('?');
- const __m128i outOfRange = _mm_set1_epi16(0x100);
-# endif
+ auto questionMark256 = []() {
+ if constexpr (UseAvx2)
+ return _mm256_broadcastw_epi16(_mm_cvtsi32_si128('?'));
+ else
+ return 0;
+ }();
+ auto outOfRange256 = []() {
+ if constexpr (UseAvx2)
+ return _mm256_broadcastw_epi16(_mm_cvtsi32_si128(0x100));
+ else
+ return 0;
+ }();
+ __m128i questionMark, outOfRange;
+ if constexpr (UseAvx2) {
+ questionMark = _mm256_castsi256_si128(questionMark256);
+ outOfRange = _mm256_castsi256_si128(outOfRange256);
+ } else {
+ questionMark = _mm_set1_epi16('?');
+ outOfRange = _mm_set1_epi16(0x100);
+ }
auto mergeQuestionMarks = [=](__m128i chunk) {
+ if (!Checked)
+ return chunk;
+
// SSE has no compare instruction for unsigned comparison.
-# ifdef __SSE4_1__
- // We use an unsigned uc = qMin(uc, 0x100) and then compare for equality.
- chunk = _mm_min_epu16(chunk, outOfRange);
- const __m128i offLimitMask = _mm_cmpeq_epi16(chunk, outOfRange);
- chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
-# else
+ if constexpr (UseSse4_1) {
+ // We use an unsigned uc = qMin(uc, 0x100) and then compare for equality.
+ chunk = _mm_min_epu16(chunk, outOfRange);
+ const __m128i offLimitMask = _mm_cmpeq_epi16(chunk, outOfRange);
+ chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
+ return chunk;
+ }
// The variables must be shiffted + 0x8000 to be compared
const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000));
const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000));
@@ -870,90 +1056,99 @@ static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype len
chunk = _mm_or_si128(correctBytes, offLimitQuestionMark);
Q_UNUSED(outOfRange);
-# endif
return chunk;
};
- // we're going to write to dst[offset..offset+15] (16 bytes)
- for ( ; dst + offset + 15 < e; offset += 16) {
-# if defined(__AVX2__)
- __m256i chunk = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + offset));
- if (Checked) {
- // See mergeQuestionMarks lambda above for details
- chunk = _mm256_min_epu16(chunk, outOfRange256);
- const __m256i offLimitMask = _mm256_cmpeq_epi16(chunk, outOfRange256);
- chunk = _mm256_blendv_epi8(chunk, questionMark256, offLimitMask);
- }
+ // we're going to read to src[offset..offset+15] (16 bytes)
+ auto loadChunkAt = [=](qptrdiff offset) {
+ __m128i chunk1, chunk2;
+ if constexpr (UseAvx2) {
+ __m256i chunk = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + offset));
+ if (Checked) {
+ // See mergeQuestionMarks lambda above for details
+ chunk = _mm256_min_epu16(chunk, outOfRange256);
+ const __m256i offLimitMask = _mm256_cmpeq_epi16(chunk, outOfRange256);
+ chunk = _mm256_blendv_epi8(chunk, questionMark256, offLimitMask);
+ }
- const __m128i chunk2 = _mm256_extracti128_si256(chunk, 1);
- const __m128i chunk1 = _mm256_castsi256_si128(chunk);
-# else
- __m128i chunk1 = _mm_loadu_si128((const __m128i*)(src + offset)); // load
- if (Checked)
+ chunk2 = _mm256_extracti128_si256(chunk, 1);
+ chunk1 = _mm256_castsi256_si128(chunk);
+ } else {
+ chunk1 = _mm_loadu_si128((const __m128i*)(src + offset)); // load
chunk1 = mergeQuestionMarks(chunk1);
- __m128i chunk2 = _mm_loadu_si128((const __m128i*)(src + offset + 8)); // load
- if (Checked)
+ chunk2 = _mm_loadu_si128((const __m128i*)(src + offset + 8)); // load
chunk2 = mergeQuestionMarks(chunk2);
-# endif
+ }
// pack the two vector to 16 x 8bits elements
- const __m128i result = _mm_packus_epi16(chunk1, chunk2);
- _mm_storeu_si128((__m128i*)(dst + offset), result); // store
+ return _mm_packus_epi16(chunk1, chunk2);
+ };
+
+ if (size_t(length) >= sizeof(__m128i)) {
+ // because of possible overlapping, we won't process the last chunk in the loop
+ qptrdiff offset = 0;
+ for ( ; offset + 2 * sizeof(__m128i) < size_t(length); offset += sizeof(__m128i))
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), loadChunkAt(offset));
+
+ // overlapped conversion of the last full chunk and the tail
+ __m128i last1 = loadChunkAt(offset);
+ __m128i last2 = loadChunkAt(length - sizeof(__m128i));
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), last1);
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + length - sizeof(__m128i)), last2);
+ return;
}
# if !defined(__OPTIMIZE_SIZE__)
- // we're going to write to dst[offset..offset+7] (8 bytes)
- if (dst + offset + 7 < e) {
- __m128i chunk = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + offset));
- if (Checked)
- chunk = mergeQuestionMarks(chunk);
-
- // pack, where the upper half is ignored
- const __m128i result = _mm_packus_epi16(chunk, chunk);
- _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + offset), result);
- offset += 8;
- }
+ if (length >= 4) {
+ // this code is fine even for in-place conversion because we load both
+ // before any store
+ if (length >= 8) {
+ __m128i chunk1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
+ __m128i chunk2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + length - 8));
+ chunk1 = mergeQuestionMarks(chunk1);
+ chunk2 = mergeQuestionMarks(chunk2);
- // we're going to write to dst[offset..offset+3] (4 bytes)
- if (dst + offset + 3 < e) {
- __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src + offset));
- if (Checked)
- chunk = mergeQuestionMarks(chunk);
+ // pack, where the upper half is ignored
+ const __m128i result1 = _mm_packus_epi16(chunk1, chunk1);
+ const __m128i result2 = _mm_packus_epi16(chunk2, chunk2);
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), result1);
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + length - 8), result2);
+ } else {
+ __m128i chunk1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src));
+ __m128i chunk2 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src + length - 4));
+ chunk1 = mergeQuestionMarks(chunk1);
+ chunk2 = mergeQuestionMarks(chunk2);
- // pack, we'll the upper three quarters
- const __m128i result = _mm_packus_epi16(chunk, chunk);
- qToUnaligned(_mm_cvtsi128_si32(result), dst + offset);
- offset += 4;
+ // pack, we'll zero the upper three quarters
+ const __m128i result1 = _mm_packus_epi16(chunk1, chunk1);
+ const __m128i result2 = _mm_packus_epi16(chunk2, chunk2);
+ qToUnaligned(_mm_cvtsi128_si32(result1), dst);
+ qToUnaligned(_mm_cvtsi128_si32(result2), dst + length - 4);
+ }
+ return;
}
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) {
+ return UnrollTailLoop<3>::exec(length, [=](qsizetype i) {
if (Checked)
dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i];
else
dst[i] = src[i];
});
-# endif
+# else
+ length = length % 16;
+# endif // optimize size
#elif defined(__ARM_NEON__)
// Refer to the documentation of the SSE2 implementation.
// This uses exactly the same method as for SSE except:
// 1) neon has unsigned comparison
// 2) packing is done to 64 bits (8 x 8bits component).
if (length >= 16) {
- const int chunkCount = length >> 3; // divided by 8
+ const qsizetype chunkCount = length >> 3; // divided by 8
const uint16x8_t questionMark = vdupq_n_u16('?'); // set
const uint16x8_t thresholdMask = vdupq_n_u16(0xff); // set
- for (int i = 0; i < chunkCount; ++i) {
+ for (qsizetype i = 0; i < chunkCount; ++i) {
uint16x8_t chunk = vld1q_u16((uint16_t *)src); // load
src += 8;
@@ -971,6 +1166,8 @@ static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype len
}
#endif
#if defined(__mips_dsp)
+ static_assert(sizeof(qsizetype) == sizeof(int),
+ "oops, the assembler implementation needs to be called in a loop");
qt_toLatin1_mips_dsp_asm(dst, src, length);
#else
while (length--) {
@@ -997,7 +1194,7 @@ void qt_to_latin1_unchecked(uchar *dst, const char16_t *src, qsizetype length)
Q_NEVER_INLINE static int ucstricmp(qsizetype alen, const char16_t *a, qsizetype blen, const char16_t *b)
{
if (a == b)
- return (alen - blen);
+ return qt_lencmp(alen, blen);
char32_t alast = 0;
char32_t blast = 0;
@@ -1049,7 +1246,7 @@ Q_NEVER_INLINE static int ucstricmp8(const char *utf8, const char *utf8end, cons
char32_t uc1 = 0;
char32_t *output = &uc1;
uchar b = *src1++;
- int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, output, src1, end1);
+ const qsizetype res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, output, src1, end1);
if (res < 0) {
// decoding error
uc1 = QChar::ReplacementCharacter;
@@ -1078,6 +1275,10 @@ extern "C" int qt_ucstrncmp_mips_dsp_asm(const char16_t *a,
template <StringComparisonMode Mode>
static int ucstrncmp(const char16_t *a, const char16_t *b, size_t l)
{
+ // This function isn't memcmp() because that can return the wrong sorting
+ // result in little-endian architectures: 0x00ff must sort before 0x0100,
+ // but the bytes in memory are FF 00 and 00 01.
+
#ifndef __OPTIMIZE_SIZE__
# if defined(__mips_dsp)
static_assert(sizeof(uint) == sizeof(size_t));
@@ -1085,79 +1286,7 @@ static int ucstrncmp(const char16_t *a, const char16_t *b, size_t l)
return qt_ucstrncmp_mips_dsp_asm(a, b, l);
}
# elif defined(__SSE2__)
- const char16_t *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;
- if (Mode == CompareStringsForEquality) {
- retval = 1;
- } else {
- uint idx = qCountTrailingZeroBits(mask);
- retval = a[offset + idx / 2] - b[offset + idx / 2];
- }
- return true;
- };
-
- // we're going to read a[0..15] and b[0..15] (32 bytes)
- for ( ; end - a >= offset + 16; offset += 16) {
-#ifdef __AVX2__
- __m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset));
- __m256i b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset));
- __m256i result = _mm256_cmpeq_epi16(a_data, b_data);
- uint mask = _mm256_movemask_epi8(result);
-#else
- __m128i a_data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset));
- __m128i a_data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset + 8));
- __m128i b_data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
- __m128i b_data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset + 8));
- __m128i result1 = _mm_cmpeq_epi16(a_data1, b_data1);
- __m128i result2 = _mm_cmpeq_epi16(a_data2, b_data2);
- uint mask = _mm_movemask_epi8(result1) | (_mm_movemask_epi8(result2) << 16);
-#endif
- mask = ~mask;
- if (mask) {
- // found a different character
- if (Mode == CompareStringsForEquality)
- return 1;
- uint idx = qCountTrailingZeroBits(mask);
- return a[offset + idx / 2] - b[offset + idx / 2];
- }
- }
-
- // we're going to read a[0..7] and b[0..7] (16 bytes)
- if (end - a >= offset + 8) {
- __m128i a_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset));
- __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
- if (isDifferent(a_data, b_data))
- return retval;
-
- offset += 8;
- }
-
- // we're going to read a[0..3] and b[0..3] (8 bytes)
- if (end - a >= offset + 4) {
- __m128i a_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(a + offset));
- __m128i b_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(b + offset));
- if (isDifferent(a_data, b_data))
- return retval;
-
- offset += 4;
- }
-
- // reset l
- l &= 3;
-
- const auto lambda = [=](size_t i) -> int {
- return a[offset + i] - b[offset + i];
- };
- return UnrollTailLoop<3>::exec(l, 0, lambda, lambda);
+ return ucstrncmp_sse2<Mode>(a, b, l);
# elif defined(__ARM_NEON__)
if (l >= 8) {
const char16_t *end = a + l;
@@ -1186,6 +1315,9 @@ static int ucstrncmp(const char16_t *a, const char16_t *b, size_t l)
# endif // MIPS DSP or __SSE2__ or __ARM_NEON__
#endif // __OPTIMIZE_SIZE__
+ if (Mode == CompareStringsForEquality || QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return memcmp(a, b, l * sizeof(char16_t));
+
for (size_t i = 0; i < l; ++i) {
if (int diff = a[i] - b[i])
return diff;
@@ -1200,104 +1332,8 @@ static int ucstrncmp(const char16_t *a, const char *b, size_t l)
const char16_t *uc = a;
const char16_t *e = uc + l;
-#ifdef __SSE2__
- __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;
- if (Mode == CompareStringsForEquality) {
- retval = 1;
- } else {
- 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) {
- // similar to fromLatin1_helper:
- // load 16 bytes of Latin 1 data
- __m128i chunk = _mm_loadu_si128((const __m128i*)(c + offset));
-
-# ifdef __AVX2__
- // expand Latin 1 data via zero extension
- __m256i ldata = _mm256_cvtepu8_epi16(chunk);
-
- // load UTF-16 data and compare
- __m256i ucdata = _mm256_loadu_si256((const __m256i*)(uc + offset));
- __m256i result = _mm256_cmpeq_epi16(ldata, ucdata);
-
- uint mask = ~_mm256_movemask_epi8(result);
-# else
- // expand via unpacking
- __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullmask);
- __m128i secondHalf = _mm_unpackhi_epi8(chunk, nullmask);
-
- // load UTF-16 data and compare
- __m128i ucdata1 = _mm_loadu_si128((const __m128i*)(uc + offset));
- __m128i ucdata2 = _mm_loadu_si128((const __m128i*)(uc + offset + 8));
- __m128i result1 = _mm_cmpeq_epi16(firstHalf, ucdata1);
- __m128i result2 = _mm_cmpeq_epi16(secondHalf, ucdata2);
-
- uint mask = ~(_mm_movemask_epi8(result1) | _mm_movemask_epi8(result2) << 16);
-# endif
- if (mask) {
- // found a different character
- if (Mode == CompareStringsForEquality)
- return 1;
- uint idx = qCountTrailingZeroBits(mask);
- return uc[offset + idx / 2] - c[offset + idx / 2];
- }
- }
-
-# if !defined(__OPTIMIZE_SIZE__)
- // 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 secondHalf = mm_load8_zero_extend(c + offset);
-
- __m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset));
- if (isDifferent(ucdata, secondHalf))
- return retval;
-
- // still matched
- offset += 8;
- }
-
- enum { MaxTailLength = 3 };
- // we'll read uc[offset..offset+3] (8 bytes) and c[offset..offset+3] (4 bytes)
- if (uc + offset + 3 < e) {
- __m128i chunk = _mm_cvtsi32_si128(qFromUnaligned<int>(c + offset));
- __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask);
-
- __m128i ucdata = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(uc + offset));
- 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] - char16_t(c[i]); };
- return UnrollTailLoop<MaxTailLength>::exec(e - uc, 0, lambda, lambda);
-# endif
+#if defined(__SSE2__) && !defined(__OPTIMIZE_SIZE__)
+ return ucstrncmp_sse2<Mode>(uc, c, l);
#endif
while (uc < e) {
@@ -1310,19 +1346,10 @@ static int ucstrncmp(const char16_t *a, const char *b, size_t l)
return 0;
}
-constexpr int lencmp(qsizetype lhs, qsizetype rhs) noexcept
-{
- return lhs == rhs ? 0 :
- lhs > rhs ? 1 :
- /* else */ -1 ;
-}
-
// Unicode case-sensitive equality
template <typename Char2>
-static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
+static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b)
{
- if (alen != blen)
- return false;
if constexpr (std::is_same_v<decltype(a), decltype(b)>) {
if (a == b)
return true;
@@ -1340,28 +1367,11 @@ static int ucstrcmp(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
}
const size_t l = qMin(alen, blen);
int cmp = ucstrncmp<CompareStringsForOrdering>(a, b, l);
- return cmp ? cmp : lencmp(alen, blen);
-}
-
-static constexpr uchar latin1Lower[256] = {
- 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
- 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
- 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
- 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
- 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
- 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
- 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
- 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
- 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
- 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
- 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
- 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
- // 0xd7 (multiplication sign) and 0xdf (sz ligature) complicate life
- 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
- 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xd7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xdf,
- 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
- 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
-};
+ return cmp ? cmp : qt_lencmp(alen, blen);
+}
+
+using CaseInsensitiveL1 = QtPrivate::QCaseInsensitiveLatin1Hash;
+
static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar, qsizetype rSize)
{
// We're called with QLatin1StringView's .data() and .size():
@@ -1372,23 +1382,24 @@ static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar
return 1;
const qsizetype size = std::min(lSize, rSize);
- const uchar *lhs = reinterpret_cast<const uchar *>(lhsChar);
- const uchar *rhs = reinterpret_cast<const uchar *>(rhsChar);
- Q_ASSERT(lhs && rhs); // since both lSize and rSize are positive
+ Q_ASSERT(lhsChar && rhsChar); // since both lSize and rSize are positive
for (qsizetype i = 0; i < size; i++) {
- if (int res = latin1Lower[lhs[i]] - latin1Lower[rhs[i]])
+ if (int res = CaseInsensitiveL1::difference(lhsChar[i], rhsChar[i]))
return res;
}
- return lencmp(lSize, rSize);
+ return qt_lencmp(lSize, rSize);
}
+
bool QtPrivate::equalStrings(QStringView lhs, QStringView rhs) noexcept
{
- return ucstreq(lhs.utf16(), lhs.size(), rhs.utf16(), rhs.size());
+ Q_ASSERT(lhs.size() == rhs.size());
+ return ucstreq(lhs.utf16(), lhs.size(), rhs.utf16());
}
bool QtPrivate::equalStrings(QStringView lhs, QLatin1StringView rhs) noexcept
{
- return ucstreq(lhs.utf16(), lhs.size(), rhs.latin1(), rhs.size());
+ Q_ASSERT(lhs.size() == rhs.size());
+ return ucstreq(lhs.utf16(), lhs.size(), rhs.latin1());
}
bool QtPrivate::equalStrings(QLatin1StringView lhs, QStringView rhs) noexcept
@@ -1398,7 +1409,8 @@ bool QtPrivate::equalStrings(QLatin1StringView lhs, QStringView rhs) noexcept
bool QtPrivate::equalStrings(QLatin1StringView lhs, QLatin1StringView rhs) noexcept
{
- return lhs.size() == rhs.size() && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
+ Q_ASSERT(lhs.size() == rhs.size());
+ return (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
}
bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QStringView rhs) noexcept
@@ -1413,8 +1425,7 @@ bool QtPrivate::equalStrings(QStringView lhs, QBasicUtf8StringView<false> rhs) n
bool QtPrivate::equalStrings(QLatin1StringView lhs, QBasicUtf8StringView<false> rhs) noexcept
{
- QString r = rhs.toString();
- return QtPrivate::equalStrings(lhs, r); // ### optimize!
+ return QUtf8::compareUtf8(QByteArrayView(rhs), lhs) == 0;
}
bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QLatin1StringView rhs) noexcept
@@ -1424,7 +1435,14 @@ bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QLatin1StringView
bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs) noexcept
{
- return lhs.size() == rhs.size() && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || defined(QT_STATIC)
+ Q_ASSERT(lhs.size() == rhs.size());
+#else
+ // operator== didn't enforce size prior to Qt 6.2
+ if (lhs.size() != rhs.size())
+ return false;
+#endif
+ return (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
}
bool QAnyStringView::equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
@@ -1445,8 +1463,7 @@ bool QAnyStringView::equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
Returns an integer that compares to 0 as \a lhs compares to \a rhs.
- If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
- otherwise the comparison is case-insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
Case-sensitive comparison is based exclusively on the numeric Unicode values
of the characters and is very fast, but is not what a human would expect.
@@ -1469,8 +1486,7 @@ int QtPrivate::compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitiv
Returns an integer that compares to 0 as \a lhs compares to \a rhs.
- If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
- otherwise the comparison is case-insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
Case-sensitive comparison is based exclusively on the numeric Unicode values
of the characters and is very fast, but is not what a human would expect.
@@ -1515,8 +1531,7 @@ int QtPrivate::compareStrings(QLatin1StringView lhs, QStringView rhs, Qt::CaseSe
Returns an integer that compares to 0 as \a lhs compares to \a rhs.
- If \a cs is Qt::CaseSensitive (the default), the comparison is case-sensitive;
- otherwise the comparison is case-insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
Case-sensitive comparison is based exclusively on the numeric Latin-1 values
of the characters and is very fast, but is not what a human would expect.
@@ -1527,12 +1542,12 @@ int QtPrivate::compareStrings(QLatin1StringView lhs, QStringView rhs, Qt::CaseSe
int QtPrivate::compareStrings(QLatin1StringView lhs, QLatin1StringView rhs, Qt::CaseSensitivity cs) noexcept
{
if (lhs.isEmpty())
- return lencmp(qsizetype(0), rhs.size());
+ return qt_lencmp(qsizetype(0), rhs.size());
if (cs == Qt::CaseInsensitive)
return latin1nicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size());
const auto l = std::min(lhs.size(), rhs.size());
int r = memcmp(lhs.data(), rhs.data(), l);
- return r ? r : lencmp(lhs.size(), rhs.size());
+ return r ? r : qt_lencmp(lhs.size(), rhs.size());
}
/*!
@@ -1543,7 +1558,7 @@ int QtPrivate::compareStrings(QLatin1StringView lhs, QLatin1StringView rhs, Qt::
*/
int QtPrivate::compareStrings(QLatin1StringView lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
{
- return compareStrings(lhs, rhs.toString(), cs); // ### optimize!
+ return -QUtf8::compareUtf8(QByteArrayView(rhs), lhs, cs);
}
/*!
@@ -1578,13 +1593,7 @@ int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QLatin1StringView
*/
int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
{
- if (lhs.isEmpty())
- return lencmp(0, rhs.size());
- if (cs == Qt::CaseInsensitive)
- return compareStrings(lhs.toString(), rhs.toString(), cs); // ### optimize!
- const auto l = std::min(lhs.size(), rhs.size());
- int r = memcmp(lhs.data(), rhs.data(), l);
- return r ? r : lencmp(lhs.size(), rhs.size());
+ return QUtf8::compareUtf8(QByteArrayView(lhs), QByteArrayView(rhs), cs);
}
int QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs) noexcept
@@ -1598,7 +1607,7 @@ int QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSens
// ### Qt 7: do not allow anything but ASCII digits
// in arg()'s replacements.
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
static bool supportUnicodeDigitValuesInArg()
{
static const bool result = []() {
@@ -1621,7 +1630,7 @@ static bool supportUnicodeDigitValuesInArg()
static int qArgDigitValue(QChar ch) noexcept
{
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
if (supportUnicodeDigitValuesInArg())
return ch.digitValue();
#endif
@@ -1701,10 +1710,18 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\ingroup shared
\ingroup string-processing
+ \compares strong
+ \compareswith strong QChar QLatin1StringView {const char16_t *} \
+ QStringView QUtf8StringView
+ \endcompareswith
+ \compareswith strong QByteArray QByteArrayView {const char *}
+ When comparing with byte arrays, their content is interpreted as utf-8.
+ \endcompareswith
+
QString stores a string of 16-bit \l{QChar}s, where each QChar
corresponds to one UTF-16 code unit. (Unicode characters
with code values above 65535 are stored using surrogate pairs,
- i.e., two consecutive \l{QChar}s.)
+ that is, two consecutive \l{QChar}s.)
\l{Unicode} is an international standard that supports most of the
writing systems in use today. It is a superset of US-ASCII (ANSI
@@ -1720,17 +1737,15 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
store raw bytes and traditional 8-bit '\\0'-terminated strings.
For most purposes, QString is the class you want to use. It is
used throughout the Qt API, and the Unicode support ensures that
- your applications will be easy to translate if you want to expand
- your application's market at some point. The two main cases where
- QByteArray is appropriate are when you need to store raw binary
- data, and when memory conservation is critical (like in embedded
- systems).
+ your applications are easy to translate if you want to expand
+ your application's market at some point. Two prominent cases
+ where QByteArray is appropriate are when you need to store raw
+ binary data, and when memory conservation is critical (like in
+ embedded systems).
- \tableofcontents
+ \section1 Initializing a string
- \section1 Initializing a String
-
- One way to initialize a QString is simply to pass a \c{const char
+ One way to initialize a QString is to pass a \c{const char
*} to its constructor. For example, the following code creates a
QString of size 5 containing the data "Hello":
@@ -1741,17 +1756,18 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
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 \nullptr.
+ C-style \c{'\\0'}-terminated string. Except where the function's
+ name overtly indicates some other encoding, such \c{const char *}
+ parameters are assumed to be encoded in UTF-8.
You can also provide string data as an array of \l{QChar}s:
\snippet qstring/main.cpp 1
QString makes a deep copy of the QChar data, so you can modify it
- later without experiencing side effects. (If for performance
- reasons you don't want to take a deep copy of the character data,
- use QString::fromRawData() instead.)
+ later without experiencing side effects. You can avoid taking a
+ deep copy of the character data by using QStringView or
+ QString::fromRawData() instead.
Another approach is to set the size of the string using resize()
and to initialize the data character per character. QString uses
@@ -1768,7 +1784,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/main.cpp 3
- The at() function can be faster than \l operator[](), because it
+ The at() function can be faster than \l operator[]() because it
never causes a \l{deep copy} to occur. Alternatively, use the
first(), last(), or sliced() functions to extract several characters
at a time.
@@ -1790,11 +1806,11 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
You can also pass string literals to functions that take QStrings
as arguments, invoking the QString(const char *)
constructor. Similarly, you can pass a QString to a function that
- takes a \c{const char *} argument using the \l qPrintable() macro
+ takes a \c{const char *} argument using the \l qPrintable() macro,
which returns the given QString as a \c{const char *}. This is
equivalent to calling <QString>.toLocal8Bit().constData().
- \section1 Manipulating String Data
+ \section1 Manipulating string data
QString provides the following basic functions for modifying the
character data: append(), prepend(), insert(), replace(), and
@@ -1802,19 +1818,19 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/main.cpp 5
- In the above example the replace() function's first two arguments are the
+ In the above example, the replace() function's first two arguments are the
position from which to start replacing and the number of characters that
should be replaced.
When data-modifying functions increase the size of the string,
- they may lead to reallocation of memory for the QString object. When
+ QString may reallocate the memory in which it holds its data. When
this happens, QString expands by more than it immediately needs so as
to have space for further expansion without reallocation until the size
- of the string has greatly increased.
+ of the string has significantly increased.
- The insert(), remove() and, when replacing a sub-string with one of
+ The insert(), remove(), and, when replacing a sub-string with one of
different size, replace() functions can be slow (\l{linear time}) for
- large strings, because they require moving many characters in the string
+ large strings because they require moving many characters in the string
by at least one position in memory.
If you are building a QString gradually and know in advance
@@ -1832,32 +1848,32 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
method of the QString is called. Accessing such an iterator or reference
after the call to a non-\c{const} method leads to undefined behavior. When
stability for iterator-like functionality is required, you should use
- indexes instead of iterators as they are not tied to QString's internal
+ indexes instead of iterators, as they are not tied to QString's internal
state and thus do not get invalidated.
\note Due to \l{implicit sharing}, the first non-\c{const} operator or
- function used on a given QString may cause it to, internally, perform a deep
+ function used on a given QString may cause it to internally perform a deep
copy of its data. This invalidates all iterators over the string and
- references to individual characters within it. After the first non-\c{const}
- operator, operations that modify QString may completely (in case of
- reallocation) or partially invalidate iterators and references, but other
- methods (such as begin() or end()) will not. Accessing an iterator or
- reference after it has been invalidated leads to undefined behavior.
-
- A frequent requirement is to remove whitespace characters from a
- string ('\\n', '\\t', ' ', etc.). If you want to remove whitespace
- from both ends of a QString, use the trimmed() function. If you
- want to remove whitespace from both ends and replace multiple
- consecutive whitespaces with a single space character within the
- string, use simplified().
+ references to individual characters within it. Do not call non-const
+ functions while keeping iterators. Accessing an iterator or reference
+ after it has been invalidated leads to undefined behavior. See the
+ \l{Implicit sharing iterator problem} section for more information.
+
+ A frequent requirement is to remove or simplify the spacing between
+ visible characters in a string. The characters that make up that spacing
+ are those for which \l {QChar::}{isSpace()} returns \c true, such as
+ the simple space \c{' '}, the horizontal tab \c{'\\t'} and the newline \c{'\\n'}.
+ To obtain a copy of a string leaving out any spacing from its start and end,
+ use \l trimmed(). To also replace each sequence of spacing characters within
+ the string with a simple space, \c{' '}, use \l simplified().
If you want to find all occurrences of a particular character or
substring in a QString, use the indexOf() or lastIndexOf()
- functions. The former searches forward starting from a given index
- position, the latter searches backward. Both return the index
- position of the character or substring if they find it; otherwise,
- they return -1. For example, here is a typical loop that finds all
- occurrences of a particular substring:
+ functions.The former searches forward, the latter searches backward.
+ Either can be told an index position from which to start their search.
+ Each returns the index position of the character or substring if they
+ find it; otherwise, they return -1. For example, here is a typical loop
+ that finds all occurrences of a particular substring:
\snippet qstring/main.cpp 6
@@ -1866,52 +1882,57 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
setNum() functions, the number() static functions, and the
toInt(), toDouble(), and similar functions.
- To get an upper- or lowercase version of a string use toUpper() or
+ To get an uppercase or lowercase version of a string, use toUpper() or
toLower().
Lists of strings are handled by the QStringList class. You can
split a string into a list of strings using the split() function,
and join a list of strings into a single string with an optional
- separator using QStringList::join(). You can obtain a list of
- strings from a string list that contain a particular substring or
- that match a particular QRegularExpression using the QStringList::filter()
- function.
+ separator using QStringList::join(). You can obtain a filtered list
+ from a string list by selecting the entries in it that contain a
+ particular substring or match a particular QRegularExpression.
+ See QStringList::filter() for details.
- \section1 Querying String Data
+ \section1 Querying string data
- If you want to see if a QString starts or ends with a particular
- substring use startsWith() or endsWith(). If you simply want to
- check whether a QString contains a particular character or
- substring, use the contains() function. If you want to find out
- how many times a particular character or substring occurs in the
- string, use count().
+ To see if a QString starts or ends with a particular substring, use
+ startsWith() or endsWith(). To check whether a QString contains a
+ specific character or substring, use the contains() function. To
+ find out how many times a particular character or substring occurs
+ in a string, use count().
To obtain a pointer to the actual character data, call data() or
constData(). These functions return a pointer to the beginning of
the QChar data. The pointer is guaranteed to remain valid until a
non-\c{const} function is called on the QString.
- \section2 Comparing Strings
+ \section2 Comparing strings
QStrings can be compared using overloaded operators such as \l
operator<(), \l operator<=(), \l operator==(), \l operator>=(),
- and so on. Note that the comparison is based exclusively on the
- numeric Unicode values of the characters. It is very fast, but is
- not what a human would expect; the QString::localeAwareCompare()
- function is usually a better choice for sorting user-interface
- strings, when such a comparison is available.
-
- On Unix-like platforms (including Linux, \macos and iOS), when Qt
- is linked with the ICU library (which it usually is), its
- locale-aware sorting is used. Otherwise, on \macos and iOS, \l
- localeAwareCompare() compares according the "Order for sorted
- lists" setting in the International preferences panel. On other
- Unix-like systems without ICU, the comparison falls back to the
- system library's \c strcoll(),
-
- \section1 Converting Between Encoded Strings Data and QString
-
- QString provides the following three functions that return a
+ and so on. The comparison is based exclusively on the lexicographical
+ order of the two strings, seen as sequences of UTF-16 code units.
+ It is very fast but is not what a human would expect; the
+ QString::localeAwareCompare() function is usually a better choice for
+ sorting user-interface strings, when such a comparison is available.
+
+ When Qt is linked with the ICU library (which it usually is), its
+ locale-aware sorting is used. Otherwise, platform-specific solutions
+ are used:
+ \list
+ \li On Windows, localeAwareCompare() uses the current user locale,
+ as set in the \uicontrol{regional} and \uicontrol{language}
+ options portion of \uicontrol{Control Panel}.
+ \li On \macos and iOS, \l localeAwareCompare() compares according
+ to the \uicontrol{Order for sorted lists} setting in the
+ \uicontrol{International preferences} panel.
+ \li On other Unix-like systems, the comparison falls back to the
+ system library's \c strcoll().
+ \endlist
+
+ \section1 Converting between encoded string data and QString
+
+ QString provides the following functions that return a
\c{const char *} version of the string as QByteArray: toUtf8(),
toLatin1(), and toLocal8Bit().
@@ -1942,7 +1963,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\li \l QT_NO_CAST_FROM_ASCII disables automatic conversions from
C string literals and pointers to Unicode.
\li \l QT_RESTRICTED_CAST_FROM_ASCII allows automatic conversions
- from C characters and character arrays, but disables automatic
+ from C characters and character arrays but disables automatic
conversions from character pointers to Unicode.
\li \l QT_NO_CAST_TO_ASCII disables automatic conversion from QString
to C strings.
@@ -1950,7 +1971,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
You then need to explicitly call fromUtf8(), fromLatin1(),
or fromLocal8Bit() to construct a QString from an
- 8-bit string, or use the lightweight QLatin1StringView class, for
+ 8-bit string, or use the lightweight QLatin1StringView class. For
example:
\snippet code/src_corelib_text_qstring.cpp 1
@@ -1971,7 +1992,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/main.cpp 7
- The \c result variable, is a normal variable allocated on the
+ The \c result variable is a normal variable allocated on the
stack. When \c return is called, and because we're returning by
value, the copy constructor is called and a copy of the string is
returned. No actual copying takes place thanks to the implicit
@@ -1979,12 +2000,12 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\endtable
- \section1 Distinction Between Null and Empty Strings
+ \section1 Distinction between null and empty strings
- For historical reasons, QString distinguishes between a null
- string and an empty string. A \e null string is a string that is
+ For historical reasons, QString distinguishes between null
+ and empty strings. A \e null string is a string that is
initialized using QString's default constructor or by passing
- (\c{const char *})0 to the constructor. An \e empty string is any
+ \nullptr to the constructor. An \e empty string is any
string with size 0. A null string is always empty, but an empty
string isn't necessarily null:
@@ -1992,10 +2013,10 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
All functions except isNull() treat null strings the same as empty
strings. For example, toUtf8().constData() returns a valid pointer
- (\e not nullptr) to a '\\0' character for a null string. We
+ (not \nullptr) to a '\\0' character for a null string. We
recommend that you always use the isEmpty() function and avoid isNull().
- \section1 Number Formats
+ \section1 Number formats
When a QString::arg() \c{'%'} format specifier includes the \c{'L'} locale
qualifier, and the base is ten (its default), the default locale is
@@ -2005,16 +2026,16 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
C locale's representation of numbers.
When QString::arg() applies left-padding to numbers, the fill character
- \c{'0'} is treated specially. If the number is negative, its minus sign will
- appear before the zero-padding. If the field is localized, the
+ \c{'0'} is treated specially. If the number is negative, its minus sign
+ appears before the zero-padding. If the field is localized, the
locale-appropriate zero character is used in place of \c{'0'}. For
floating-point numbers, this special treatment only applies if the number is
finite.
- \section2 Floating-point Formats
+ \section2 Floating-point formats
- In member functions (e.g., arg(), number()) that represent floating-point
- numbers (\c float or \c double) as strings, the form of display can be
+ In member functions (for example, arg() and number()) that format floating-point
+ numbers (\c float or \c double) as strings, the representation used can be
controlled by a choice of \e format and \e precision, whose meanings are as
for \l {QLocale::toString(double, char, int)}.
@@ -2023,19 +2044,15 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
the exponent shows its sign and includes at least two digits, left-padding
with zero if needed.
- \section1 More Efficient String Construction
+ \section1 More efficient string construction
- Many strings are known at compile time. But the trivial
- constructor QString("Hello"), will copy the contents of the string,
- treating the contents as Latin-1. To avoid this one can use the
- QStringLiteral macro to directly create the required data at compile
- time. Constructing a QString out of the literal does then not cause
- any overhead at runtime.
-
- A slightly less efficient way is to use QLatin1StringView. This class wraps
- a C string literal, precalculates it length at compile time and can
- then be used for faster comparison with QStrings and conversion to
- QStrings than a regular C string literal.
+ Many strings are known at compile time. The QString constructor from
+ C++ string literals will copy the contents of the string,
+ treating the contents as UTF-8. This requires memory allocation and
+ re-encoding string data, operations that will happen at runtime.
+ If the string data is known at compile time, you can use the QStringLiteral
+ macro or similarly \c{operator""_s} to create QString's payload at compile
+ time instead.
Using the QString \c{'+'} operator, it is easy to construct a
complex string from multiple substrings. You will often write code
@@ -2044,16 +2061,15 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/stringbuilder.cpp 0
There is nothing wrong with either of these string constructions,
- but there are a few hidden inefficiencies. Beginning with Qt 4.6,
- you can eliminate them.
+ but there are a few hidden inefficiencies:
- First, multiple uses of the \c{'+'} operator usually means
+ First, repeated use of the \c{'+'} operator may lead to
multiple memory allocations. When concatenating \e{n} substrings,
where \e{n > 2}, there can be as many as \e{n - 1} calls to the
memory allocator.
- In 4.6, an internal template class \c{QStringBuilder} has been
- added along with a few helper functions. This class is marked
+ These allocations can be optimized by an internal class
+ \c{QStringBuilder}. This class is marked
internal and does not appear in the documentation, because you
aren't meant to instantiate it in your code. Its use will be
automatic, as described below. The class is found in
@@ -2069,47 +2085,57 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
then called \e{once} to get the required space, and the substrings
are copied into it one by one.
- Additional efficiency is gained by inlining and reduced reference
- counting (the QString created from a \c{QStringBuilder} typically
+ Additional efficiency is gained by inlining and reducing reference
+ counting (the QString created from a \c{QStringBuilder}
has a ref count of 1, whereas QString::append() needs an extra
test).
There are two ways you can access this improved method of string
construction. The straightforward way is to include
- \c{QStringBuilder} wherever you want to use it, and use the
+ \c{QStringBuilder} wherever you want to use it and use the
\c{'%'} operator instead of \c{'+'} when concatenating strings:
\snippet qstring/stringbuilder.cpp 5
- A more global approach which is the most convenient but
- not entirely source compatible, is to this define in your
- .pro file:
+ A more global approach, which is more convenient but not entirely
+ source-compatible, is to define \c QT_USE_QSTRINGBUILDER (by adding
+ it to the compiler flags) at build time. This will make concatenating
+ strings with \c{'+'} work the same way as \c{QStringBuilder's} \c{'%'}.
+
+ \note Using automatic type deduction (for example, by using the \c
+ auto keyword) with the result of string concatenation when QStringBuilder
+ is enabled will show that the concatenation is indeed an object of a
+ QStringBuilder specialization:
- \snippet qstring/stringbuilder.cpp 3
+ \snippet qstring/stringbuilder.cpp 6
- and the \c{'+'} will automatically be performed as the
- \c{QStringBuilder} \c{'%'} everywhere.
+ This does not cause any harm, as QStringBuilder will implicitly convert to
+ QString when required. If this is undesirable, then one should specify
+ the necessary types instead of having the compiler deduce them:
- \section1 Maximum Size and Out-of-memory Conditions
+ \snippet qstring/stringbuilder.cpp 7
+
+ \section1 Maximum size and out-of-memory conditions
The maximum size of QString depends on the architecture. Most 64-bit
systems can allocate more than 2 GB of memory, with a typical limit
of 2^63 bytes. The actual value also depends on the overhead required for
- managing the data block. As a result, you can expect the maximum size
- of 2 GB minus overhead on 32-bit platforms, and 2^63 bytes minus overhead
+ managing the data block. As a result, you can expect a maximum size
+ of 2 GB minus overhead on 32-bit platforms and 2^63 bytes minus overhead
on 64-bit platforms. The number of elements that can be stored in a
QString is this maximum size divided by the size of QChar.
When memory allocation fails, QString throws a \c std::bad_alloc
exception if the application was compiled with exception support.
- Out of memory conditions in Qt containers are the only case where Qt
+ Out-of-memory conditions in Qt containers are the only cases where Qt
will throw exceptions. If exceptions are disabled, then running out of
memory is undefined behavior.
- Note that the operating system may impose further limits on applications
- holding a lot of allocated memory, especially large, contiguous blocks.
- Such considerations, the configuration of such behavior or any mitigation
- are outside the scope of the Qt API.
+ \note Target operating systems may impose limits on how much memory an
+ application can allocate, in total, or on the size of individual allocations.
+ This may further restrict the size of string a QString can hold.
+ Mitigating or controlling the behavior these limits cause is beyond the
+ scope of the Qt API.
\sa fromRawData(), QChar, QStringView, QLatin1StringView, QByteArray
*/
@@ -2354,10 +2380,16 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\sa fromLatin1(), fromLocal8Bit(), fromUtf8()
*/
+/*
+//! [from-std-string]
+Returns a copy of the \a str string. The given string is assumed to be
+encoded in \1, and is converted to QString using the \2 function.
+//! [from-std-string]
+*/
+
/*! \fn QString QString::fromStdString(const std::string &str)
- Returns a copy of the \a str string. The given string is converted
- to Unicode using the fromUtf8() function.
+ \include qstring.cpp {from-std-string} {UTF-8} {fromUtf8()}
\sa fromLatin1(), fromLocal8Bit(), fromUtf8(), QByteArray::fromStdString()
*/
@@ -2389,8 +2421,8 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
/*! \fn std::wstring QString::toStdWString() const
Returns a std::wstring object with the data contained in this
- QString. The std::wstring is encoded in utf16 on platforms where
- wchar_t is 2 bytes wide (e.g. windows) and in ucs4 on platforms
+ QString. The std::wstring is encoded in UTF-16 on platforms where
+ wchar_t is 2 bytes wide (for example, Windows) and in UTF-32 on platforms
where wchar_t is 4 bytes wide (most Unix systems).
This method is mostly useful to pass a QString to a function
@@ -2400,7 +2432,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
toStdU32String()
*/
-qsizetype QString::toUcs4_helper(const ushort *uc, qsizetype length, uint *out)
+qsizetype QString::toUcs4_helper(const char16_t *uc, qsizetype length, char32_t *out)
{
qsizetype count = 0;
@@ -2463,15 +2495,12 @@ QString::QString(const QChar *unicode, qsizetype size)
if (!unicode) {
d.clear();
} else {
- if (size < 0) {
- size = 0;
- while (!unicode[size].isNull())
- ++size;
- }
+ if (size < 0)
+ size = QtPrivate::qustrlen(reinterpret_cast<const char16_t *>(unicode));
if (!size) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
memcpy(d.data(), unicode, size * sizeof(QChar));
d.data()[size] = '\0';
@@ -2490,14 +2519,13 @@ QString::QString(qsizetype size, QChar ch)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
d.data()[size] = '\0';
- char16_t *i = d.data() + size;
char16_t *b = d.data();
+ char16_t *e = d.data() + size;
const char16_t value = ch.unicode();
- while (i != b)
- *--i = value;
+ std::fill(b, e, value);
}
}
@@ -2512,7 +2540,7 @@ QString::QString(qsizetype size, Qt::Initialization)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
d.data()[size] = '\0';
}
@@ -2520,7 +2548,7 @@ QString::QString(qsizetype size, Qt::Initialization)
/*! \fn QString::QString(QLatin1StringView str)
- Constructs a copy of the Latin-1 string \a str.
+ Constructs a copy of the Latin-1 string viewed by \a str.
\sa fromLatin1()
*/
@@ -2530,7 +2558,7 @@ QString::QString(qsizetype size, Qt::Initialization)
*/
QString::QString(QChar ch)
{
- d = DataPointer(Data::allocate(1), 1);
+ d = DataPointer(1, 1);
Q_CHECK_PTR(d.data());
d.data()[0] = ch.unicode();
d.data()[1] = '\0';
@@ -2546,7 +2574,7 @@ QString::QString(QChar ch)
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
- \note: any null ('\\0') bytes in the byte array will be included in this
+ \note Any null ('\\0') bytes in the byte array will be included in this
string, converted to Unicode null characters (U+0000). This behavior is
different from Qt 5.x.
@@ -2594,6 +2622,18 @@ QString::QString(QChar ch)
\internal
*/
+/*! \fn QString::operator std::u16string_view() const
+ \since 6.7
+
+ Converts this QString object to a \c{std::u16string_view} object.
+*/
+
+static bool needsReallocate(const QString &str, qsizetype newSize)
+{
+ const auto capacityAtEnd = str.capacity() - str.data_ptr().freeSpaceAtBegin();
+ return newSize > capacityAtEnd;
+}
+
/*!
Sets the size of the string to \a size characters.
@@ -2630,12 +2670,11 @@ void QString::resize(qsizetype size)
if (size < 0)
size = 0;
- const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin();
- if (d->needsDetach() || size > capacityAtEnd)
+ if (d->needsDetach() || needsReallocate(*this, size))
reallocData(size, QArrayData::Grow);
d.size = size;
if (d->allocatedCapacity())
- d.data()[size] = 0;
+ d.data()[size] = u'\0';
}
/*!
@@ -2648,15 +2687,33 @@ void QString::resize(qsizetype size)
\snippet qstring/main.cpp 46
*/
-void QString::resize(qsizetype size, QChar fillChar)
+void QString::resize(qsizetype newSize, QChar fillChar)
{
- const qsizetype oldSize = length();
- resize(size);
- const qsizetype difference = length() - oldSize;
+ const qsizetype oldSize = size();
+ resize(newSize);
+ const qsizetype difference = size() - oldSize;
if (difference > 0)
std::fill_n(d.data() + oldSize, difference, fillChar.unicode());
}
+
+/*!
+ \since 6.8
+
+ Sets the size of the string to \a size characters. If the size of
+ the string grows, the new characters are uninitialized.
+
+ The behavior is identical to \c{resize(size)}.
+
+ \sa resize()
+*/
+
+void QString::resizeForOverwrite(qsizetype size)
+{
+ resize(size);
+}
+
+
/*! \fn qsizetype QString::capacity() const
Returns the maximum number of characters that can be stored in
@@ -2682,20 +2739,20 @@ void QString::resize(qsizetype size, QChar fillChar)
Ensures the string has space for at least \a size characters.
- If you know in advance how large the string will be, you can call this
- function to save repeated reallocation in the course of building it.
+ If you know in advance how large a string will be, you can call this
+ function to save repeated reallocation while building it.
This can improve performance when building a string incrementally.
A long sequence of operations that add to a string may trigger several
reallocations, the last of which may leave you with significantly more
- space than you really need, which is less efficient than doing a single
+ space than you need. This is less efficient than doing a single
allocation of the right size at the start.
If in doubt about how much space shall be needed, it is usually better to
use an upper bound as \a size, or a high estimate of the most likely size,
if a strict upper bound would be much bigger than this. If \a size is an
underestimate, the string will grow as needed once the reserved size is
- exceeded, which may lead to a larger allocation than your best overestimate
- would have and will slow the operation that triggers it.
+ exceeded, which may lead to a larger allocation than your best
+ overestimate would have and will slow the operation that triggers it.
\warning reserve() reserves memory but does not change the size of the
string. Accessing data beyond the end of the string is undefined behavior.
@@ -2737,7 +2794,7 @@ void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
if (d->needsDetach() || cannotUseReallocate) {
- DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size));
+ DataPointer dd(alloc, qMin(alloc, d.size), option);
Q_CHECK_PTR(dd.data());
if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
@@ -2795,7 +2852,7 @@ QString &QString::operator=(const QString &other) noexcept
\overload operator=()
- Assigns the Latin-1 string \a str to this string.
+ Assigns the Latin-1 string viewed by \a str to this string.
*/
QString &QString::operator=(QLatin1StringView other)
{
@@ -2843,16 +2900,7 @@ QString &QString::operator=(QLatin1StringView other)
*/
QString &QString::operator=(QChar ch)
{
- const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
- if (isDetached() && capacityAtEnd >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
- // re-use existing capacity:
- d.data()[0] = ch.unicode();
- d.data()[1] = 0;
- d.size = 1;
- } else {
- operator=(QString(ch));
- }
- return *this;
+ return assign(1, ch);
}
/*!
@@ -2900,7 +2948,6 @@ QString &QString::operator=(QChar ch)
defined.
*/
-
/*!
\fn QString& QString::insert(qsizetype position, const QByteArray &str)
\since 5.5
@@ -2916,11 +2963,62 @@ QString &QString::operator=(QChar ch)
defined.
*/
+/*! \internal
+ T is a view or a container on/of QChar, char16_t, or char
+*/
+template <typename T>
+static void insert_helper(QString &str, qsizetype i, const T &toInsert)
+{
+ auto &str_d = str.data_ptr();
+ qsizetype difference = 0;
+ if (Q_UNLIKELY(i > str_d.size))
+ difference = i - str_d.size;
+ const qsizetype oldSize = str_d.size;
+ const qsizetype insert_size = toInsert.size();
+ const qsizetype newSize = str_d.size + difference + insert_size;
+ const auto side = i == 0 ? QArrayData::GrowsAtBeginning : QArrayData::GrowsAtEnd;
+
+ if (str_d.needsDetach() || needsReallocate(str, newSize)) {
+ const auto cbegin = str.cbegin();
+ const auto cend = str.cend();
+ const auto insert_start = difference == 0 ? std::next(cbegin, i) : cend;
+ QString other;
+ // Using detachAndGrow() so that prepend optimization works and QStringBuilder
+ // unittests pass
+ other.data_ptr().detachAndGrow(side, newSize, nullptr, nullptr);
+ other.append(QStringView(cbegin, insert_start));
+ other.resize(i, u' ');
+ other.append(toInsert);
+ other.append(QStringView(insert_start, cend));
+ str.swap(other);
+ return;
+ }
+
+ str_d.detachAndGrow(side, difference + insert_size, nullptr, nullptr);
+ Q_CHECK_PTR(str_d.data());
+ str.resize(newSize);
+
+ auto begin = str_d.begin();
+ auto old_end = std::next(begin, oldSize);
+ std::fill_n(old_end, difference, u' ');
+ auto insert_start = std::next(begin, i);
+ if (difference == 0)
+ std::move_backward(insert_start, old_end, str_d.end());
+
+ using Char = std::remove_cv_t<typename T::value_type>;
+ if constexpr(std::is_same_v<Char, QChar>)
+ std::copy_n(reinterpret_cast<const char16_t *>(toInsert.data()), insert_size, insert_start);
+ else if constexpr (std::is_same_v<Char, char16_t>)
+ std::copy_n(toInsert.data(), insert_size, insert_start);
+ else if constexpr (std::is_same_v<Char, char>)
+ qt_from_latin1(insert_start, toInsert.data(), insert_size);
+}
+
/*!
\fn QString &QString::insert(qsizetype position, QLatin1StringView str)
\overload insert()
- Inserts the Latin-1 string \a str at the given index \a position.
+ Inserts the Latin-1 string viewed by \a str at the given index \a position.
\include qstring.cpp string-grow-at-insertion
*/
@@ -2930,18 +3028,65 @@ QString &QString::insert(qsizetype i, QLatin1StringView str)
if (i < 0 || !s || !(*s))
return *this;
- qsizetype len = str.size();
+ insert_helper(*this, i, str);
+ return *this;
+}
+
+/*!
+ \fn QString &QString::insert(qsizetype position, QUtf8StringView str)
+ \overload insert()
+ \since 6.5
+
+ Inserts the UTF-8 string view \a str at the given index \a position.
+
+ \note Inserting variable-width UTF-8-encoded string data is conceptually slower
+ than inserting fixed-width string data such as UTF-16 (QStringView) or Latin-1
+ (QLatin1StringView) and should thus be used sparingly.
+
+ \include qstring.cpp string-grow-at-insertion
+*/
+QString &QString::insert(qsizetype i, QUtf8StringView s)
+{
+ auto insert_size = s.size();
+ if (i < 0 || insert_size <= 0)
+ return *this;
+
qsizetype difference = 0;
- if (Q_UNLIKELY(i > size()))
- difference = i - size();
- d.detachAndGrow(Data::GrowsAtEnd, difference + len, nullptr, nullptr);
- Q_CHECK_PTR(d.data());
- d->copyAppend(difference, u' ');
- d.size += len;
+ if (Q_UNLIKELY(i > d.size))
+ difference = i - d.size;
+
+ const qsizetype newSize = d.size + difference + insert_size;
+
+ if (d.needsDetach() || needsReallocate(*this, newSize)) {
+ const auto cbegin = this->cbegin();
+ const auto insert_start = difference == 0 ? std::next(cbegin, i) : cend();
+ QString other;
+ other.reserve(newSize);
+ other.append(QStringView(cbegin, insert_start));
+ if (difference > 0)
+ other.resize(i, u' ');
+ other.append(s);
+ other.append(QStringView(insert_start, cend()));
+ swap(other);
+ return *this;
+ }
+
+ if (i >= d.size) {
+ d.detachAndGrow(QArrayData::GrowsAtEnd, difference + insert_size, nullptr, nullptr);
+ Q_CHECK_PTR(d.data());
+
+ if (difference > 0)
+ resize(i, u' ');
+ append(s);
+ } else {
+ // Optimal insertion of Utf8 data is at the end, anywhere else could
+ // potentially lead to moving characters twice if Utf8 data size
+ // (variable-width) is less than the equivalent Utf16 data size
+ QVarLengthArray<char16_t> buffer(insert_size); // ### optimize (QTBUG-108546)
+ char16_t *b = QUtf8::convertToUnicode(buffer.data(), s);
+ insert_helper(*this, i, QStringView(buffer.data(), b));
+ }
- ::memmove(d.data() + i + len, d.data() + i, (d.size - i - len) * sizeof(QChar));
- qt_from_latin1(d.data() + i, s, size_t(len));
- d.data()[d.size] = u'\0';
return *this;
}
@@ -2962,28 +3107,14 @@ QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size)
if (i < 0 || size <= 0)
return *this;
- const char16_t *s = reinterpret_cast<const char16_t *>(unicode);
-
- // handle this specially, as QArrayDataOps::insert() doesn't handle out of
- // bounds positions
- if (i >= d->size) {
- // In case when data points into the range or is == *this, we need to
- // defer a call to free() so that it comes after we copied the data from
- // the old memory:
- DataPointer detached{}; // construction is free
- d.detachAndGrow(Data::GrowsAtEnd, (i - d.size) + size, &s, &detached);
- Q_CHECK_PTR(d.data());
- d->copyAppend(i - d->size, u' ');
- d->copyAppend(s, s + size);
- d.data()[d.size] = u'\0';
- return *this;
+ // In case when data points into "this"
+ if (!d->needsDetach() && QtPrivate::q_points_into_range(unicode, *this)) {
+ QVarLengthArray copy(unicode, unicode + size);
+ insert(i, copy.data(), size);
+ } else {
+ insert_helper(*this, i, QStringView(unicode, size));
}
- if (!d->needsDetach() && QtPrivate::q_points_into_range(s, d.data(), d.data() + d.size))
- return insert(i, QStringView{QVarLengthArray(s, s + size)});
-
- d->insert(i, s, size);
- d.data()[d.size] = u'\0';
return *this;
}
@@ -3027,7 +3158,10 @@ QString &QString::append(const QString &str)
{
if (!str.isNull()) {
if (isNull()) {
- operator=(str);
+ if (Q_UNLIKELY(!str.d.isMutable()))
+ assign(str); // fromRawData, so we do a deep copy
+ else
+ operator=(str);
} else if (str.size()) {
append(str.constData(), str.size());
}
@@ -3036,6 +3170,14 @@ QString &QString::append(const QString &str)
}
/*!
+ \fn QString &QString::append(QStringView v)
+ \overload append()
+ \since 6.0
+
+ Appends the given string view \a v to this string and returns the result.
+*/
+
+/*!
\overload append()
\since 5.0
@@ -3056,23 +3198,23 @@ QString &QString::append(const QChar *str, qsizetype len)
/*!
\overload append()
- Appends the Latin-1 string \a str to this string.
+ Appends the Latin-1 string viewed by \a str to this string.
*/
QString &QString::append(QLatin1StringView str)
{
- const char *s = str.latin1();
- const qsizetype len = str.size();
- if (s && len > 0) {
- d.detachAndGrow(Data::GrowsAtEnd, len, nullptr, nullptr);
- Q_CHECK_PTR(d.data());
- Q_ASSERT(len <= d->freeSpaceAtEnd());
- char16_t *i = d.data() + d.size;
- qt_from_latin1(i, s, size_t(len));
- d.size += len;
- d.data()[d.size] = '\0';
- } else if (d.isNull() && !str.isNull()) { // special case
- d = DataPointer::fromRawData(&_empty, 0);
- }
+ append_helper(*this, str);
+ return *this;
+}
+
+/*!
+ \overload append()
+ \since 6.5
+
+ Appends the UTF-8 string view \a str to this string.
+*/
+QString &QString::append(QUtf8StringView str)
+{
+ append_helper(*this, str);
return *this;
}
@@ -3135,7 +3277,14 @@ QString &QString::append(QChar ch)
\overload prepend()
- Prepends the Latin-1 string \a str to this string.
+ Prepends the Latin-1 string viewed by \a str to this string.
+*/
+
+/*! \fn QString &QString::prepend(QUtf8StringView str)
+ \since 6.5
+ \overload prepend()
+
+ Prepends the UTF-8 string view \a str to this string.
*/
/*! \fn QString &QString::prepend(const QChar *str, qsizetype len)
@@ -3188,6 +3337,111 @@ QString &QString::append(QChar ch)
*/
/*!
+ \fn QString &QString::assign(QAnyStringView v)
+ \since 6.6
+
+ Replaces the contents of this string with a copy of \a v and returns a
+ reference to this string.
+
+ The size of this string will be equal to the size of \a v, converted to
+ UTF-16 as if by \c{v.toString()}. Unlike QAnyStringView::toString(), however,
+ this function only allocates memory if the estimated size exceeds the capacity
+ of this string or this string is shared.
+
+ \sa QAnyStringView::toString()
+*/
+
+/*!
+ \fn QString &QString::assign(qsizetype n, QChar c)
+ \since 6.6
+
+ Replaces the contents of this string with \a n copies of \a c and
+ returns a reference to this string.
+
+ The size of this string will be equal to \a n, which has to be non-negative.
+
+ This function will only allocate memory if \a n exceeds the capacity of this
+ string or this string is shared.
+
+ \sa fill()
+*/
+
+/*!
+ \fn template <typename InputIterator, QString::if_compatible_iterator<InputIterator>> QString &QString::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this string with a copy of the elements in the
+ iterator range [\a first, \a last) and returns a reference to this string.
+
+ The size of this string will be equal to the decoded length of the elements
+ in the range [\a first, \a last), which need not be the same as the length of
+ the range itself, because this function transparently recodes the input
+ character set to UTF-16.
+
+ This function will only allocate memory if the number of elements in the
+ range, or, for non-UTF-16-encoded input, the maximum possible size of the
+ resulting string, exceeds the capacity of this string, or if this string is
+ shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}
+ and the \c{value_type} of \c InputIterator is one of the following character types:
+ \list
+ \li QChar
+ \li QLatin1Char
+ \li \c {char}
+ \li \c {unsigned char}
+ \li \c {signed char}
+ \li \c {char8_t}
+ \li \c char16_t
+ \li (on platforms, such as Windows, where it is a 16-bit type) \c wchar_t
+ \li \c char32_t
+ \endlist
+
+ \note The behavior is undefined if either argument is an iterator into *this or
+ [\a first, \a last) is not a valid range.
+*/
+
+QString &QString::assign(QAnyStringView s)
+{
+ if (s.size() <= capacity() && isDetached()) {
+ const auto offset = d.freeSpaceAtBegin();
+ if (offset)
+ d.setBegin(d.begin() - offset);
+ resize(0);
+ s.visit([this](auto input) {
+ this->append(input);
+ });
+ } else {
+ *this = s.toString();
+ }
+ return *this;
+}
+
+#ifndef QT_BOOTSTRAPPED
+QString &QString::assign_helper(const char32_t *data, qsizetype len)
+{
+ // worst case: each char32_t requires a surrogate pair, so
+ const auto requiredCapacity = len * 2;
+ if (requiredCapacity <= capacity() && isDetached()) {
+ const auto offset = d.freeSpaceAtBegin();
+ if (offset)
+ d.setBegin(d.begin() - offset);
+ auto begin = reinterpret_cast<QChar *>(d.begin());
+ auto ba = QByteArrayView(reinterpret_cast<const std::byte*>(data), len * sizeof(char32_t));
+ QStringConverter::State state;
+ const auto end = QUtf32::convertToUnicode(begin, ba, &state, DetectEndianness);
+ d.size = end - begin;
+ d.data()[d.size] = u'\0';
+ } else {
+ *this = QString::fromUcs4(data, len);
+ }
+ return *this;
+}
+#endif
+
+/*!
\fn QString &QString::remove(qsizetype position, qsizetype n)
Removes \a n characters from the string, starting at the given \a
@@ -3197,6 +3451,8 @@ QString &QString::append(QChar ch)
position + \a n is beyond the end of the string, the string is
truncated at the specified \a position.
+ If \a n is <= 0 nothing is changed.
+
\snippet qstring/main.cpp 37
//! [shrinking-erase]
@@ -3211,14 +3467,26 @@ QString &QString::remove(qsizetype pos, qsizetype len)
{
if (pos < 0) // count from end of string
pos += size();
- if (size_t(pos) >= size_t(size())) {
- // range problems
- } else if (len >= size() - pos) {
- resize(pos); // truncate
- } else if (len > 0) {
- detach();
+
+ if (size_t(pos) >= size_t(size()) || len <= 0)
+ return *this;
+
+ len = std::min(len, size() - pos);
+
+ if (!d->isShared()) {
d->erase(d.begin() + pos, len);
d.data()[d.size] = u'\0';
+ } else {
+ // TODO: either reserve "size()", which is bigger than needed, or
+ // modify the shrinking-erase docs of this method (since the size
+ // of "copy" won't have any extra capacity any more)
+ const qsizetype sz = size() - len;
+ QString copy{sz, Qt::Uninitialized};
+ auto begin = d.begin();
+ auto toRemove_start = d.begin() + pos;
+ copy.d->copyRanges({{begin, toRemove_start},
+ {toRemove_start + len, d.end()}});
+ swap(copy);
}
return *this;
}
@@ -3235,29 +3503,40 @@ static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs
if (i < 0)
return;
- const auto beg = s.begin(); // detaches
- auto dst = beg + i;
- auto src = beg + i + needleSize;
- const auto end = s.end();
- // loop invariant: [beg, dst[ is partial result
- // [src, end[ still to be checked for needles
- while (src < end) {
- const auto i = s.indexOf(needle, src - beg, cs);
- const auto hit = i == -1 ? end : beg + i;
- const auto skipped = hit - src;
- memmove(dst, src, skipped * sizeof(QChar));
- dst += skipped;
- src = hit + needleSize;
+ QString::DataPointer &dptr = s.data_ptr();
+ auto begin = dptr.begin();
+ auto end = dptr.end();
+
+ auto copyFunc = [&](auto &dst) {
+ auto src = begin + i + needleSize;
+ while (src < end) {
+ i = s.indexOf(needle, std::distance(begin, src), cs);
+ auto hit = i == -1 ? end : begin + i;
+ dst = std::copy(src, hit, dst);
+ src = hit + needleSize;
+ }
+ return dst;
+ };
+
+ if (!dptr->needsDetach()) {
+ auto dst = begin + i;
+ dst = copyFunc(dst);
+ s.truncate(std::distance(begin, dst));
+ } else {
+ QString copy{s.size(), Qt::Uninitialized};
+ auto copy_begin = copy.begin();
+ auto dst = std::copy(begin, begin + i, copy_begin); // Chunk before the first hit
+ dst = copyFunc(dst);
+ copy.resize(std::distance(copy_begin, dst));
+ s.swap(copy);
}
- s.truncate(dst - beg);
}
/*!
Removes every occurrence of the given \a str string in this
string, and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
This is the same as \c replace(str, "", cs).
@@ -3268,7 +3547,7 @@ static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs
QString &QString::remove(const QString &str, Qt::CaseSensitivity cs)
{
const auto s = str.d.data();
- if (QtPrivate::q_points_into_range(s, d.data(), d.data() + d.size))
+ if (QtPrivate::q_points_into_range(s, d))
removeStringImpl(*this, QStringView{QVarLengthArray(s, s + str.size())}, cs);
else
removeStringImpl(*this, qToStringViewIgnoringNull(str), cs);
@@ -3279,11 +3558,10 @@ QString &QString::remove(const QString &str, Qt::CaseSensitivity cs)
\since 5.11
\overload
- Removes every occurrence of the given \a str string in this
- string, and returns a reference to this string.
+ Removes every occurrence of the given Latin-1 string viewed by \a str
+ from this string, and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
This is the same as \c replace(str, "", cs).
@@ -3298,11 +3576,43 @@ QString &QString::remove(QLatin1StringView str, Qt::CaseSensitivity cs)
}
/*!
+ \fn QString &QString::removeAt(qsizetype pos)
+
+ \since 6.5
+
+ Removes the character at index \a pos. If \a pos is out of bounds
+ (i.e. \a pos >= size()), this function does nothing.
+
+ \sa remove()
+*/
+
+/*!
+ \fn QString &QString::removeFirst()
+
+ \since 6.5
+
+ Removes the first character in this string. If the string is empty,
+ this function does nothing.
+
+ \sa remove()
+*/
+
+/*!
+ \fn QString &QString::removeLast()
+
+ \since 6.5
+
+ Removes the last character in this string. If the string is empty,
+ this function does nothing.
+
+ \sa remove()
+*/
+
+/*!
Removes every occurrence of the character \a ch in this string, and
returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
@@ -3317,19 +3627,34 @@ QString &QString::remove(QLatin1StringView str, Qt::CaseSensitivity cs)
QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
{
const qsizetype idx = indexOf(ch, 0, cs);
- if (idx != -1) {
- const auto first = begin(); // implicit detach()
- auto last = end();
- if (cs == Qt::CaseSensitive) {
- last = std::remove(first + idx, last, ch);
- } else {
- const QChar c = ch.toCaseFolded();
- auto caseInsensEqual = [c](QChar x) {
- return c == x.toCaseFolded();
- };
- last = std::remove_if(first + idx, last, caseInsensEqual);
- }
- resize(last - first);
+ if (idx == -1)
+ return *this;
+
+ const bool isCase = cs == Qt::CaseSensitive;
+ ch = isCase ? ch : ch.toCaseFolded();
+ auto match = [ch, isCase](QChar x) {
+ return ch == (isCase ? x : x.toCaseFolded());
+ };
+
+
+ auto begin = d.begin();
+ auto first_match = begin + idx;
+ auto end = d.end();
+ if (!d->isShared()) {
+ auto it = std::remove_if(first_match, end, match);
+ d->erase(it, std::distance(it, end));
+ d.data()[d.size] = u'\0';
+ } else {
+ // Instead of detaching, create a new string and copy all characters except for
+ // the ones we're removing
+ // TODO: size() is more than the needed since "copy" would be shorter
+ QString copy{size(), Qt::Uninitialized};
+ auto dst = copy.d.begin();
+ auto it = std::copy(begin, first_match, dst); // Chunk before idx
+ it = std::remove_copy_if(first_match + 1, end, it, match);
+ copy.d.size = std::distance(dst, it);
+ copy.d.data()[copy.d.size] = u'\0';
+ *this = std::move(copy);
}
return *this;
}
@@ -3358,6 +3683,97 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
\sa remove()
*/
+
+/*! \internal
+ Instead of detaching, or reallocating if "before" is shorter than "after"
+ and there isn't enough capacity, create a new string, copy characters to it
+ as needed, then swap it with "str".
+*/
+static void replace_with_copy(QString &str, QSpan<size_t> indices, qsizetype blen,
+ QStringView after)
+{
+ const qsizetype alen = after.size();
+ const char16_t *after_b = after.utf16();
+
+ const QString::DataPointer &str_d = str.data_ptr();
+ auto src_start = str_d.begin();
+ const qsizetype newSize = str_d.size + indices.size() * (alen - blen);
+ QString copy{ newSize, Qt::Uninitialized };
+ QString::DataPointer &copy_d = copy.data_ptr();
+ auto dst = copy_d.begin();
+ for (size_t index : indices) {
+ auto hit = str_d.begin() + index;
+ dst = std::copy(src_start, hit, dst);
+ dst = std::copy_n(after_b, alen, dst);
+ src_start = hit + blen;
+ }
+ dst = std::copy(src_start, str_d.end(), dst);
+ str.swap(copy);
+}
+
+// No detaching or reallocation is needed
+static void replace_in_place(QString &str, QSpan<size_t> indices,
+ qsizetype blen, QStringView after)
+{
+ const qsizetype alen = after.size();
+ const char16_t *after_b = after.utf16();
+ const char16_t *after_e = after.utf16() + after.size();
+
+ if (blen == alen) { // Replace in place
+ for (size_t index : indices)
+ std::copy_n(after_b, alen, str.data_ptr().begin() + index);
+ } else if (blen > alen) { // Replace from front
+ char16_t *begin = str.data_ptr().begin();
+ char16_t *hit = begin + indices.front();
+ char16_t *to = hit;
+ to = std::copy_n(after_b, alen, to);
+ char16_t *movestart = hit + blen;
+ for (size_t index : indices.sliced(1)) {
+ hit = begin + index;
+ to = std::move(movestart, hit, to);
+ to = std::copy_n(after_b, alen, to);
+ movestart = hit + blen;
+ }
+ to = std::move(movestart, str.data_ptr().end(), to);
+ str.resize(std::distance(begin, to));
+ } else { // blen < alen, Replace from back
+ const qsizetype oldSize = str.data_ptr().size;
+ const qsizetype adjust = indices.size() * (alen - blen);
+ const qsizetype newSize = oldSize + adjust;
+
+ str.resize(newSize);
+ char16_t *begin = str.data_ptr().begin();
+ char16_t *moveend = begin + oldSize;
+ char16_t *to = str.data_ptr().end();
+
+ for (auto it = indices.rbegin(), end = indices.rend(); it != end; ++it) {
+ char16_t *hit = begin + *it;
+ char16_t *movestart = hit + blen;
+ to = std::move_backward(movestart, moveend, to);
+ to = std::copy_backward(after_b, after_e, to);
+ moveend = hit;
+ }
+ }
+}
+
+static void replace_helper(QString &str, QSpan<size_t> indices, qsizetype blen, QStringView after)
+{
+ const qsizetype oldSize = str.data_ptr().size;
+ const qsizetype adjust = indices.size() * (after.size() - blen);
+ const qsizetype newSize = oldSize + adjust;
+ if (str.data_ptr().needsDetach() || needsReallocate(str, newSize)) {
+ replace_with_copy(str, indices, blen, after);
+ return;
+ }
+
+ if (QtPrivate::q_points_into_range(after.begin(), str))
+ // Copy after if it lies inside our own d.b area (which we could
+ // possibly invalidate via a realloc or modify by replacement)
+ replace_in_place(str, indices, blen, QVarLengthArray(after.begin(), after.end()));
+ else
+ replace_in_place(str, indices, blen, after);
+}
+
/*!
\fn QString &QString::replace(qsizetype position, qsizetype n, const QString &after)
@@ -3376,17 +3792,17 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
*/
QString &QString::replace(qsizetype pos, qsizetype len, const QString &after)
{
- return replace(pos, len, after.constData(), after.length());
+ return replace(pos, len, after.constData(), after.size());
}
/*!
- \fn QString &QString::replace(qsizetype position, qsizetype n, const QChar *unicode, qsizetype size)
+ \fn QString &QString::replace(qsizetype position, qsizetype n, const QChar *after, qsizetype alen)
\overload replace()
Replaces \a n characters beginning at index \a position with the
- first \a size characters of the QChar array \a unicode and returns a
+ first \a alen characters of the QChar array \a after and returns a
reference to this string.
*/
-QString &QString::replace(qsizetype pos, qsizetype len, const QChar *unicode, qsizetype size)
+QString &QString::replace(qsizetype pos, qsizetype len, const QChar *after, qsizetype alen)
{
if (size_t(pos) > size_t(this->size()))
return *this;
@@ -3394,7 +3810,7 @@ QString &QString::replace(qsizetype pos, qsizetype len, const QChar *unicode, qs
len = this->size() - pos;
size_t index = pos;
- replace_helper(&index, 1, len, unicode, size);
+ replace_helper(*this, QSpan(&index, 1), len, QStringView{after, alen});
return *this;
}
@@ -3415,8 +3831,7 @@ QString &QString::replace(qsizetype pos, qsizetype len, QChar after)
Replaces every occurrence of the string \a before with the string \a
after and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
@@ -3433,90 +3848,6 @@ QString &QString::replace(const QString &before, const QString &after, Qt::CaseS
return replace(before.constData(), before.size(), after.constData(), after.size(), cs);
}
-namespace { // helpers for replace and its helper:
-QChar *textCopy(const QChar *start, qsizetype len)
-{
- const size_t size = len * sizeof(QChar);
- QChar *const copy = static_cast<QChar *>(::malloc(size));
- Q_CHECK_PTR(copy);
- ::memcpy(copy, start, size);
- return copy;
-}
-
-static bool pointsIntoRange(const QChar *ptr, const char16_t *base, qsizetype len)
-{
- const QChar *const start = reinterpret_cast<const QChar *>(base);
- const std::less<const QChar *> less;
- return !less(ptr, start) && less(ptr, start + len);
-}
-} // end namespace
-
-/*!
- \internal
- */
-void QString::replace_helper(size_t *indices, qsizetype nIndices, qsizetype blen, const QChar *after, qsizetype alen)
-{
- // Copy after if it lies inside our own d.b area (which we could
- // possibly invalidate via a realloc or modify by replacement).
- QChar *afterBuffer = nullptr;
- if (pointsIntoRange(after, d.data(), d.size)) // Use copy in place of vulnerable original:
- after = afterBuffer = textCopy(after, alen);
-
- QT_TRY {
- if (blen == alen) {
- // replace in place
- detach();
- for (qsizetype i = 0; i < nIndices; ++i)
- memcpy(d.data() + indices[i], after, alen * sizeof(QChar));
- } else if (alen < blen) {
- // replace from front
- detach();
- size_t to = indices[0];
- if (alen)
- memcpy(d.data()+to, after, alen*sizeof(QChar));
- to += alen;
- size_t movestart = indices[0] + blen;
- for (qsizetype i = 1; i < nIndices; ++i) {
- qsizetype msize = indices[i] - movestart;
- if (msize > 0) {
- memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar));
- to += msize;
- }
- if (alen) {
- memcpy(d.data() + to, after, alen * sizeof(QChar));
- to += alen;
- }
- movestart = indices[i] + blen;
- }
- qsizetype msize = d.size - movestart;
- if (msize > 0)
- memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar));
- resize(d.size - nIndices*(blen-alen));
- } else {
- // replace from back
- qsizetype adjust = nIndices*(alen-blen);
- qsizetype newLen = d.size + adjust;
- qsizetype moveend = d.size;
- resize(newLen);
-
- while (nIndices) {
- --nIndices;
- qsizetype movestart = indices[nIndices] + blen;
- qsizetype insertstart = indices[nIndices] + nIndices*(alen-blen);
- qsizetype moveto = insertstart + alen;
- memmove(d.data() + moveto, d.data() + movestart,
- (moveend - movestart)*sizeof(QChar));
- memcpy(d.data() + insertstart, after, alen * sizeof(QChar));
- moveend = movestart-blen;
- }
- }
- } QT_CATCH(const std::bad_alloc &) {
- ::free(afterBuffer);
- QT_RETHROW;
- }
- ::free(afterBuffer);
-}
-
/*!
\since 4.5
\overload replace()
@@ -3525,8 +3856,7 @@ void QString::replace_helper(size_t *indices, qsizetype nIndices, qsizetype blen
characters of \a before with the first \a alen characters of \a
after and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
*/
QString &QString::replace(const QChar *before, qsizetype blen,
const QChar *after, qsizetype alen,
@@ -3541,51 +3871,25 @@ QString &QString::replace(const QChar *before, qsizetype blen,
}
if (alen == 0 && blen == 0)
return *this;
+ if (alen == 1 && blen == 1)
+ return replace(*before, *after, cs);
QStringMatcher matcher(before, blen, cs);
- QChar *beforeBuffer = nullptr, *afterBuffer = nullptr;
qsizetype index = 0;
- while (1) {
- size_t indices[1024];
- size_t pos = 0;
- while (pos < 1024) {
- index = matcher.indexIn(*this, index);
- if (index == -1)
- break;
- indices[pos++] = index;
- if (blen) // Step over before:
- index += blen;
- else // Only count one instance of empty between any two characters:
- index++;
- }
- if (!pos) // Nothing to replace
- break;
-
- if (Q_UNLIKELY(index != -1)) {
- /*
- We're about to change data, that before and after might point
- into, and we'll need that data for our next batch of indices.
- */
- if (!afterBuffer && pointsIntoRange(after, d.data(), d.size))
- after = afterBuffer = textCopy(after, alen);
-
- if (!beforeBuffer && pointsIntoRange(before, d.data(), d.size)) {
- beforeBuffer = textCopy(before, blen);
- matcher = QStringMatcher(beforeBuffer, blen, cs);
- }
- }
- replace_helper(indices, pos, blen, after, alen);
-
- if (Q_LIKELY(index == -1)) // Nothing left to replace
- break;
- // The call to replace_helper just moved what index points at:
- index += pos*(alen-blen);
+ QVarLengthArray<size_t> indices;
+ while ((index = matcher.indexIn(*this, index)) != -1) {
+ indices.push_back(index);
+ if (blen) // Step over before:
+ index += blen;
+ else // Only count one instance of empty between any two characters:
+ index++;
}
- ::free(afterBuffer);
- ::free(beforeBuffer);
+ if (indices.isEmpty())
+ return *this;
+ replace_helper(*this, indices, blen, QStringView{after, alen});
return *this;
}
@@ -3594,8 +3898,7 @@ QString &QString::replace(const QChar *before, qsizetype blen,
Replaces every occurrence of the character \a ch in the string with
\a after and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
*/
QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs)
{
@@ -3608,35 +3911,27 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
if (size() == 0)
return *this;
- char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
+ const char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
- qsizetype index = 0;
- while (1) {
- size_t indices[1024];
- size_t pos = 0;
- if (cs == Qt::CaseSensitive) {
- while (pos < 1024 && index < size()) {
- if (d.data()[index] == cc)
- indices[pos++] = index;
- index++;
- }
- } else {
- while (pos < 1024 && index < size()) {
- if (QChar::toCaseFolded(d.data()[index]) == cc)
- indices[pos++] = index;
- index++;
- }
+ QVarLengthArray<size_t> indices;
+ if (cs == Qt::CaseSensitive) {
+ const char16_t *begin = d.begin();
+ const char16_t *end = d.end();
+ QStringView view(begin, end);
+ const char16_t *hit = nullptr;
+ while ((hit = QtPrivate::qustrchr(view, cc)) != end) {
+ indices.push_back(std::distance(begin, hit));
+ view = QStringView(std::next(hit), end);
}
- if (!pos) // Nothing to replace
- break;
-
- replace_helper(indices, pos, 1, after.constData(), after.size());
-
- if (Q_LIKELY(index == size())) // Nothing left to replace
- break;
- // The call to replace_helper just moved what index points at:
- index += pos*(after.size() - 1);
+ } else {
+ for (qsizetype i = 0; i < d.size; ++i)
+ if (QChar::toCaseFolded(d.data()[i]) == cc)
+ indices.push_back(i);
}
+ if (indices.isEmpty())
+ return *this;
+
+ replace_helper(*this, indices, 1, after);
return *this;
}
@@ -3645,34 +3940,43 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
Replaces every occurrence of the character \a before with the
character \a after and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
*/
QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs)
{
- if (d.size) {
- const qsizetype idx = indexOf(before, 0, cs);
- if (idx != -1) {
- detach();
- const char16_t a = after.unicode();
- char16_t *i = d.data();
- char16_t *const e = i + d.size;
- i += idx;
- *i = a;
- if (cs == Qt::CaseSensitive) {
- const char16_t b = before.unicode();
- while (++i != e) {
- if (*i == b)
- *i = a;
- }
- } else {
- const char16_t b = foldCase(before.unicode());
- while (++i != e) {
- if (foldCase(*i) == b)
- *i = a;
- }
- }
+ const qsizetype idx = indexOf(before, 0, cs);
+ if (idx == -1)
+ return *this;
+
+ const char16_t achar = after.unicode();
+ char16_t bchar = before.unicode();
+
+ auto matchesCIS = [](char16_t beforeChar) {
+ return [beforeChar](char16_t ch) { return foldAndCompare(ch, beforeChar); };
+ };
+
+ auto hit = d.begin() + idx;
+ if (!d.needsDetach()) {
+ *hit++ = achar;
+ if (cs == Qt::CaseSensitive) {
+ std::replace(hit, d.end(), bchar, achar);
+ } else {
+ bchar = foldCase(bchar);
+ std::replace_if(hit, d.end(), matchesCIS(bchar), achar);
+ }
+ } else {
+ QString other{ d.size, Qt::Uninitialized };
+ auto dest = std::copy(d.begin(), hit, other.d.begin());
+ *dest++ = achar;
+ ++hit;
+ if (cs == Qt::CaseSensitive) {
+ std::replace_copy(hit, d.end(), dest, bchar, achar);
+ } else {
+ bchar = foldCase(bchar);
+ std::replace_copy_if(hit, d.end(), dest, matchesCIS(bchar), achar);
}
+
+ swap(other);
}
return *this;
}
@@ -3681,22 +3985,23 @@ QString& QString::replace(QChar before, QChar after, Qt::CaseSensitivity cs)
\since 4.5
\overload replace()
- Replaces every occurrence of the string \a before with the string \a
- after and returns a reference to this string.
+ Replaces every occurrence in this string of the Latin-1 string viewed
+ by \a before with the Latin-1 string viewed by \a after, and returns a
+ reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\note The text is not rescanned after a replacement.
*/
QString &QString::replace(QLatin1StringView before, QLatin1StringView after, Qt::CaseSensitivity cs)
{
- qsizetype alen = after.size();
- qsizetype blen = before.size();
- QVarLengthArray<char16_t> a(alen);
- QVarLengthArray<char16_t> b(blen);
- qt_from_latin1(a.data(), after.latin1(), alen);
- qt_from_latin1(b.data(), before.latin1(), blen);
+ const qsizetype alen = after.size();
+ const qsizetype blen = before.size();
+ if (blen == 1 && alen == 1)
+ return replace(before.front(), after.front(), cs);
+
+ QVarLengthArray<char16_t> a = qt_from_latin1_to_qvla(after);
+ QVarLengthArray<char16_t> b = qt_from_latin1_to_qvla(before);
return replace((const QChar *)b.data(), blen, (const QChar *)a.data(), alen, cs);
}
@@ -3704,19 +4009,21 @@ QString &QString::replace(QLatin1StringView before, QLatin1StringView after, Qt:
\since 4.5
\overload replace()
- Replaces every occurrence of the string \a before with the string \a
- after and returns a reference to this string.
+ Replaces every occurrence in this string of the Latin-1 string viewed
+ by \a before with the string \a after, and returns a reference to this
+ string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\note The text is not rescanned after a replacement.
*/
QString &QString::replace(QLatin1StringView before, const QString &after, Qt::CaseSensitivity cs)
{
- qsizetype blen = before.size();
- QVarLengthArray<char16_t> b(blen);
- qt_from_latin1(b.data(), before.latin1(), blen);
+ const qsizetype blen = before.size();
+ if (blen == 1 && after.size() == 1)
+ return replace(before.front(), after.front(), cs);
+
+ QVarLengthArray<char16_t> b = qt_from_latin1_to_qvla(before);
return replace((const QChar *)b.data(), blen, after.constData(), after.d.size, cs);
}
@@ -3727,16 +4034,17 @@ QString &QString::replace(QLatin1StringView before, const QString &after, Qt::Ca
Replaces every occurrence of the string \a before with the string \a
after and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\note The text is not rescanned after a replacement.
*/
QString &QString::replace(const QString &before, QLatin1StringView after, Qt::CaseSensitivity cs)
{
- qsizetype alen = after.size();
- QVarLengthArray<char16_t> a(alen);
- qt_from_latin1(a.data(), after.latin1(), alen);
+ const qsizetype alen = after.size();
+ if (before.size() == 1 && alen == 1)
+ return replace(before.front(), after.front(), cs);
+
+ QVarLengthArray<char16_t> a = qt_from_latin1_to_qvla(after);
return replace(before.constData(), before.d.size, (const QChar *)a.data(), alen, cs);
}
@@ -3747,70 +4055,70 @@ QString &QString::replace(const QString &before, QLatin1StringView after, Qt::Ca
Replaces every occurrence of the character \a c with the string \a
after and returns a reference to this string.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\note The text is not rescanned after a replacement.
*/
QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity cs)
{
- qsizetype alen = after.size();
- QVarLengthArray<char16_t> a(alen);
- qt_from_latin1(a.data(), after.latin1(), alen);
+ const qsizetype alen = after.size();
+ if (alen == 1)
+ return replace(c, after.front(), cs);
+
+ QVarLengthArray<char16_t> a = qt_from_latin1_to_qvla(after);
return replace(&c, 1, (const QChar *)a.data(), alen, cs);
}
-
/*!
- \fn bool QString::operator==(const QString &s1, const QString &s2)
+ \fn bool QString::operator==(const QString &lhs, const QString &rhs)
\overload operator==()
- Returns \c true if string \a s1 is equal to string \a s2; otherwise
+ Returns \c true if string \a lhs is equal to string \a rhs; otherwise
returns \c false.
+ \include qstring.cpp compare-isNull-vs-isEmpty
+
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator==(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator==(const QString &lhs, const QLatin1StringView &rhs)
\overload operator==()
- Returns \c true if \a s1 is equal to \a s2; otherwise
+ Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false.
*/
/*!
- \fn bool QString::operator==(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator==(const QLatin1StringView &lhs, const QString &rhs)
\overload operator==()
- Returns \c true if \a s1 is equal to \a s2; otherwise
+ Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false.
*/
-/*! \fn bool QString::operator==(const QByteArray &other) const
+/*! \fn bool QString::operator==(const QString &lhs, const QByteArray &rhs)
\overload operator==()
- The \a other byte array is converted to a QString using the
- fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l 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.
- Returns \c true if this string is lexically equal to the parameter
- string \a other. Otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically equal to \a rhs.
+ Otherwise returns \c false.
*/
-/*! \fn bool QString::operator==(const char *other) const
+/*! \fn bool QString::operator==(const QString &lhs, const char * const &rhs)
\overload operator==()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3819,41 +4127,41 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
*/
/*!
- \fn bool QString::operator<(const QString &s1, const QString &s2)
+ \fn bool QString::operator<(const QString &lhs, const QString &rhs)
\overload operator<()
- Returns \c true if string \a s1 is lexically less than string
- \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than string
+ \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator<(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator<(const QString &lhs, const QLatin1StringView &rhs)
\overload operator<()
- Returns \c true if \a s1 is lexically less than \a s2;
+ Returns \c true if \a lhs is lexically less than \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator<(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator<(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<()
- Returns \c true if \a s1 is lexically less than \a s2;
+ Returns \c true if \a lhs is lexically less than \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator<(const QByteArray &other) const
+/*! \fn bool QString::operator<(const QString &lhs, const QByteArray &rhs)
\overload operator<()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3861,15 +4169,14 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator<(const char *other) const
+/*! \fn bool QString::operator<(const QString &lhs, const char * const &rhs)
- Returns \c true if this string is lexically less than string \a other.
+ Returns \c true if string \a lhs is lexically less than string \a rhs.
Otherwise returns \c false.
\overload operator<()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3877,39 +4184,39 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator<=(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator<=(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is lexically less than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than or equal to
+ string \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator<=(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator<=(const QString &lhs, const QLatin1StringView &rhs)
\overload operator<=()
- Returns \c true if \a s1 is lexically less than or equal to \a s2;
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator<=(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator<=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<=()
- Returns \c true if \a s1 is lexically less than or equal to \a s2;
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator<=(const QByteArray &other) const
+/*! \fn bool QString::operator<=(const QString &lhs, const QByteArray &rhs)
\overload operator<=()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3917,12 +4224,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator<=(const char *other) const
+/*! \fn bool QString::operator<=(const QString &lhs, const char * const &rhs)
\overload operator<=()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3930,39 +4236,39 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator>(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator>(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is lexically greater than string \a s2;
+ Returns \c true if string \a lhs is lexically greater than string \a rhs;
otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator>(const QString &lhs, const QLatin1StringView &rhs)
\overload operator>()
- Returns \c true if \a s1 is lexically greater than \a s2;
+ Returns \c true if \a lhs is lexically greater than \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator>(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator>(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>()
- Returns \c true if \a s1 is lexically greater than \a s2;
+ Returns \c true if \a lhs is lexically greater than \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator>(const QByteArray &other) const
+/*! \fn bool QString::operator>(const QString &lhs, const QByteArray &rhs)
\overload operator>()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3970,12 +4276,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator>(const char *other) const
+/*! \fn bool QString::operator>(const QString &lhs, const char * const &rhs)
\overload operator>()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -3983,39 +4288,39 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator>=(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator>=(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is lexically greater than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically greater than or equal to
+ string \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>=(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator>=(const QString &lhs, const QLatin1StringView &rhs)
\overload operator>=()
- Returns \c true if \a s1 is lexically greater than or equal to \a s2;
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator>=(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator>=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>=()
- Returns \c true if \a s1 is lexically greater than or equal to \a s2;
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator>=(const QByteArray &other) const
+/*! \fn bool QString::operator>=(const QString &lhs, const QByteArray &rhs)
\overload operator>=()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded in
- the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4023,12 +4328,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator>=(const char *other) const
+/*! \fn bool QString::operator>=(const QString &lhs, const char * const &rhs)
\overload operator>=()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4036,29 +4340,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator!=(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator!=(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is not equal to string \a s2;
+ Returns \c true if string \a lhs is not equal to string \a rhs;
otherwise returns \c false.
\sa {Comparing Strings}
*/
-/*! \fn bool QString::operator!=(const QString &s1, QLatin1StringView s2)
+/*! \fn bool QString::operator!=(const QString &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is not equal to string \a s2.
+ Returns \c true if string \a lhs is not equal to string \a rhs.
Otherwise returns \c false.
\overload operator!=()
*/
-/*! \fn bool QString::operator!=(const QByteArray &other) const
+/*! \fn bool QString::operator!=(const QString &lhs, const QByteArray &rhs)
\overload operator!=()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4066,12 +4370,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator!=(const char *other) const
+/*! \fn bool QString::operator!=(const QString &lhs, const char * const &rhs)
\overload operator!=()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4079,63 +4382,134 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-#if QT_STRINGVIEW_LEVEL < 2
+/*! \fn bool QString::operator==(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is equal to the UTF-8 encoding of
+ \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator!=(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is not equal to the UTF-8 encoding of
+ \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator<(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is lexically less than the UTF-8 encoding
+ of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator>(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is lexically greater than the UTF-8
+ encoding of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator<=(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is lexically less than or equal to the
+ UTF-8 encoding of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator>=(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is greater than or equal to the UTF-8
+ encoding of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
/*!
- Returns the index position of the first occurrence of the string \a
- str in this string, searching forward from index position \a
- from. Returns -1 if \a str is not found.
+ \include qstring.qdocinc {qstring-first-index-of} {string} {str}
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
\snippet qstring/main.cpp 24
- 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.
+ \include qstring.qdocinc negative-index-start-search-from-end
\sa lastIndexOf(), contains(), count()
*/
qsizetype QString::indexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
{
- return QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs);
+ return QtPrivate::findString(QStringView(unicode(), size()), from, QStringView(str.unicode(), str.size()), cs);
}
-#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\fn qsizetype QString::indexOf(QStringView str, qsizetype 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.
+ \include qstring.qdocinc {qstring-first-index-of} {string view} {str}
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
- 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.
+ \include qstring.qdocinc negative-index-start-search-from-end
\sa QStringView::indexOf(), lastIndexOf(), contains(), count()
*/
/*!
\since 4.5
- Returns the index position of the first occurrence of the string \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.
+ \include {qstring.qdocinc} {qstring-first-index-of} {Latin-1 string viewed by} {str}
+
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
\snippet qstring/main.cpp 24
- 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.
+ \include qstring.qdocinc negative-index-start-search-from-end
\sa lastIndexOf(), contains(), count()
*/
@@ -4146,27 +4520,20 @@ qsizetype QString::indexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensit
}
/*!
+ \fn qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
\overload indexOf()
- Returns the index position of the first occurrence of the
- character \a ch in the string, searching forward from index
- position \a from. Returns -1 if \a ch could not be found.
+ \include qstring.qdocinc {qstring-first-index-of} {character} {ch}
*/
-qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
-{
- return qFindChar(QStringView(unicode(), length()), ch, from, cs);
-}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
- Returns the index position of the last occurrence of the string \a
- str in this string, searching backward from index position \a
- from. If \a from is -1, 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.
+ \include qstring.qdocinc {qstring-last-index-of} {string} {str}
+
+ \include qstring.qdocinc negative-index-start-search-from-end
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ Returns -1 if \a str is not found.
+
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
@@ -4194,8 +4561,7 @@ qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensi
Returns the index position of the last occurrence of the string \a
str in this string. 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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
@@ -4204,20 +4570,18 @@ qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensi
\sa indexOf(), contains(), count()
*/
-#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.5
\overload lastIndexOf()
- Returns the index position of the last occurrence of the string \a
- str in this string, searching backward from index position \a
- from. If \a from is -1, 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.
+ \include qstring.qdocinc {qstring-last-index-of} {Latin-1 string viewed by} {str}
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc negative-index-start-search-from-end
+
+ Returns -1 if \a str is not found.
+
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
@@ -4245,8 +4609,7 @@ qsizetype QString::lastIndexOf(QLatin1StringView str, qsizetype from, Qt::CaseSe
Returns the index position of the last occurrence of the string \a
str in this string. 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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
@@ -4256,15 +4619,11 @@ qsizetype QString::lastIndexOf(QLatin1StringView str, qsizetype from, Qt::CaseSe
*/
/*!
+ \fn qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
\overload lastIndexOf()
- Returns the index position of the last occurrence of the character
- \a ch, searching backward from position \a from.
+ \include qstring.qdocinc {qstring-last-index-of} {character} {ch}
*/
-qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
-{
- return qLastIndexOf(QStringView(*this), ch, from, cs);
-}
/*!
\fn QString::lastIndexOf(QChar ch, Qt::CaseSensitivity) const
@@ -4277,14 +4636,13 @@ qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs)
\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, 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.
+ \include qstring.qdocinc {qstring-last-index-of} {string view} {str}
+
+ \include qstring.qdocinc negative-index-start-search-from-end
+
+ 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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\note When searching for a 0-length \a str, the match at the end of
the data is excluded from the search by a negative \a from, even
@@ -4304,8 +4662,7 @@ qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs)
Returns the index position of the last occurrence of the string view \a
str in this string. 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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa indexOf(), contains(), count()
*/
@@ -4355,8 +4712,8 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
// 1. build the backreferences list, holding where the backreferences
// are in the replacement string
- QList<QStringCapture> backReferences;
- const qsizetype al = after.length();
+ QVarLengthArray<QStringCapture> backReferences;
+ const qsizetype al = after.size();
const QChar *ac = after.unicode();
for (qsizetype i = 0; i < al - 1; i++) {
@@ -4387,7 +4744,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
qsizetype newLength = 0; // length of the new string, with all the replacements
qsizetype lastEnd = 0;
- QList<QStringView> chunks;
+ QVarLengthArray<QStringView> chunks;
const QStringView copyView{ copy }, afterView{ after };
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
@@ -4401,7 +4758,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
lastEnd = 0;
// add the after string, with replacements for the backreferences
- for (const QStringCapture &backReference : qAsConst(backReferences)) {
+ for (const QStringCapture &backReference : std::as_const(backReferences)) {
// part of "after" before the backreference
len = backReference.pos - lastEnd;
if (len > 0) {
@@ -4420,7 +4777,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
}
// add the last part of the after string
- len = afterView.length() - lastEnd;
+ len = afterView.size() - lastEnd;
if (len > 0) {
chunks << afterView.mid(lastEnd, len);
newLength += len;
@@ -4430,17 +4787,17 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
}
// 3. trailing string after the last match
- if (copyView.length() > lastEnd) {
+ if (copyView.size() > lastEnd) {
chunks << copyView.mid(lastEnd);
- newLength += copyView.length() - lastEnd;
+ newLength += copyView.size() - lastEnd;
}
// 4. assemble the chunks together
resize(newLength);
qsizetype i = 0;
QChar *uc = data();
- for (const QStringView &chunk : qAsConst(chunks)) {
- qsizetype len = chunk.length();
+ for (const QStringView &chunk : std::as_const(chunks)) {
+ qsizetype len = chunk.size();
memcpy(uc + i, chunk.constData(), len * sizeof(QChar));
i += len;
}
@@ -4453,8 +4810,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
Returns the number of (potentially overlapping) occurrences of
the string \a str in this string.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa contains(), indexOf()
*/
@@ -4469,8 +4825,7 @@ qsizetype QString::count(const QString &str, Qt::CaseSensitivity cs) const
Returns the number of occurrences of character \a ch in the string.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa contains(), indexOf()
*/
@@ -4486,8 +4841,7 @@ qsizetype QString::count(QChar ch, Qt::CaseSensitivity cs) const
Returns the number of (potentially overlapping) occurrences of the
string view \a str in this string.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa contains(), indexOf()
*/
@@ -4496,21 +4850,18 @@ qsizetype QString::count(QStringView str, Qt::CaseSensitivity cs) const
return QtPrivate::count(*this, str, 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
\a str; otherwise returns \c false.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
Example:
\snippet qstring/main.cpp 17
\sa indexOf(), count()
*/
-#endif // QT_STRINGVIEW_LEVEL < 2
/*! \fn bool QString::contains(QLatin1StringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
\since 5.3
@@ -4536,8 +4887,7 @@ qsizetype QString::count(QStringView str, Qt::CaseSensitivity cs) const
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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa indexOf(), count()
*/
@@ -4560,7 +4910,7 @@ qsizetype QString::count(QStringView str, Qt::CaseSensitivity cs) const
*/
qsizetype QString::indexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const
{
- return QtPrivate::indexOf(QStringView(*this), re, from, rmatch);
+ return QtPrivate::indexOf(QStringView(*this), this, re, from, rmatch);
}
/*!
@@ -4568,9 +4918,11 @@ qsizetype QString::indexOf(const QRegularExpression &re, qsizetype from, QRegula
Returns the index position of the last match of the regular
expression \a re in the string, which starts before the index
- position \a from. If \a from is -1, 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 re didn't match anywhere.
+ position \a from.
+
+ \include qstring.qdocinc negative-index-start-search-from-end
+
+ Returns -1 if \a re didn't match anywhere.
If the match is successful and \a rmatch is not \nullptr, it also
writes the results of the match into the QRegularExpressionMatch object
@@ -4594,7 +4946,7 @@ qsizetype QString::indexOf(const QRegularExpression &re, qsizetype from, QRegula
*/
qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const
{
- return QtPrivate::lastIndexOf(QStringView(*this), re, from, rmatch);
+ return QtPrivate::lastIndexOf(QStringView(*this), this, re, from, rmatch);
}
/*!
@@ -4633,7 +4985,7 @@ qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRe
bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch) const
{
- return QtPrivate::contains(QStringView(*this), re, rmatch);
+ return QtPrivate::contains(QStringView(*this), this, re, rmatch);
}
/*!
@@ -4791,7 +5143,7 @@ public:
};
Q_DECLARE_TYPEINFO(qt_section_chunk, Q_RELOCATABLE_TYPE);
-static QString extractSections(const QList<qt_section_chunk> &sections, qsizetype start, qsizetype end,
+static QString extractSections(QSpan<qt_section_chunk> sections, qsizetype start, qsizetype end,
QString::SectionFlags flags)
{
const qsizetype sectionsSize = sections.size();
@@ -4804,8 +5156,8 @@ static QString extractSections(const QList<qt_section_chunk> &sections, qsizetyp
} else {
qsizetype skip = 0;
for (qsizetype k = 0; k < sectionsSize; ++k) {
- const qt_section_chunk &section = sections.at(k);
- if (section.length == section.string.length())
+ const qt_section_chunk &section = sections[k];
+ if (section.length == section.string.size())
skip++;
}
if (start < 0)
@@ -4820,8 +5172,8 @@ static QString extractSections(const QList<qt_section_chunk> &sections, qsizetyp
qsizetype x = 0;
qsizetype first_i = start, last_i = end;
for (qsizetype i = 0; x <= end && i < sectionsSize; ++i) {
- const qt_section_chunk &section = sections.at(i);
- const bool empty = (section.length == section.string.length());
+ const qt_section_chunk &section = sections[i];
+ const bool empty = (section.length == section.string.size());
if (x >= start) {
if (x == start)
first_i = i;
@@ -4837,13 +5189,13 @@ static QString extractSections(const QList<qt_section_chunk> &sections, qsizetyp
}
if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) {
- const qt_section_chunk &section = sections.at(first_i);
+ const qt_section_chunk &section = sections[first_i];
ret.prepend(section.string.left(section.length));
}
if ((flags & QString::SectionIncludeTrailingSep)
&& last_i < sectionsSize - 1) {
- const qt_section_chunk &section = sections.at(last_i+1);
+ const qt_section_chunk &section = sections[last_i + 1];
ret += section.string.left(section.length);
}
@@ -4879,8 +5231,8 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
if (flags & SectionCaseInsensitiveSeps)
sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption);
- QList<qt_section_chunk> sections;
- qsizetype n = length(), m = 0, last_m = 0, last_len = 0;
+ QVarLengthArray<qt_section_chunk> sections;
+ qsizetype n = size(), m = 0, last_m = 0, last_len = 0;
QRegularExpressionMatchIterator iterator = sep.globalMatch(*this);
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
@@ -4896,6 +5248,9 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
#endif // QT_CONFIG(regularexpression)
/*!
+ \fn QString QString::left(qsizetype n) const &
+ \fn QString QString::left(qsizetype n) &&
+
Returns a substring that contains the \a n leftmost characters
of the string.
@@ -4907,14 +5262,11 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
-QString QString::left(qsizetype n) const
-{
- if (size_t(n) >= size_t(size()))
- return *this;
- return QString((const QChar*) d.data(), n);
-}
/*!
+ \fn QString QString::right(qsizetype n) const &
+ \fn QString QString::right(qsizetype n) &&
+
Returns a substring that contains the \a n rightmost characters
of the string.
@@ -4924,16 +5276,13 @@ QString QString::left(qsizetype n) const
The entire string is returned if \a n is greater than or equal
to size(), or less than zero.
- \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
+ \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QString QString::right(qsizetype n) const
-{
- if (size_t(n) >= size_t(size()))
- return *this;
- return QString(constData() + size() - n, n);
-}
/*!
+ \fn QString QString::mid(qsizetype position, qsizetype n) const &
+ \fn QString QString::mid(qsizetype position, qsizetype n) &&
+
Returns a string that contains \a n characters of this string,
starting at the specified \a position index.
@@ -4946,11 +5295,9 @@ QString QString::right(qsizetype n) const
\a n is -1 (default), the function returns all characters that
are available from the specified \a position.
-
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), sliced(), chopped(), chop(), truncate(), slice()
*/
-
-QString QString::mid(qsizetype position, qsizetype n) const
+QString QString::mid(qsizetype position, qsizetype n) const &
{
qsizetype p = position;
qsizetype l = n;
@@ -4963,14 +5310,33 @@ QString QString::mid(qsizetype position, qsizetype n) const
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
- return QString(constData() + p, l);
+ return sliced(p, l);
}
- Q_UNREACHABLE();
- return QString();
+ Q_UNREACHABLE_RETURN(QString());
+}
+
+QString QString::mid(qsizetype position, qsizetype n) &&
+{
+ qsizetype p = position;
+ qsizetype l = n;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(size(), &p, &l)) {
+ case QContainerImplHelper::Null:
+ return QString();
+ case QContainerImplHelper::Empty:
+ resize(0); // keep capacity if we've reserve()d
+ [[fallthrough]];
+ case QContainerImplHelper::Full:
+ return std::move(*this);
+ case QContainerImplHelper::Subset:
+ return std::move(*this).sliced(p, l);
+ }
+ Q_UNREACHABLE_RETURN(QString());
}
/*!
- \fn QString QString::first(qsizetype n) const
+ \fn QString QString::first(qsizetype n) const &
+ \fn QString QString::first(qsizetype n) &&
\since 6.0
Returns a string that contains the first \a n characters
@@ -4980,11 +5346,12 @@ QString QString::mid(qsizetype position, qsizetype n) const
\snippet qstring/main.cpp 31
- \sa last(), sliced(), startsWith(), chopped(), chop(), truncate()
+ \sa last(), sliced(), startsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QString QString::last(qsizetype n) const
+ \fn QString QString::last(qsizetype n) const &
+ \fn QString QString::last(qsizetype n) &&
\since 6.0
Returns the string that contains the last \a n characters of this string.
@@ -4993,11 +5360,12 @@ QString QString::mid(qsizetype position, qsizetype n) const
\snippet qstring/main.cpp 48
- \sa first(), sliced(), endsWith(), chopped(), chop(), truncate()
+ \sa first(), sliced(), endsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QString QString::sliced(qsizetype pos, qsizetype n) const
+ \fn QString QString::sliced(qsizetype pos, qsizetype n) const &
+ \fn QString QString::sliced(qsizetype pos, qsizetype n) &&
\since 6.0
Returns a string that contains \a n characters of this string,
@@ -5008,11 +5376,20 @@ QString QString::mid(qsizetype position, qsizetype n) const
\snippet qstring/main.cpp 34
- \sa first(), last(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
*/
+QString QString::sliced_helper(QString &str, qsizetype pos, qsizetype n)
+{
+ if (n == 0)
+ return QString(DataPointer::fromRawData(&_empty, 0));
+ DataPointer d = std::move(str.d).sliced(pos, n);
+ d.data()[n] = 0;
+ return QString(std::move(d));
+}
/*!
- \fn QString QString::sliced(qsizetype pos) const
+ \fn QString QString::sliced(qsizetype pos) const &
+ \fn QString QString::sliced(qsizetype pos) &&
\since 6.0
\overload
@@ -5021,11 +5398,40 @@ QString QString::mid(qsizetype position, qsizetype n) const
\note The behavior is undefined when \a pos < 0 or \a pos > size().
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QString QString::chopped(qsizetype len) const
+ \fn QString &QString::slice(qsizetype pos, qsizetype n)
+ \since 6.8
+
+ Modifies this string to start at position \a pos, extending for \a n
+ characters (code points), and returns a reference to this string.
+
+ \note The behavior is undefined if \a pos < 0, \a n < 0,
+ or \a pos + \a n > size().
+
+ \snippet qstring/main.cpp 86
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QString &QString::slice(qsizetype pos)
+ \since 6.8
+ \overload
+
+ Modifies this string to start at position \a pos and extending to its end,
+ and returns a reference to this string.
+
+ \note The behavior is undefined if \a pos < 0 or \a pos > size().
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QString QString::chopped(qsizetype len) const &
+ \fn QString QString::chopped(qsizetype len) &&
\since 5.10
Returns a string that contains the size() - \a len leftmost characters
@@ -5033,16 +5439,14 @@ QString QString::mid(qsizetype position, qsizetype n) const
\note The behavior is undefined if \a len is negative or greater than size().
- \sa endsWith(), first(), last(), sliced(), chop(), truncate()
+ \sa endsWith(), first(), last(), sliced(), chop(), truncate(), slice()
*/
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns \c true if the string starts with \a s; otherwise returns
\c false.
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\snippet qstring/main.cpp 65
@@ -5052,7 +5456,6 @@ bool QString::startsWith(const QString& s, Qt::CaseSensitivity cs) const
{
return qt_starts_with_impl(QStringView(*this), QStringView(s), cs);
}
-#endif
/*!
\overload startsWith()
@@ -5085,19 +5488,16 @@ bool QString::startsWith(QChar c, Qt::CaseSensitivity cs) const
Returns \c true if the string starts with 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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa endsWith()
*/
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns \c true if the string ends with \a s; otherwise returns
\c false.
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\snippet qstring/main.cpp 20
@@ -5107,7 +5507,6 @@ bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
{
return qt_ends_with_impl(QStringView(*this), QStringView(s), cs);
}
-#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\fn bool QString::endsWith(QStringView str, Qt::CaseSensitivity cs) const
@@ -5116,8 +5515,7 @@ bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
Returns \c true if the string ends with 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.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa startsWith()
*/
@@ -5145,6 +5543,27 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
return foldCase(at(size() - 1)) == foldCase(c);
}
+static bool checkCase(QStringView s, QUnicodeTables::Case c) noexcept
+{
+ QStringIterator it(s);
+ while (it.hasNext()) {
+ const char32_t uc = it.next();
+ if (qGetProp(uc)->cases[c].diff)
+ return false;
+ }
+ return true;
+}
+
+bool QtPrivate::isLower(QStringView s) noexcept
+{
+ return checkCase(s, QUnicodeTables::LowerCase);
+}
+
+bool QtPrivate::isUpper(QStringView s) noexcept
+{
+ return checkCase(s, QUnicodeTables::UpperCase);
+}
+
/*!
Returns \c true if the string is uppercase, that is, it's identical
to its toUpper() folding.
@@ -5160,15 +5579,7 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
*/
bool QString::isUpper() const
{
- QStringIterator it(*this);
-
- while (it.hasNext()) {
- const char32_t uc = it.next();
- if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff)
- return false;
- }
-
- return true;
+ return QtPrivate::isUpper(qToStringViewIgnoringNull(*this));
}
/*!
@@ -5186,15 +5597,7 @@ bool QString::isUpper() const
*/
bool QString::isLower() const
{
- QStringIterator it(*this);
-
- while (it.hasNext()) {
- const char32_t uc = it.next();
- if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff)
- return false;
- }
-
- return true;
+ return QtPrivate::isLower(qToStringViewIgnoringNull(*this));
}
static QByteArray qt_convert_to_latin1(QStringView string);
@@ -5242,7 +5645,7 @@ static QByteArray qt_convert_to_latin1(QStringView string)
if (Q_UNLIKELY(string.isNull()))
return QByteArray();
- QByteArray ba(string.length(), Qt::Uninitialized);
+ QByteArray ba(string.size(), Qt::Uninitialized);
// since we own the only copy, we're going to const_cast the constData;
// that avoids an unnecessary call to detach() and expansion code that will never get used
@@ -5280,6 +5683,21 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
return QByteArray(std::move(ba_d));
}
+// QLatin1 methods that use helpers from qstring.cpp
+char16_t *QLatin1::convertToUnicode(char16_t *out, QLatin1StringView in) noexcept
+{
+ const qsizetype len = in.size();
+ qt_from_latin1(out, in.data(), len);
+ return std::next(out, len);
+}
+
+char *QLatin1::convertFromUnicode(char *out, QStringView in) noexcept
+{
+ const qsizetype len = in.size();
+ qt_to_latin1(reinterpret_cast<uchar *>(out), in.utf16(), len);
+ return out + len;
+}
+
/*!
\fn QByteArray QString::toLatin1() const
@@ -5298,15 +5716,13 @@ static QByteArray qt_convert_to_local_8bit(QStringView string);
\fn QByteArray QString::toLocal8Bit() const
Returns the local 8-bit representation of the string as a
- QByteArray. The returned byte array is undefined if the string
- contains characters not supported by the local 8-bit encoding.
+ QByteArray.
- On Unix systems this is equivalen to toUtf8(), on Windows the systems
- current code page is being used.
+ \include qstring.qdocinc {qstring-local-8-bit-equivalent} {toUtf8}
If this string contains any characters that cannot be encoded in the
- locale, the returned byte array is undefined. Those characters may be
- suppressed or replaced by another.
+ local 8-bit encoding, the returned byte array is undefined. Those
+ characters may be suppressed or replaced by another.
\sa fromLocal8Bit(), toLatin1(), toUtf8(), QStringEncoder
*/
@@ -5331,7 +5747,7 @@ static QByteArray qt_convert_to_local_8bit(QStringView string)
Returns a local 8-bit representation of \a string as a QByteArray.
- On Unix systems this is equivalen to toUtf8(), on Windows the systems
+ On Unix systems this is equivalent to toUtf8(), on Windows the systems
current code page is being used.
The behavior is undefined if \a string contains characters not
@@ -5411,7 +5827,7 @@ QList<uint> QString::toUcs4() const
static QList<uint> qt_convert_to_ucs4(QStringView string)
{
- QList<uint> v(string.length());
+ QList<uint> v(string.size());
uint *a = const_cast<uint*>(v.constData());
QStringIterator it(string);
while (it.hasNext())
@@ -5460,7 +5876,7 @@ QString QString::fromLatin1(QByteArrayView ba)
} else if (ba.size() == 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(ba.size()), ba.size());
+ d = DataPointer(ba.size(), ba.size());
Q_CHECK_PTR(d.data());
d.data()[ba.size()] = '\0';
char16_t *dst = d.data();
@@ -5499,8 +5915,7 @@ QString QString::fromLatin1(QByteArrayView ba)
If \a size is \c{-1}, \c{strlen(str)} is used instead.
- On Unix systems this is equivalen to fromUtf8(), on Windows the systems
- current code page is being used.
+ \include qstring.qdocinc {qstring-local-8-bit-equivalent} {fromUtf8}
\sa toLocal8Bit(), fromLatin1(), fromUtf8()
*/
@@ -5512,6 +5927,8 @@ QString QString::fromLatin1(QByteArrayView ba)
Returns a QString initialized with the 8-bit string \a str.
+ \include qstring.qdocinc {qstring-local-8-bit-equivalent} {fromUtf8}
+
\note: any null ('\\0') bytes in the byte array will be included in this
string, converted to Unicode null characters (U+0000). This behavior is
different from Qt 5.x.
@@ -5524,6 +5941,8 @@ QString QString::fromLatin1(QByteArrayView ba)
Returns a QString initialized with the 8-bit string \a str.
+ \include qstring.qdocinc {qstring-local-8-bit-equivalent} {fromUtf8}
+
\note: any null ('\\0') bytes in the byte array will be included in this
string, converted to Unicode null characters (U+0000).
*/
@@ -5605,6 +6024,7 @@ QString QString::fromUtf8(QByteArrayView ba)
return QUtf8::convertToUnicode(ba);
}
+#ifndef QT_BOOTSTRAPPED
/*!
\since 5.3
Returns a QString initialized with the first \a size characters
@@ -5616,7 +6036,7 @@ QString QString::fromUtf8(QByteArrayView ba)
host byte order is assumed.
This function is slow compared to the other Unicode conversions.
- Use QString(const QChar *, int) or QString(const QChar *) if possible.
+ Use QString(const QChar *, qsizetype) or QString(const QChar *) if possible.
QString makes a deep copy of the Unicode data.
@@ -5666,7 +6086,7 @@ QString QString::fromUcs4(const char32_t *unicode, qsizetype size)
QStringDecoder toUtf16(QStringDecoder::Utf32, QStringDecoder::Flag::Stateless);
return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 4));
}
-
+#endif // !QT_BOOTSTRAPPED
/*!
Resizes the string to \a size characters and copies \a unicode
@@ -5731,9 +6151,7 @@ namespace {
template <typename StringView>
StringView qt_trimmed(StringView s) noexcept
{
- auto begin = s.begin();
- auto end = s.end();
- QStringAlgorithms<const StringView>::trimmed_helper_positions(begin, end);
+ const auto [begin, end] = QStringAlgorithms<const StringView>::trimmed_helper_positions(s);
return StringView{begin, end};
}
}
@@ -5940,12 +6358,8 @@ void QString::chop(qsizetype n)
QString& QString::fill(QChar ch, qsizetype size)
{
resize(size < 0 ? d.size : size);
- if (d.size) {
- QChar *i = (QChar*)d.data() + d.size;
- QChar *b = (QChar*)d.data();
- while (i != b)
- *--i = ch;
- }
+ if (d.size)
+ std::fill(d.data(), d.data() + d.size, ch.unicode());
return *this;
}
@@ -5971,6 +6385,16 @@ QString& QString::fill(QChar ch, qsizetype size)
\sa isEmpty(), resize()
*/
+/*!
+ \fn qsizetype QString::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the string can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn bool QString::isNull() const
Returns \c true if this string is null; otherwise returns \c false.
@@ -6020,7 +6444,14 @@ QString& QString::fill(QChar ch, qsizetype size)
\overload operator+=()
- Appends the Latin-1 string \a str to this string.
+ Appends the Latin-1 string viewed by \a str to this string.
+*/
+
+/*! \fn QString &QString::operator+=(QUtf8StringView str)
+ \since 6.5
+ \overload operator+=()
+
+ Appends the UTF-8 string view \a str to this string.
*/
/*! \fn QString &QString::operator+=(const QByteArray &ba)
@@ -6066,67 +6497,68 @@ QString& QString::fill(QChar ch, qsizetype size)
*/
/*!
- \fn bool QString::operator==(const char *s1, const QString &s2)
+ \fn bool QString::operator==(const char * const &lhs, const QString &rhs)
\overload operator==()
- Returns \c true if \a s1 is equal to \a s2; otherwise returns \c false.
- Note that no string is equal to \a s1 being 0.
+ Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
+ Note that no string is equal to \a lhs being 0.
- Equivalent to \c {s1 != 0 && compare(s1, s2) == 0}.
+ Equivalent to \c {lhs != 0 && compare(lhs, rhs) == 0}.
*/
/*!
- \fn bool QString::operator!=(const char *s1, const QString &s2)
+ \fn bool QString::operator!=(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is not equal to \a s2; otherwise returns
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise returns
\c false.
- For \a s1 != 0, this is equivalent to \c {compare(} \a s1, \a s2
- \c {) != 0}. Note that no string is equal to \a s1 being 0.
+ For \a lhs != 0, this is equivalent to \c {compare(} \a lhs, \a rhs
+ \c {) != 0}. Note that no string is equal to \a lhs being 0.
*/
/*!
- \fn bool QString::operator<(const char *s1, const QString &s2)
+ \fn bool QString::operator<(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically less than \a s2; otherwise
- returns \c false. For \a s1 != 0, this is equivalent to \c
- {compare(s1, s2) < 0}.
+ Returns \c true if \a lhs is lexically less than \a rhs; otherwise
+ returns \c false. For \a lhs != 0, this is equivalent to \c
+ {compare(lhs, rhs) < 0}.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator<=(const char *s1, const QString &s2)
+ \fn bool QString::operator<=(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically less than or equal to \a s2;
- otherwise returns \c false. For \a s1 != 0, this is equivalent to \c
- {compare(s1, s2) <= 0}.
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
+ otherwise returns \c false. For \a lhs != 0, this is equivalent to \c
+ {compare(lhs, rhs) <= 0}.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>(const char *s1, const QString &s2)
+ \fn bool QString::operator>(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically greater than \a s2; otherwise
- returns \c false. Equivalent to \c {compare(s1, s2) > 0}.
+ Returns \c true if \a lhs is lexically greater than \a rhs; otherwise
+ returns \c false. Equivalent to \c {compare(lhs, rhs) > 0}.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>=(const char *s1, const QString &s2)
+ \fn bool QString::operator>=(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically greater than or equal to \a s2;
- otherwise returns \c false. For \a s1 != 0, this is equivalent to \c
- {compare(s1, s2) >= 0}.
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
+ otherwise returns \c false. For \a lhs != 0, this is equivalent to \c
+ {compare(lhs, rhs) >= 0}.
\sa {Comparing Strings}
*/
/*!
- \fn const QString operator+(const QString &s1, const QString &s2)
+ \fn QString operator+(const QString &s1, const QString &s2)
+ \fn QString operator+(QString &&s1, const QString &s2)
\relates QString
Returns a string which is the result of concatenating \a s1 and \a
@@ -6134,7 +6566,7 @@ QString& QString::fill(QChar ch, qsizetype size)
*/
/*!
- \fn const QString operator+(const QString &s1, const char *s2)
+ \fn QString operator+(const QString &s1, const char *s2)
\relates QString
Returns a string which is the result of concatenating \a s1 and \a
@@ -6145,7 +6577,7 @@ QString& QString::fill(QChar ch, qsizetype size)
*/
/*!
- \fn const QString operator+(const char *s1, const QString &s2)
+ \fn QString operator+(const char *s1, const QString &s2)
\relates QString
Returns a string which is the result of concatenating \a s1 and \a
@@ -6159,12 +6591,11 @@ QString& QString::fill(QChar ch, qsizetype size)
\fn int QString::compare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs)
\since 4.2
- Compares \a s1 with \a s2 and returns an integer less than, equal
- to, or greater than zero if \a s1 is less than, equal to, or
- greater than \a s2.
+ Compares the string \a s1 with the string \a s2 and returns a negative integer
+ if \a s1 is less than \a s2, a positive integer if it is greater than \a s2,
+ and zero if they are equal.
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
Case sensitive comparison is based exclusively on the numeric
Unicode values of the characters and is very fast, but is not what
@@ -6173,6 +6604,11 @@ QString& QString::fill(QChar ch, qsizetype size)
\snippet qstring/main.cpp 16
+//! [compare-isNull-vs-isEmpty]
+ \note This function treats null strings the same as empty strings,
+ for more details see \l {Distinction Between Null and Empty Strings}.
+//! [compare-isNull-vs-isEmpty]
+
\sa operator==(), operator<(), operator>(), {Comparing Strings}
*/
@@ -6215,15 +6651,13 @@ QString& QString::fill(QChar ch, qsizetype size)
sensitivity setting \a cs.
*/
-#if QT_STRINGVIEW_LEVEL < 2
/*!
\overload compare()
\since 4.2
- Lexically compares this string with the \a other string and
- returns an integer less than, equal to, or greater than zero if
- this string is less than, equal to, or greater than the other
- string.
+ Lexically compares this string with the string \a other and returns
+ a negative integer if this string is less than \a other, a positive
+ integer if it is greater than \a other, and zero if they are equal.
Same as compare(*this, \a other, \a cs).
*/
@@ -6231,7 +6665,6 @@ int QString::compare(const QString &other, Qt::CaseSensitivity cs) const noexcep
{
return QtPrivate::compareStrings(*this, other, cs);
}
-#endif
/*!
\internal
@@ -6268,7 +6701,7 @@ int QString::compare_helper(const QChar *data1, qsizetype length1, const char *d
Q_ASSERT(length1 >= 0);
Q_ASSERT(data1 || length1 == 0);
if (!data2)
- return length1;
+ return qt_lencmp(length1, 0);
if (Q_UNLIKELY(length2 < 0))
length2 = qsizetype(strlen(data2));
return QtPrivate::compareStrings(QStringView(data1, length1),
@@ -6285,6 +6718,110 @@ int QString::compare_helper(const QChar *data1, qsizetype length1, const char *d
\overload compare()
*/
+bool comparesEqual(const QByteArrayView &lhs, const QChar &rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArrayView &lhs, const QChar &rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+bool comparesEqual(const QByteArrayView &lhs, char16_t rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArrayView &lhs, char16_t rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+bool comparesEqual(const QByteArray &lhs, const QChar &rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArray &lhs, const QChar &rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+bool comparesEqual(const QByteArray &lhs, char16_t rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArray &lhs, char16_t rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+bool QT_FASTCALL QChar::equal_helper(QChar lhs, const char *rhs) noexcept
+{
+ return QtPrivate::equalStrings(QStringView(&lhs, 1), QUtf8StringView(rhs));
+}
+
+int QT_FASTCALL QChar::compare_helper(QChar lhs, const char *rhs) noexcept
+{
+ return QtPrivate::compareStrings(QStringView(&lhs, 1), QUtf8StringView(rhs));
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+bool QStringView::equal_helper(QStringView sv, const char *data, qsizetype len)
+{
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(data || len == 0);
+ return QtPrivate::equalStrings(sv, QUtf8StringView(data, len));
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+int QStringView::compare_helper(QStringView sv, const char *data, qsizetype len)
+{
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(data || len == 0);
+ return QtPrivate::compareStrings(sv, QUtf8StringView(data, len));
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+bool QLatin1StringView::equal_helper(QLatin1StringView s1, const char *s2, qsizetype len) noexcept
+{
+ // because qlatin1stringview.h can't include qutf8stringview.h
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(s2 || len == 0);
+ return QtPrivate::equalStrings(s1, QUtf8StringView(s2, len));
+}
+
+/*!
+ \internal
+ \since 6.6
+*/
+int QLatin1StringView::compare_helper(const QLatin1StringView &s1, const char *s2, qsizetype len) noexcept
+{
+ // because qlatin1stringview.h can't include qutf8stringview.h
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(s2 || len == 0);
+ return QtPrivate::compareStrings(s1, QUtf8StringView(s2, len));
+}
+
/*!
\internal
\since 4.5
@@ -6369,7 +6906,7 @@ int QLatin1StringView::compare_helper(const QChar *data1, qsizetype length1, QLa
*/
int QString::localeAwareCompare(const QString &other) const
{
- return localeAwareCompare_helper(constData(), length(), other.constData(), other.length());
+ return localeAwareCompare_helper(constData(), size(), other.constData(), other.size());
}
/*!
@@ -6485,7 +7022,7 @@ const ushort *QString::utf16() const
QString QString::leftJustified(qsizetype width, QChar fill, bool truncate) const
{
QString result;
- qsizetype len = length();
+ qsizetype len = size();
qsizetype padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
@@ -6524,7 +7061,7 @@ QString QString::leftJustified(qsizetype width, QChar fill, bool truncate) const
QString QString::rightJustified(qsizetype width, QChar fill, bool truncate) const
{
QString result;
- qsizetype len = length();
+ qsizetype len = size();
qsizetype padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
@@ -6732,9 +7269,9 @@ QString QString::asprintf(const char *cformat, ...)
return s;
}
-static void append_utf8(QString &qs, const char *cs, int len)
+static void append_utf8(QString &qs, const char *cs, qsizetype len)
{
- const int oldSize = qs.size();
+ const qsizetype oldSize = qs.size();
qs.resize(oldSize + len);
const QChar *newEnd = QUtf8::convertToUnicode(qs.data() + oldSize, QByteArrayView(cs, len));
qs.resize(newEnd - qs.constData());
@@ -6762,19 +7299,19 @@ static uint parse_flag_characters(const char * &c) noexcept
static int parse_field_width(const char *&c, qsizetype size)
{
- Q_ASSERT(qIsDigit(*c));
+ Q_ASSERT(isAsciiDigit(*c));
const char *const stop = c + size;
// can't be negative - started with a digit
// contains at least one digit
- const char *endp;
- bool ok;
- const qulonglong result = qstrntoull(c, size, &endp, 10, &ok);
- c = endp;
+ auto [result, used] = qstrntoull(c, size, 10);
+ c += used;
+ if (used <= 0)
+ return false;
// preserve Qt 5.5 behavior of consuming all digits, no matter how many
- while (c < stop && qIsDigit(*c))
+ while (c < stop && isAsciiDigit(*c))
++c;
- return ok && result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0;
+ return result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0;
}
enum LengthMod { lm_none, lm_hh, lm_h, lm_l, lm_ll, lm_L, lm_j, lm_z, lm_t };
@@ -6862,7 +7399,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
// Parse field width
int width = -1; // -1 means unspecified
- if (qIsDigit(*c)) {
+ if (isAsciiDigit(*c)) {
width = parse_field_width(c, formatEnd - c);
} else if (*c == '*') { // can't parse this in another function, not portably, at least
width = va_arg(ap, int);
@@ -6880,7 +7417,8 @@ QString QString::vasprintf(const char *cformat, va_list ap)
int precision = -1; // -1 means unspecified
if (*c == '.') {
++c;
- if (qIsDigit(*c)) {
+ precision = 0;
+ if (isAsciiDigit(*c)) {
precision = parse_field_width(c, formatEnd - c);
} else if (*c == '*') { // can't parse this in another function, not portably, at least
precision = va_arg(ap, int);
@@ -6941,7 +7479,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
default: u = 0; break;
}
- if (qIsUpper(*c))
+ if (isAsciiUpper(*c))
flags |= QLocaleData::CapitalEorX;
int base = 10;
@@ -6972,7 +7510,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
else
d = va_arg(ap, double);
- if (qIsUpper(*c))
+ if (isAsciiUpper(*c))
flags |= QLocaleData::CapitalEorX;
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
@@ -7025,27 +7563,27 @@ QString QString::vasprintf(const char *cformat, va_list ap)
switch (length_mod) {
case lm_hh: {
signed char *n = va_arg(ap, signed char*);
- *n = result.length();
+ *n = result.size();
break;
}
case lm_h: {
short int *n = va_arg(ap, short int*);
- *n = result.length();
+ *n = result.size();
break;
}
case lm_l: {
long int *n = va_arg(ap, long int*);
- *n = result.length();
+ *n = result.size();
break;
}
case lm_ll: {
qint64 *n = va_arg(ap, qint64*);
- *n = result.length();
+ *n = result.size();
break;
}
default: {
int *n = va_arg(ap, int*);
- *n = result.length();
+ *n = int(result.size());
break;
}
}
@@ -7068,6 +7606,8 @@ QString QString::vasprintf(const char *cformat, va_list ap)
}
/*!
+ \fn QString::toLongLong(bool *ok, int base) const
+
Returns the string converted to a \c{long long} using base \a
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
@@ -7094,25 +7634,36 @@ QString QString::vasprintf(const char *cformat, va_list ap)
\sa number(), toULongLong(), toInt(), QLocale::toLongLong()
*/
-qint64 QString::toLongLong(bool *ok, int base) const
-{
- return toIntegral_helper<qlonglong>(*this, ok, base);
-}
-
-qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
+template <typename Int>
+static Int toIntegral(QStringView string, bool *ok, int base)
{
#if defined(QT_CHECK_RANGE)
if (base != 0 && (base < 2 || base > 36)) {
- qWarning("QString::toULongLong: Invalid base (%d)", base);
+ qWarning("QString::toIntegral: Invalid base (%d)", base);
base = 10;
}
#endif
- return QLocaleData::c()->stringToLongLong(string, base, ok, QLocale::RejectGroupSeparator);
+ QVarLengthArray<uchar> latin1(string.size());
+ qt_to_latin1(latin1.data(), string.utf16(), string.size());
+ QSimpleParsedNumber<Int> r;
+ if constexpr (std::is_signed_v<Int>)
+ r = QLocaleData::bytearrayToLongLong(latin1, base);
+ else
+ r = QLocaleData::bytearrayToUnsLongLong(latin1, base);
+ if (ok)
+ *ok = r.ok();
+ return r.result;
}
+qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
+{
+ return toIntegral<qlonglong>(string, ok, base);
+}
/*!
+ \fn QString::toULongLong(bool *ok, int base) const
+
Returns the string converted to an \c{unsigned long long} using base \a
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
@@ -7139,21 +7690,9 @@ qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
\sa number(), toLongLong(), QLocale::toULongLong()
*/
-quint64 QString::toULongLong(bool *ok, int base) const
-{
- return toIntegral_helper<qulonglong>(*this, ok, base);
-}
-
qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
{
-#if defined(QT_CHECK_RANGE)
- if (base != 0 && (base < 2 || base > 36)) {
- qWarning("QString::toULongLong: Invalid base (%d)", base);
- base = 10;
- }
-#endif
-
- return QLocaleData::c()->stringToUnsLongLong(string, base, ok, QLocale::RejectGroupSeparator);
+ return toIntegral<qulonglong>(string, ok, base);
}
/*!
@@ -7364,7 +7903,18 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
double QString::toDouble(bool *ok) const
{
- return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator);
+ return QStringView(*this).toDouble(ok);
+}
+
+double QStringView::toDouble(bool *ok) const
+{
+ QStringView string = qt_trimmed(*this);
+ QVarLengthArray<uchar> latin1(string.size());
+ qt_to_latin1(latin1.data(), string.utf16(), string.size());
+ auto r = qt_asciiToDouble(reinterpret_cast<const char *>(latin1.data()), string.size());
+ if (ok != nullptr)
+ *ok = r.ok();
+ return r.result;
}
/*!
@@ -7402,6 +7952,11 @@ float QString::toFloat(bool *ok) const
return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
}
+float QStringView::toFloat(bool *ok) const
+{
+ return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
+}
+
/*! \fn QString &QString::setNum(int n, int base)
Sets the string to the printed value of \a n in the specified \a
@@ -7605,7 +8160,7 @@ QString QString::number(double n, char format, int precision)
break;
}
- return qdtoBasicLatin(n, form, precision, qIsUpper(format));
+ return qdtoBasicLatin(n, form, precision, isAsciiUpper(format));
}
namespace {
@@ -7679,14 +8234,15 @@ QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensit
\fn QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
- Splits the string into substring views wherever \a sep occurs, and
+ Splits the view into substring views wherever \a sep occurs, and
returns the list of those string views.
See QString::split() for how \a sep, \a behavior and \a cs interact to form
the result.
- \note All views are valid as long as this string is. Destroying this
- string will cause all views to be dangling pointers.
+ \note All the returned views are valid as long as the data referenced by
+ this string view is valid. Destroying the data will cause all views to
+ become dangling.
\since 6.0
*/
@@ -7702,8 +8258,9 @@ QList<QStringView> QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt:
#if QT_CONFIG(regularexpression)
namespace {
-template<class ResultList, typename String>
+template<class ResultList, typename String, typename MatchingFunction>
static ResultList splitString(const String &source, const QRegularExpression &re,
+ MatchingFunction matchingFunction,
Qt::SplitBehavior behavior)
{
ResultList list;
@@ -7714,7 +8271,7 @@ static ResultList splitString(const String &source, const QRegularExpression &re
qsizetype start = 0;
qsizetype end = 0;
- QRegularExpressionMatchIterator iterator = re.globalMatch(source);
+ QRegularExpressionMatchIterator iterator = (re.*matchingFunction)(source, 0, QRegularExpression::NormalMatch, QRegularExpression::NoMatchOption);
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
end = match.capturedStart();
@@ -7759,10 +8316,19 @@ static ResultList splitString(const String &source, const QRegularExpression &re
*/
QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
{
- return splitString<QStringList>(*this, re, behavior);
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ const auto matchingFunction = qOverload<const QString &, qsizetype, QRegularExpression::MatchType, QRegularExpression::MatchOptions>(&QRegularExpression::globalMatch);
+#else
+ const auto matchingFunction = &QRegularExpression::globalMatch;
+#endif
+ return splitString<QStringList>(*this,
+ re,
+ matchingFunction,
+ behavior);
}
/*!
+ \overload
\since 6.0
Splits the string into substring views wherever the regular expression \a re
@@ -7776,7 +8342,7 @@ QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behav
*/
QList<QStringView> QStringView::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
{
- return splitString<QList<QStringView>>(*this, re, behavior);
+ return splitString<QList<QStringView>>(*this, re, &QRegularExpression::globalMatchView, behavior);
}
#endif // QT_CONFIG(regularexpression)
@@ -7847,7 +8413,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::
// check if it's fully ASCII first, because then we have no work
auto start = reinterpret_cast<const char16_t *>(data->constData());
const char16_t *p = start + from;
- if (isAscii_helper(p, p + data->length() - from))
+ if (isAscii_helper(p, p + data->size() - from))
return;
if (p > start + from)
from = p - start - 1; // need one before the non-ASCII to perform NFC
@@ -7858,8 +8424,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::
} else if (int(version) <= NormalizationCorrectionsVersionMax) {
const QString &s = *data;
QChar *d = nullptr;
- for (int i = 0; i < NumNormalizationCorrections; ++i) {
- const NormalizationCorrection &n = uc_normalization_corrections[i];
+ for (const NormalizationCorrection &n : uc_normalization_corrections) {
if (n.version > version) {
qsizetype pos = from;
if (QChar::requiresSurrogates(n.ucs4)) {
@@ -7867,7 +8432,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::
char16_t ucs4Low = QChar::lowSurrogate(n.ucs4);
char16_t oldHigh = QChar::highSurrogate(n.old_mapping);
char16_t oldLow = QChar::lowSurrogate(n.old_mapping);
- while (pos < s.length() - 1) {
+ while (pos < s.size() - 1) {
if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) {
if (!d)
d = data->data();
@@ -7877,7 +8442,7 @@ void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::
++pos;
}
} else {
- while (pos < s.length()) {
+ while (pos < s.size()) {
if (s.at(pos).unicode() == n.ucs4) {
if (!d)
d = data->data();
@@ -7914,7 +8479,7 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi
return copy;
}
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
static void checkArgEscape(QStringView s)
{
// If we're in here, it means that qArgDigitValue has accepted the
@@ -7946,10 +8511,10 @@ static void checkArgEscape(QStringView s)
struct ArgEscapeData
{
int min_escape; // lowest escape sequence number
- int occurrences; // number of occurrences of the lowest escape sequence number
- int locale_occurrences; // number of occurrences of the lowest escape sequence number that
- // contain 'L'
- int escape_len; // total length of escape sequences which will be replaced
+ qsizetype occurrences; // number of occurrences of the lowest escape sequence number
+ qsizetype locale_occurrences; // number of occurrences of the lowest escape sequence number that
+ // contain 'L'
+ qsizetype escape_len; // total length of escape sequences which will be replaced
};
static ArgEscapeData findArgEscapes(QStringView s)
@@ -7988,7 +8553,7 @@ static ArgEscapeData findArgEscapes(QStringView s)
// ### Qt 7: do not allow anything but ASCII digits
// in arg()'s replacements.
-#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
const QChar *escapeBegin = c;
const QChar *escapeEnd = escapeBegin + 1;
#endif
@@ -8000,13 +8565,13 @@ static ArgEscapeData findArgEscapes(QStringView s)
if (next_escape != -1) {
escape = (10 * escape) + next_escape;
++c;
-#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
++escapeEnd;
#endif
}
}
-#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
checkArgEscape(QStringView(escapeBegin, escapeEnd));
#endif
@@ -8034,14 +8599,14 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp
// Negative field-width for right-padding, positive for left-padding:
const qsizetype abs_field_width = qAbs(field_width);
const qsizetype result_len =
- s.length() - d.escape_len
- + (d.occurrences - d.locale_occurrences) * qMax(abs_field_width, arg.length())
- + d.locale_occurrences * qMax(abs_field_width, larg.length());
+ s.size() - d.escape_len
+ + (d.occurrences - d.locale_occurrences) * qMax(abs_field_width, arg.size())
+ + d.locale_occurrences * qMax(abs_field_width, larg.size());
QString result(result_len, Qt::Uninitialized);
QChar *rc = const_cast<QChar *>(result.unicode());
QChar *const result_end = rc + result_len;
- int repl_cnt = 0;
+ qsizetype repl_cnt = 0;
const QChar *c = s.begin();
const QChar *const uc_end = s.end();
@@ -8079,20 +8644,19 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp
rc += escape_start - text_start;
const QStringView use = localize ? larg : arg;
- const qsizetype pad_chars = abs_field_width - use.length();
+ const qsizetype pad_chars = abs_field_width - use.size();
// (If negative, relevant loops are no-ops: no need to check.)
if (field_width > 0) { // left padded
- for (qsizetype i = 0; i < pad_chars; ++i)
- *rc++ = fillChar;
+ rc = std::fill_n(rc, pad_chars, fillChar);
}
- memcpy(rc, use.data(), use.length() * sizeof(QChar));
- rc += use.length();
+ if (use.size())
+ memcpy(rc, use.data(), use.size() * sizeof(QChar));
+ rc += use.size();
if (field_width < 0) { // right padded
- for (qsizetype i = 0; i < pad_chars; ++i)
- *rc++ = fillChar;
+ rc = std::fill_n(rc, pad_chars, fillChar);
}
if (++repl_cnt == d.occurrences) {
@@ -8108,7 +8672,6 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp
return result;
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
Returns a copy of this string with the lowest numbered place marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
@@ -8142,7 +8705,6 @@ QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
{
return arg(qToStringViewIgnoringNull(a), fieldWidth, fillChar);
}
-#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\overload
@@ -8193,7 +8755,7 @@ QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
\since 5.10
Returns a copy of this string with the lowest-numbered place-marker
- replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
+ replaced by the Latin-1 string viewed by \a a, i.e., \c %1, \c %2, ..., \c %99.
\a fieldWidth specifies the minimum amount of space that \a a
shall occupy. If \a a requires less space than \a fieldWidth, it
@@ -8214,8 +8776,7 @@ QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
*/
QString QString::arg(QLatin1StringView a, int fieldWidth, QChar fillChar) const
{
- QVarLengthArray<char16_t> utf16(a.size());
- qt_from_latin1(utf16.data(), a.data(), a.size());
+ QVarLengthArray<char16_t> utf16 = qt_from_latin1_to_qvla(a);
return arg(QStringView(utf16.data(), utf16.size()), fieldWidth, fillChar);
}
@@ -8323,8 +8884,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
QString arg;
if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->longLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= arg.length());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= arg.size());
}
QString localeArg;
@@ -8333,8 +8893,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
flags |= QLocaleData::GroupDigits;
localeArg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= localeArg.length());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= localeArg.size());
}
return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
@@ -8371,8 +8930,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
QString arg;
if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->unsLongLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= arg.length());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= arg.size());
}
QString localeArg;
@@ -8381,8 +8939,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
flags |= QLocaleData::GroupDigits;
localeArg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= localeArg.length());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= localeArg.size());
}
return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
@@ -8468,7 +9025,7 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar
if (fillChar == u'0')
flags |= QLocaleData::ZeroPadded;
- if (qIsUpper(format))
+ if (isAsciiUpper(format))
flags |= QLocaleData::CapitalEorX;
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
@@ -8493,8 +9050,8 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar
if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->doubleToString(a, precision, form, fieldWidth,
flags | QLocaleData::ZeroPadExponent);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= arg.length());
+ Q_ASSERT(fillChar != u'0' || !qt_is_finite(a)
+ || fieldWidth <= arg.size());
}
QString localeArg;
@@ -8509,8 +9066,8 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar
if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
flags |= QLocaleData::AddTrailingZeroes;
localeArg = locale.d->m_data->doubleToString(a, precision, form, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= localeArg.length());
+ Q_ASSERT(fillChar != u'0' || !qt_is_finite(a)
+ || fieldWidth <= localeArg.size());
}
return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
@@ -8522,7 +9079,7 @@ static inline char16_t 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;
+ qsizetype i = *pos;
++i;
if (i < len && uc[i] == u'L')
++i;
@@ -8644,7 +9201,7 @@ static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult &
{
ArgIndexToPlaceholderMap result;
- for (Part part : parts) {
+ for (const Part &part : parts) {
if (part.number >= 0)
result.push_back(part.number);
}
@@ -8710,7 +9267,7 @@ static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPriv
QString result(totalSize, Qt::Uninitialized);
auto out = const_cast<QChar*>(result.constData());
- for (Part part : parts) {
+ for (const Part &part : parts) {
switch (part.tag) {
case QtPrivate::ArgBase::L1:
if (part.size) {
@@ -8742,26 +9299,6 @@ QString QtPrivate::argToQString(QLatin1StringView pattern, size_t n, const ArgBa
return argToQStringImpl(pattern, n, args);
}
-/*! \fn bool QString::isSimpleText() const
-
- \internal
-*/
-bool QString::isSimpleText() const
-{
- const char16_t *p = d.data();
- const char16_t * const end = p + d.size;
- while (p < end) {
- char16_t uc = *p;
- // sort out regions of complex text formatting
- if (uc > 0x058f && (uc < 0x1100 || uc > 0xfb0f)) {
- return false;
- }
- p++;
- }
-
- return true;
-}
-
/*! \fn bool QString::isRightToLeft() const
Returns \c true if the string is read right to left.
@@ -8869,7 +9406,8 @@ bool QString::isRightToLeft() const
Removes from the string the characters in the half-open range
[ \a first , \a last ). Returns an iterator to the character
- referred to by \a last before the erase.
+ immediately after the last erased character (i.e. the character
+ referred to by \a last before the erase).
*/
QString::iterator QString::erase(QString::const_iterator first, QString::const_iterator last)
{
@@ -8879,6 +9417,22 @@ QString::iterator QString::erase(QString::const_iterator first, QString::const_i
return begin() + start;
}
+/*!
+ \fn QString::iterator QString::erase(QString::const_iterator it)
+
+ \overload
+ \since 6.5
+
+ Removes the character denoted by \c it from the string.
+ Returns an iterator to the character immediately after the
+ erased character.
+
+ \code
+ QString c = "abcdefg";
+ auto it = c.erase(c.cbegin()); // c is now "bcdefg"; "it" points to "b"
+ \endcode
+*/
+
/*! \fn void QString::shrink_to_fit()
\since 5.10
@@ -8957,8 +9511,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
/*! \fn QString QString::fromStdU16String(const std::u16string &str)
\since 5.5
- Returns a copy of the \a str string. The given string is assumed
- to be encoded in UTF-16.
+ \include qstring.cpp {from-std-string} {UTF-16} {fromUtf16()}
\sa fromUtf16(), fromStdWString(), fromStdU32String()
*/
@@ -8977,8 +9530,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
/*! \fn QString QString::fromStdU32String(const std::u32string &str)
\since 5.5
- Returns a copy of the \a str string. The given string is assumed
- to be encoded in UCS-4.
+ \include qstring.cpp {from-std-string} {UCS-4} {fromUcs4()}
\sa fromUcs4(), fromStdWString(), fromStdU16String()
*/
@@ -8994,1252 +9546,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
\sa toUcs4(), toStdWString(), toStdU16String()
*/
-/*! \class QLatin1StringView
- \inmodule QtCore
- \brief The QLatin1StringView class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
-
- \ingroup string-processing
- \reentrant
-
- Many of QString's member functions are overloaded to accept
- \c{const char *} instead of QString. This includes the copy
- constructor, the assignment operator, the comparison operators,
- and various other functions such as \l{QString::insert()}{insert()},
- \l{QString::replace()}{replace()}, and \l{QString::indexOf()}{indexOf()}.
- These functions are usually optimized to avoid constructing a
- QString object for the \c{const char *} data. For example,
- assuming \c str is a QString,
-
- \snippet code/src_corelib_text_qstring.cpp 3
-
- is much faster than
-
- \snippet code/src_corelib_text_qstring.cpp 4
-
- because it doesn't construct four temporary QString objects and
- make a deep copy of the character data.
-
- Applications that define \l QT_NO_CAST_FROM_ASCII (as explained
- in the QString documentation) don't have access to QString's
- \c{const char *} API. To provide an efficient way of specifying
- constant Latin-1 strings, Qt provides the QLatin1StringView, which is
- just a very thin wrapper around a \c{const char *}. Using
- QLatin1StringView, the example code above becomes
-
- \snippet code/src_corelib_text_qstring.cpp 5
-
- This is a bit longer to type, but it provides exactly the same
- benefits as the first version of the code, and is faster than
- converting the Latin-1 strings using QString::fromLatin1().
-
- Thanks to the QString(QLatin1StringView) constructor,
- QLatin1StringView can be used everywhere a QString is expected. For
- example:
-
- \snippet code/src_corelib_text_qstring.cpp 6
-
- \note If the function you're calling with a QLatin1StringView
- argument isn't actually overloaded to take QLatin1StringView, the
- implicit conversion to QString will trigger a memory allocation,
- which is usually what you want to avoid by using QLatin1StringView
- in the first place. In those cases, using QStringLiteral may be
- the better option.
-
- \sa QString, QLatin1Char, {QStringLiteral()}{QStringLiteral},
- QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \class QLatin1String
- \inmodule QtCore
- \brief QLatin1String is the same as QLatin1StringView.
-
- QLatin1String is a view to a Latin-1 string. It's the same as
- QLatin1StringView and is kept for compatibility reasons. It is
- recommended to use QLatin1StringView instead.
-
- Please see the QLatin1StringView documentation for details.
-*/
-
-/*!
- \typedef QLatin1StringView::value_type
- \since 5.10
-
- Alias for \c{const char}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1StringView::difference_type
- \since 5.10
-
- Alias for \c{qsizetype}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1StringView::size_type
- \since 5.10
-
- Alias for \c{qsizetype}. Provided for compatibility with the STL.
-
- \note In version prior to Qt 6, this was an alias for \c{int},
- restricting the amount of data that could be held in a QLatin1StringView
- on 64-bit architectures.
-*/
-
-/*!
- \typedef QLatin1StringView::reference
- \since 5.10
-
- Alias for \c{value_type &}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1StringView::const_reference
- \since 5.11
-
- Alias for \c{reference}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1StringView::iterator
- \since 5.10
-
- QLatin1StringView does not support mutable iterators, so this is the same
- as const_iterator.
-
- \sa const_iterator, reverse_iterator
-*/
-
-/*!
- \typedef QLatin1StringView::const_iterator
- \since 5.10
-
- \sa iterator, const_reverse_iterator
-*/
-
-/*!
- \typedef QLatin1StringView::reverse_iterator
- \since 5.10
-
- QLatin1StringView does not support mutable reverse iterators, so this is the
- same as const_reverse_iterator.
-
- \sa const_reverse_iterator, iterator
-*/
-
-/*!
- \typedef QLatin1StringView::const_reverse_iterator
- \since 5.10
-
- \sa reverse_iterator, const_iterator
-*/
-
-/*! \fn QLatin1StringView::QLatin1StringView()
- \since 5.6
-
- Constructs a QLatin1StringView object that stores a \nullptr.
-
- \sa data(), isEmpty(), isNull(), {Distinction Between Null and Empty Strings}
-*/
-
-/*! \fn QLatin1StringView::QLatin1StringView(std::nullptr_t)
- \since 6.4
-
- Constructs a QLatin1StringView object that stores a \nullptr.
-
- \sa data(), isEmpty(), isNull(), {Distinction Between Null and Empty Strings}
-*/
-
-/*! \fn QLatin1StringView::QLatin1StringView(const char *str)
-
- Constructs a QLatin1StringView object that stores \a str.
-
- The string data is \e not copied. The caller must be able to
- guarantee that \a str will not be deleted or modified as long as
- the QLatin1StringView object exists.
-
- \sa latin1()
-*/
-
-/*! \fn QLatin1StringView::QLatin1StringView(const char *str, qsizetype size)
-
- Constructs a QLatin1StringView object that stores \a str with \a size.
-
- The string data is \e not copied. The caller must be able to
- guarantee that \a str will not be deleted or modified as long as
- the QLatin1StringView object exists.
-
- \note: any null ('\\0') bytes in the byte array will be included in this
- string, which will be converted to Unicode null characters (U+0000) if this
- string is used by QString. This behavior is different from Qt 5.x.
-
- \sa latin1()
-*/
-
-/*!
- \fn QLatin1StringView::QLatin1StringView(const char *first, const char *last)
- \since 5.10
-
- Constructs a QLatin1StringView object that stores \a first with length
- (\a last - \a first).
-
- The range \c{[first,last)} must remain valid for the lifetime of
- this Latin-1 string object.
-
- 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 \nullptr and \a last is not, or if \c{last - first >
- INT_MAX}.
-*/
-
-/*! \fn QLatin1StringView::QLatin1StringView(const QByteArray &str)
-
- Constructs a QLatin1StringView object that stores \a str.
-
- The string data is \e not copied. The caller must be able to
- guarantee that \a str will not be deleted or modified as long as
- the QLatin1StringView object exists.
-
- \sa latin1()
-*/
-
-/*! \fn QLatin1StringView::QLatin1StringView(QByteArrayView str)
- \since 6.3
-
- Constructs a QLatin1StringView object that stores \a str.
-
- The string data is \e not copied. The caller must be able to
- guarantee that the data which \a str is pointing to will not
- be deleted or modified as long as the QLatin1StringView object
- exists. The size is obtained from \a str as-is, without checking
- for a null-terminator.
-
- \note: any null ('\\0') bytes in the byte array will be included in this
- string, which will be converted to Unicode null characters (U+0000) if this
- string is used by QString.
-
- \sa latin1()
-*/
-
-/*!
- \fn QString QLatin1StringView::toString() const
- \since 6.0
-
- Converts this Latin-1 string into a QString. Equivalent to
- \code
- return QString(*this);
- \endcode
-*/
-
-/*! \fn const char *QLatin1StringView::latin1() const
-
- Returns the start of the Latin-1 string referenced by this object.
-*/
-
-/*! \fn const char *QLatin1StringView::data() const
-
- Returns the start of the Latin-1 string referenced by this object.
-*/
-
-/*! \fn const char *QLatin1StringView::constData() const
- \since 6.4
-
- Returns the start of the Latin-1 string referenced by this object.
-
- This function is provided for compatibility with other Qt containers.
-
- \sa data()
-*/
-
-/*! \fn qsizetype QLatin1StringView::size() const
-
- Returns the size of the Latin-1 string referenced by this object.
-
- \note In version prior to Qt 6, this function returned \c{int},
- restricting the amount of data that could be held in a QLatin1StringView
- on 64-bit architectures.
-*/
-
-/*! \fn qsizetype QLatin1StringView::length() const
- \since 6.4
-
- Same as size().
-
- This function is provided for compatibility with other Qt containers.
-*/
-
-/*! \fn bool QLatin1StringView::isNull() const
- \since 5.10
-
- Returns whether the Latin-1 string referenced by this object is null
- (\c{data() == nullptr}) or not.
-
- \sa isEmpty(), data()
-*/
-
-/*! \fn bool QLatin1StringView::isEmpty() const
- \since 5.10
-
- Returns whether the Latin-1 string referenced by this object is empty
- (\c{size() == 0}) or not.
-
- \sa isNull(), size()
-*/
-
-/*! \fn bool QLatin1StringView::empty() const
- \since 6.4
-
- Returns whether the Latin-1 string referenced by this object is empty
- (\c{size() == 0}) or not.
-
- This function is provided for STL compatibility.
-
- \sa isEmpty(), isNull(), size()
-*/
-
-/*! \fn QLatin1Char QLatin1StringView::at(qsizetype pos) const
- \since 5.8
-
- Returns the character at position \a pos in this object.
-
- \note This function performs no error checking.
- The behavior is undefined when \a pos < 0 or \a pos >= size().
-
- \sa operator[]()
-*/
-
-/*! \fn QLatin1Char QLatin1StringView::operator[](qsizetype pos) const
- \since 5.8
-
- Returns the character at position \a pos in this object.
-
- \note This function performs no error checking.
- The behavior is undefined when \a pos < 0 or \a pos >= size().
-
- \sa at()
-*/
-
-/*!
- \fn QLatin1Char QLatin1StringView::front() const
- \since 5.10
-
- Returns the first character in the string.
- Same as \c{at(0)}.
-
- This function is provided for STL compatibility.
-
- \warning Calling this function on an empty string constitutes
- undefined behavior.
-
- \sa back(), at(), operator[]()
-*/
-
-/*!
- \fn QLatin1Char QLatin1StringView::first() const
- \since 6.4
-
- Returns the first character in the string.
- Same as \c{at(0)} or front().
-
- This function is provided for compatibility with other Qt containers.
-
- \warning Calling this function on an empty string constitutes
- undefined behavior.
-
- \sa last(), front(), back()
-*/
-
-/*!
- \fn QLatin1Char QLatin1StringView::back() const
- \since 5.10
-
- Returns the last character in the string.
- Same as \c{at(size() - 1)}.
-
- This function is provided for STL compatibility.
-
- \warning Calling this function on an empty string constitutes
- undefined behavior.
-
- \sa front(), at(), operator[]()
-*/
-
-/*!
- \fn QLatin1Char QLatin1StringView::last() const
- \since 6.4
-
- Returns the last character in the string.
- Same as \c{at(size() - 1)} or back().
-
- This function is provided for compatibility with other Qt containers.
-
- \warning Calling this function on an empty string constitutes
- undefined behavior.
-
- \sa first(), back(), front()
-*/
-
-/*!
- \fn int QLatin1StringView::compare(QStringView str, Qt::CaseSensitivity cs) const
- \fn int QLatin1StringView::compare(QLatin1StringView l1, Qt::CaseSensitivity cs) const
- \fn int QLatin1StringView::compare(QChar ch) const
- \fn int QLatin1StringView::compare(QChar ch, Qt::CaseSensitivity cs) const
- \since 5.14
-
- Returns an integer that compares to zero as this Latin-1 string compares to the
- string-view \a str, Latin-1 string \a l1, or character \a ch, respectively.
-
- If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive;
- otherwise the comparison is case-insensitive.
-
- \sa operator==(), operator<(), operator>()
-*/
-
-
-/*!
- \fn bool QLatin1StringView::startsWith(QStringView str, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1StringView::startsWith(QLatin1StringView l1, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1StringView::startsWith(QChar ch) const
- \since 5.10
- \fn bool QLatin1StringView::startsWith(QChar ch, Qt::CaseSensitivity cs) const
- \since 5.10
-
- Returns \c true if this Latin-1 string starts with string-view \a str,
- Latin-1 string \a l1, or character \a ch, respectively;
- otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
- otherwise the search is case-insensitive.
-
- \sa endsWith()
-*/
-
-/*!
- \fn bool QLatin1StringView::endsWith(QStringView str, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1StringView::endsWith(QLatin1StringView l1, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1StringView::endsWith(QChar ch) const
- \since 5.10
- \fn bool QLatin1StringView::endsWith(QChar ch, Qt::CaseSensitivity cs) const
- \since 5.10
-
- Returns \c true if this Latin-1 string ends with string-view \a str,
- Latin-1 string \a l1, or character \a ch, respectively;
- otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
- otherwise the search is case-insensitive.
-
- \sa startsWith()
-*/
-
-/*!
- \fn qsizetype QLatin1StringView::indexOf(QStringView str, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \fn qsizetype QLatin1StringView::indexOf(QLatin1StringView l1, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \fn qsizetype QLatin1StringView::indexOf(QChar c, qsizetype 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 QLatin1StringView::contains(QStringView str, Qt::CaseSensitivity cs) const
- \fn bool QLatin1StringView::contains(QLatin1StringView l1, Qt::CaseSensitivity cs) const
- \fn bool QLatin1StringView::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 qsizetype QLatin1StringView::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
- \fn qsizetype QLatin1StringView::lastIndexOf(QLatin1StringView l1, qsizetype from, Qt::CaseSensitivity cs) const
- \fn qsizetype QLatin1StringView::lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs) const
- \since 5.14
-
- Returns the index position of the last occurrence of the string-view \a str,
- Latin-1 string \a l1, or character \a ch, respectively, in this Latin-1
- string, searching backward from index position \a from.
- Returns -1 if \a str is not found.
-
- If \a from is -1, the search starts at the last character;
- if \a from is -2, at the next to last character and so on.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \note When searching for a 0-length \a str or \a l1, the match at
- the end of the data is excluded from the search by a negative \a
- from, even though \c{-1} is normally thought of as searching from
- the end of the string: the match at the end is \e after the last
- character, so it is excluded. To include such a final empty match,
- either give a positive value for \a from or omit the \a from
- parameter entirely.
-
- \sa indexOf(), QStringView::lastIndexOf(), QStringView::indexOf(),
- QString::indexOf()
-*/
-
-/*!
- \fn qsizetype QLatin1StringView::lastIndexOf(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \fn qsizetype QLatin1StringView::lastIndexOf(QLatin1StringView l1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 6.2
- \overload lastIndexOf()
-
- Returns the index position of the last occurrence of the
- string-view \a str or Latin-1 string \a l1, respectively, in this
- Latin-1 string. 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.
-*/
-
-/*!
- \fn qsizetype QLatin1StringView::lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const
- \since 6.3
- \overload
-*/
-
-/*!
- \fn qsizetype QLatin1StringView::count(QStringView str, Qt::CaseSensitivity cs) const
- \fn qsizetype QLatin1StringView::count(QLatin1StringView l1, Qt::CaseSensitivity cs) const
- \fn qsizetype QLatin1StringView::count(QChar ch, Qt::CaseSensitivity cs) const
- \since 6.4
-
- Returns the number of (potentially overlapping) occurrences of the
- string-view \a str, Latin-1 string \a l1, or character \a ch,
- respectively, in this Latin-1 string.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa contains(), indexOf()
-*/
-
-/*!
- \fn QLatin1StringView::const_iterator QLatin1StringView::begin() const
- \since 5.10
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
- first character in the string.
-
- This function is provided for STL compatibility.
-
- \sa end(), cbegin(), rbegin(), data()
-*/
-
-/*!
- \fn QLatin1StringView::const_iterator QLatin1StringView::cbegin() const
- \since 5.10
-
- Same as begin().
-
- This function is provided for STL compatibility.
-
- \sa cend(), begin(), crbegin(), data()
-*/
-
-/*!
- \fn QLatin1StringView::const_iterator QLatin1StringView::constBegin() const
- \since 6.4
-
- Same as begin().
-
- This function is provided for compatibility with other Qt containers.
-
- \sa constEnd(), begin(), cbegin(), data()
-*/
-
-/*!
- \fn QLatin1StringView::const_iterator QLatin1StringView::end() const
- \since 5.10
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
- after the last character in the string.
-
- This function is provided for STL compatibility.
-
- \sa begin(), cend(), rend()
-*/
-
-/*! \fn QLatin1StringView::const_iterator QLatin1StringView::cend() const
- \since 5.10
-
- Same as end().
-
- This function is provided for STL compatibility.
-
- \sa cbegin(), end(), crend()
-*/
-
-/*! \fn QLatin1StringView::const_iterator QLatin1StringView::constEnd() const
- \since 6.4
-
- Same as end().
-
- This function is provided for compatibility with other Qt containers.
-
- \sa constBegin(), end(), cend(), crend()
-*/
-
-/*!
- \fn QLatin1StringView::const_reverse_iterator QLatin1StringView::rbegin() const
- \since 5.10
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing
- to the first character in the string, in reverse order.
-
- This function is provided for STL compatibility.
-
- \sa rend(), crbegin(), begin()
-*/
-
-/*!
- \fn QLatin1StringView::const_reverse_iterator QLatin1StringView::crbegin() const
- \since 5.10
-
- Same as rbegin().
-
- This function is provided for STL compatibility.
-
- \sa crend(), rbegin(), cbegin()
-*/
-
-/*!
- \fn QLatin1StringView::const_reverse_iterator QLatin1StringView::rend() const
- \since 5.10
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing just
- after the last character in the string, in reverse order.
-
- This function is provided for STL compatibility.
-
- \sa rbegin(), crend(), end()
-*/
-
-/*!
- \fn QLatin1StringView::const_reverse_iterator QLatin1StringView::crend() const
- \since 5.10
-
- Same as rend().
-
- This function is provided for STL compatibility.
-
- \sa crbegin(), rend(), cend()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::mid(qsizetype start, qsizetype length) const
- \since 5.8
-
- Returns the substring of length \a length starting at position
- \a start in this Latin-1 string.
-
- If you know that \a start and \a length cannot be out of bounds, use
- sliced() instead in new code, because it is faster.
-
- Returns an empty Latin-1 string if \a start exceeds the
- length of this Latin-1 string. If there are less than \a length characters
- available in this Latin-1 string starting at \a start, or if
- \a length is negative (default), the function returns all characters that
- are available from \a start.
-
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::left(qsizetype length) const
- \since 5.8
-
- If you know that \a length cannot be out of bounds, use first() instead in
- new code, because it is faster.
-
- Returns the substring of length \a length starting at position
- 0 in this Latin-1 string.
-
- The entire Latin-1 string is returned if \a length is greater than or equal
- to size(), or less than zero.
-
- \sa first(), last(), sliced(), startsWith(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::right(qsizetype length) const
- \since 5.8
-
- If you know that \a length cannot be out of bounds, use last() instead in
- new code, because it is faster.
-
- Returns the substring of length \a length starting at position
- size() - \a length in this Latin-1 string.
-
- The entire Latin-1 string is returned if \a length is greater than or equal
- to size(), or less than zero.
-
- \sa first(), last(), sliced(), endsWith(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::first(qsizetype n) const
- \since 6.0
-
- Returns a Latin-1 string that contains the first \a n characters
- of this Latin-1 string.
-
- \note The behavior is undefined when \a n < 0 or \a n > size().
-
- \sa last(), startsWith(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::last(qsizetype n) const
- \since 6.0
-
- Returns a Latin-1 string that contains the last \a n characters
- of this Latin-1 string.
-
- \note The behavior is undefined when \a n < 0 or \a n > size().
-
- \sa first(), endsWith(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::sliced(qsizetype pos, qsizetype n) const
- \since 6.0
-
- Returns a Latin-1 string that points to \a n characters of this
- Latin-1 string, starting at position \a pos.
-
- \note The behavior is undefined when \a pos < 0, \a n < 0,
- or \c{pos + n > size()}.
-
- \sa first(), last(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::sliced(qsizetype pos) const
- \since 6.0
-
- Returns a Latin-1 string starting at position \a pos in this
- Latin-1 string, and extending to its end.
-
- \note The behavior is undefined when \a pos < 0 or \a pos > size().
-
- \sa first(), last(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::chopped(qsizetype length) const
- \since 5.10
-
- Returns the substring of length size() - \a length starting at the
- beginning of this object.
-
- Same as \c{left(size() - length)}.
-
- \note The behavior is undefined when \a length < 0 or \a length > size().
-
- \sa sliced(), first(), last(), chop(), truncate()
-*/
-
-/*!
- \fn void QLatin1StringView::truncate(qsizetype length)
- \since 5.10
-
- Truncates this string to length \a length.
-
- Same as \c{*this = left(length)}.
-
- \note The behavior is undefined when \a length < 0 or \a length > size().
-
- \sa sliced(), first(), last(), chopped(), chop()
-*/
-
-/*!
- \fn void QLatin1StringView::chop(qsizetype length)
- \since 5.10
-
- Truncates this string by \a length characters.
-
- Same as \c{*this = left(size() - length)}.
-
- \note The behavior is undefined when \a length < 0 or \a length > size().
-
- \sa sliced(), first(), last(), chopped(), truncate()
-*/
-
-/*!
- \fn QLatin1StringView QLatin1StringView::trimmed() const
- \since 5.10
-
- Strips leading and trailing whitespace and returns the result.
-
- Whitespace means any character for which QChar::isSpace() returns
- \c true. This includes the ASCII characters '\\t', '\\n', '\\v',
- '\\f', '\\r', and ' '.
-*/
-
-/*!
- \fn bool QLatin1StringView::operator==(const char *other) const
- \since 4.3
-
- Returns \c true if the string is equal to const char pointer \a other;
- otherwise returns \c false.
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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 {Comparing Strings}
-*/
-
-/*!
- \fn bool QLatin1StringView::operator==(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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.
-*/
-
-/*!
- \fn bool QLatin1StringView::operator!=(const char *other) const
- \since 4.3
-
- Returns \c true if this string is not equal to const char pointer \a other;
- otherwise returns \c false.
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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 {Comparing Strings}
-*/
-
-/*!
- \fn bool QLatin1StringView::operator!=(const QByteArray &other) const
- \since 5.0
- \overload operator!=()
-
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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.
-*/
-
-/*!
- \fn bool QLatin1StringView::operator>(const char *other) const
- \since 4.3
-
- Returns \c true if this string is lexically greater than const char pointer
- \a other; otherwise returns \c false.
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \l 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 {Comparing Strings}
-*/
-
-/*!
- \fn bool QLatin1StringView::operator>(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \l 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.
-*/
-
-/*!
- \fn bool QLatin1StringView::operator<(const char *other) const
- \since 4.3
-
- Returns \c true if this string is lexically less than const char pointer
- \a other; otherwise returns \c false.
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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 {Comparing Strings}
-*/
-
-/*!
- \fn bool QLatin1StringView::operator<(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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.
-*/
-
-/*!
- \fn bool QLatin1StringView::operator>=(const char *other) const
- \since 4.3
-
- Returns \c true if this string is lexically greater than or equal to
- const char pointer \a other; otherwise returns \c false.
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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 {Comparing Strings}
-*/
-
-/*!
- \fn bool QLatin1StringView::operator>=(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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.
-*/
-
-/*!
- \fn bool QLatin1StringView::operator<=(const char *other) const
- \since 4.3
-
- Returns \c true if this string is lexically less than or equal to
- const char pointer \a other; otherwise returns \c false.
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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 {Comparing Strings}
-*/
-
-/*!
- \fn bool QLatin1StringView::operator<=(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining
- \l 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.
-*/
-
-/*! \fn bool QLatin1StringView::operator==(QLatin1StringView s1, QLatin1StringView s2)
-
- Returns \c true if string \a s1 is lexically equal to string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator!=(QLatin1StringView s1, QLatin1StringView s2)
-
- Returns \c true if string \a s1 is lexically not equal to string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<(QLatin1StringView s1, QLatin1StringView s2)
-
- Returns \c true if string \a s1 is lexically less than string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<=(QLatin1StringView s1, QLatin1StringView s2)
-
- Returns \c true if string \a s1 is lexically less than or equal to
- string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>(QLatin1StringView s1, QLatin1StringView s2)
-
- Returns \c true if string \a s1 is lexically greater than string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>=(QLatin1StringView s1, QLatin1StringView s2)
-
- Returns \c true if string \a s1 is lexically greater than or equal
- to string \a s2; otherwise returns \c false.
-*/
-
-/*! \fn bool QLatin1StringView::operator==(QChar ch, QLatin1StringView s)
-
- Returns \c true if char \a ch is lexically equal to string \a s;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<(QChar ch, QLatin1StringView s)
-
- Returns \c true if char \a ch is lexically less than string \a s;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>(QChar ch, QLatin1StringView s)
- Returns \c true if char \a ch is lexically greater than string \a s;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator!=(QChar ch, QLatin1StringView s)
-
- Returns \c true if char \a ch is lexically not equal to string \a s;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<=(QChar ch, QLatin1StringView s)
-
- Returns \c true if char \a ch is lexically less than or equal to
- string \a s; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>=(QChar ch, QLatin1StringView s)
-
- Returns \c true if char \a ch is lexically greater than or equal to
- string \a s; otherwise returns \c false.
-*/
-
-/*! \fn bool QLatin1StringView::operator==(QLatin1StringView s, QChar ch)
-
- Returns \c true if string \a s is lexically equal to char \a ch;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<(QLatin1StringView s, QChar ch)
-
- Returns \c true if string \a s is lexically less than char \a ch;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>(QLatin1StringView s, QChar ch)
-
- Returns \c true if string \a s is lexically greater than char \a ch;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator!=(QLatin1StringView s, QChar ch)
-
- Returns \c true if string \a s is lexically not equal to char \a ch;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<=(QLatin1StringView s, QChar ch)
-
- Returns \c true if string \a s is lexically less than or equal to
- char \a ch; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>=(QLatin1StringView s, QChar ch)
-
- Returns \c true if string \a s is lexically greater than or equal to
- char \a ch; otherwise returns \c false.
-*/
-
-/*! \fn bool QLatin1StringView::operator==(QStringView s1, QLatin1StringView s2)
-
- Returns \c true if string view \a s1 is lexically equal to string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<(QStringView s1, QLatin1StringView s2)
-
- Returns \c true if string view \a s1 is lexically less than string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>(QStringView s1, QLatin1StringView s2)
-
- Returns \c true if string view \a s1 is lexically greater than string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator!=(QStringView s1, QLatin1StringView s2)
-
- Returns \c true if string view \a s1 is lexically not equal to string \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<=(QStringView s1, QLatin1StringView s2)
-
- Returns \c true if string view \a s1 is lexically less than or equal to
- string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>=(QStringView s1, QLatin1StringView s2)
-
- Returns \c true if string view \a s1 is lexically greater than or equal to
- string \a s2; otherwise returns \c false.
-*/
-
-/*! \fn bool QLatin1StringView::operator==(QLatin1StringView s1, QStringView s2)
-
- Returns \c true if string \a s1 is lexically equal to string view \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<(QLatin1StringView s1, QStringView s2)
-
- Returns \c true if string \a s1 is lexically less than string view \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>(QLatin1StringView s1, QStringView s2)
-
- Returns \c true if string \a s1 is lexically greater than string view \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator!=(QLatin1StringView s1, QStringView s2)
-
- Returns \c true if string \a s1 is lexically not equal to string view \a s2;
- otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<=(QLatin1StringView s1, QStringView s2)
-
- Returns \c true if string \a s1 is lexically less than or equal to
- string view \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>=(QLatin1StringView s1, QStringView s2)
-
- Returns \c true if string \a s1 is lexically greater than or equal to
- string view \a s2; otherwise returns \c false.
-*/
-
-/*! \fn bool QLatin1StringView::operator==(const char *s1, QLatin1StringView s2)
-
- Returns \c true if const char pointer \a s1 is lexically equal to
- string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<(const char *s1, QLatin1StringView s2)
-
- Returns \c true if const char pointer \a s1 is lexically less than
- string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>(const char *s1, QLatin1StringView s2)
-
- Returns \c true if const char pointer \a s1 is lexically greater than
- string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator!=(const char *s1, QLatin1StringView s2)
-
- Returns \c true if const char pointer \a s1 is lexically not equal to
- string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator<=(const char *s1, QLatin1StringView s2)
-
- Returns \c true if const char pointer \a s1 is lexically less than or
- equal to string \a s2; otherwise returns \c false.
-*/
-/*! \fn bool QLatin1StringView::operator>=(const char *s1, QLatin1StringView s2)
-
- Returns \c true if const char pointer \a s1 is lexically greater than or
- equal to string \a s2; otherwise returns \c false.
-*/
-
-/*!
- \fn qlonglong QLatin1StringView::toLongLong(bool *ok, int base) const
- \fn qulonglong QLatin1StringView::toULongLong(bool *ok, int base) const
- \fn int QLatin1StringView::toInt(bool *ok, int base) const
- \fn uint QLatin1StringView::toUInt(bool *ok, int base) const
- \fn long QLatin1StringView::toLong(bool *ok, int base) const
- \fn ulong QLatin1StringView::toULong(bool *ok, int base) const
- \fn short QLatin1StringView::toShort(bool *ok, int base) const
- \fn ushort QLatin1StringView::toUShort(bool *ok, int base) const
-
- \since 6.4
-
- Returns this QLatin1StringView converted to a corresponding numeric value using
- base \a base, which is ten by default. Bases 0 and 2 through 36 are supported,
- using letters for digits beyond 9; A is ten, B is eleven and so on.
-
- If \a base is 0, the base is determined automatically using the following
- rules: if the Latin-1 string begins with "0x", the rest of it is read as
- hexadecimal (base 16); otherwise, if it begins with "0b", the rest of it is
- read as binary (base 2); otherwise, if it begins with "0", the rest of it is
- read as octal (base 8); otherwise it is read as decimal.
-
- Returns 0 if the conversion fails.
-
- 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.
-
-//! [latin1-numeric-conversion-note]
- \note The conversion of the number is performed in the default C locale,
- regardless of the user's locale. Use QLocale to perform locale-aware
- conversions between numbers and strings.
-
- This function ignores leading and trailing spacing characters.
-//! [latin1-numeric-conversion-note]
-
- \note Support for the "0b" prefix was added in Qt 6.4.
-*/
-
-/*!
- \fn double QLatin1StringView::toDouble(bool *ok) const
- \fn float QLatin1StringView::toFloat(bool *ok) const
- \since 6.4
-
- Returns this QLatin1StringView converted to a corresponding floating-point value.
-
- 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 \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
-
- \warning The QLatin1StringView content may only contain valid numerical
- characters which includes the plus/minus sign, the character e used in
- scientific notation, and the decimal point. Including the unit or additional
- characters leads to a conversion error.
-
- \include qstring.cpp latin1-numeric-conversion-note
-*/
-
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_DATASTREAM)
/*!
\fn QDataStream &operator<<(QDataStream &stream, const QString &string)
\relates QString
@@ -10257,16 +9564,15 @@ QDataStream &operator<<(QDataStream &out, const QString &str)
if (!str.isNull() || out.version() < 3) {
if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
out.writeBytes(reinterpret_cast<const char *>(str.unicode()),
- static_cast<uint>(sizeof(QChar) * str.length()));
+ static_cast<qsizetype>(sizeof(QChar) * str.size()));
} else {
- QVarLengthArray<char16_t> buffer(str.length());
- qbswap<sizeof(char16_t)>(str.constData(), str.length(), buffer.data());
+ QVarLengthArray<char16_t> buffer(str.size());
+ qbswap<sizeof(char16_t)>(str.constData(), str.size(), buffer.data());
out.writeBytes(reinterpret_cast<const char *>(buffer.data()),
- static_cast<uint>(sizeof(char16_t) * buffer.size()));
+ static_cast<qsizetype>(sizeof(char16_t) * buffer.size()));
}
} else {
- // write null marker
- out << (quint32)0xffffffff;
+ QDataStream::writeQSizeType(out, -1); // write null marker
}
}
return out;
@@ -10288,20 +9594,25 @@ QDataStream &operator>>(QDataStream &in, QString &str)
in >> l;
str = QString::fromLatin1(l);
} else {
- quint32 bytes = 0;
- in >> bytes; // read size of string
- if (bytes == 0xffffffff) { // null string
+ qint64 size = QDataStream::readQSizeType(in);
+ qsizetype bytes = size;
+ if (size != bytes || size < -1) {
str.clear();
- } else if (bytes > 0) { // not empty
+ in.setStatus(QDataStream::SizeLimitExceeded);
+ return in;
+ }
+ if (bytes == -1) { // null string
+ str = QString();
+ } else if (bytes > 0) {
if (bytes & 0x1) {
str.clear();
in.setStatus(QDataStream::ReadCorruptData);
return in;
}
- const quint32 Step = 1024 * 1024;
- quint32 len = bytes / 2;
- quint32 allocated = 0;
+ const qsizetype Step = 1024 * 1024;
+ qsizetype len = bytes / 2;
+ qsizetype allocated = 0;
while (allocated < len) {
int blockSize = qMin(Step, len - allocated);
@@ -10415,22 +9726,14 @@ qsizetype QtPrivate::count(QStringView haystack, QStringView needle, Qt::CaseSen
return num;
}
-qsizetype QtPrivate::count(QStringView haystack, QChar ch, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs) noexcept
{
- qsizetype num = 0;
- if (cs == Qt::CaseSensitive) {
- for (QChar c : haystack) {
- if (c == ch)
- ++num;
- }
- } else {
- ch = foldCase(ch);
- for (QChar c : haystack) {
- if (foldCase(c) == ch)
- ++num;
- }
- }
- return num;
+ if (cs == Qt::CaseSensitive)
+ return std::count(haystack.cbegin(), haystack.cend(), needle);
+
+ needle = foldCase(needle);
+ return std::count_if(haystack.cbegin(), haystack.cend(),
+ [needle](const QChar c) { return foldAndCompare(c, needle); });
}
qsizetype QtPrivate::count(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
@@ -10438,16 +9741,10 @@ qsizetype QtPrivate::count(QLatin1StringView haystack, QLatin1StringView needle,
qsizetype num = 0;
qsizetype i = -1;
- // TODO: use Boyer-Moore searcher for case-insensitive search too
- // when QTBUG-100236 is done
- if (cs == Qt::CaseSensitive) {
- QByteArrayMatcher matcher(needle);
- while ((i = matcher.indexIn(haystack, i + 1)) != -1)
- ++num;
- } else {
- while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1)
- ++num;
- }
+ QLatin1StringMatcher matcher(needle, cs);
+ while ((i = matcher.indexIn(haystack, i + 1)) != -1)
+ ++num;
+
return num;
}
@@ -10462,19 +9759,14 @@ qsizetype QtPrivate::count(QLatin1StringView haystack, QStringView needle, Qt::C
qsizetype num = 0;
qsizetype i = -1;
- // TODO: use Boyer-Moore searcher for case-insensitive search too
- // when QTBUG-100236 is done
- if (cs == Qt::CaseSensitive) {
- QVarLengthArray<uchar> s(needle.size());
- qt_to_latin1_unchecked(s.data(), needle.utf16(), needle.size());
+ QVarLengthArray<uchar> s(needle.size());
+ qt_to_latin1_unchecked(s.data(), needle.utf16(), needle.size());
+
+ QLatin1StringMatcher matcher(QLatin1StringView(reinterpret_cast<char *>(s.data()), s.size()),
+ cs);
+ while ((i = matcher.indexIn(haystack, i + 1)) != -1)
+ ++num;
- QByteArrayMatcher matcher(s);
- while ((i = matcher.indexIn(haystack, i + 1)) != -1)
- ++num;
- } else {
- while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1)
- ++num;
- }
return num;
}
@@ -10483,9 +9775,7 @@ qsizetype QtPrivate::count(QStringView haystack, QLatin1StringView needle, Qt::C
if (haystack.size() < needle.size())
return -1;
- QVarLengthArray<char16_t> s(needle.size());
- qt_from_latin1(s.data(), needle.latin1(), size_t(needle.size()));
-
+ QVarLengthArray<char16_t> s = qt_from_latin1_to_qvla(needle);
return QtPrivate::count(haystack, QStringView(s.data(), s.size()), cs);
}
@@ -10495,22 +9785,12 @@ qsizetype QtPrivate::count(QLatin1StringView haystack, QChar needle, Qt::CaseSen
if (needle.unicode() > 0xff)
return 0;
- qsizetype num = 0;
if (cs == Qt::CaseSensitive) {
- const char needleL1 = needle.toLatin1();
- for (char c : haystack) {
- if (c == needleL1)
- ++num;
- }
+ return std::count(haystack.cbegin(), haystack.cend(), needle.toLatin1());
} else {
- auto toLower = [](char ch) { return latin1Lower[uchar(ch)]; };
- const uchar ch = toLower(needle.toLatin1());
- for (char c : haystack) {
- if (toLower(c) == ch)
- ++num;
- }
+ return std::count_if(haystack.cbegin(), haystack.cend(),
+ CaseInsensitiveL1::matcher(needle.toLatin1()));
}
- return num;
}
/*!
@@ -10528,8 +9808,7 @@ qsizetype QtPrivate::count(QLatin1StringView haystack, QChar needle, Qt::CaseSen
Returns \c true if \a haystack starts with \a needle,
otherwise returns \c false.
- If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
- otherwise the search is case-insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa QtPrivate::endsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1StringView::endsWith()
*/
@@ -10569,8 +9848,7 @@ bool QtPrivate::startsWith(QLatin1StringView haystack, QLatin1StringView needle,
Returns \c true if \a haystack ends with \a needle,
otherwise returns \c false.
- If \a cs is Qt::CaseSensitive (the default), the search is case-sensitive;
- otherwise the search is case-insensitive.
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
\sa QtPrivate::startsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1StringView::endsWith()
*/
@@ -10599,6 +9877,8 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
{
const qsizetype l = haystack0.size();
const qsizetype sl = needle0.size();
+ if (sl == 1)
+ return findString(haystack0, from, needle0[0], cs);
if (from < 0)
from += l;
if (std::size_t(sl + from) > std::size_t(l))
@@ -10608,9 +9888,6 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
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
@@ -10675,8 +9952,7 @@ qsizetype QtPrivate::findString(QStringView haystack, qsizetype from, QLatin1Str
if (haystack.size() < needle.size())
return -1;
- QVarLengthArray<char16_t> s(needle.size());
- qt_from_latin1(s.data(), needle.latin1(), needle.size());
+ QVarLengthArray<char16_t> s = qt_from_latin1_to_qvla(needle);
return QtPrivate::findString(haystack, from, QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), cs);
}
@@ -10713,13 +9989,13 @@ qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLat
if (cs == Qt::CaseSensitive) {
if (needle.size() == 1) {
- Q_ASSUME(haystack.data() != nullptr); // see size check above
+ Q_ASSERT(haystack.data() != nullptr); // see size check above
if (auto it = memchr(haystack.data() + from, needle.front().toLatin1(), adjustedSize))
return static_cast<const char *>(it) - haystack.data();
return -1;
}
- const QByteArrayMatcher matcher(needle);
+ const QLatin1StringMatcher matcher(needle, Qt::CaseSensitivity::CaseSensitive);
return matcher.indexIn(haystack, from);
}
@@ -10740,12 +10016,9 @@ qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLat
if (needle.size() <= threshold) {
const auto begin = haystack.begin();
const auto end = haystack.end() - needle.size() + 1;
- const uchar needle1 = latin1Lower[uchar(needle[0].toLatin1())];
- auto ciMatch = [needle1](const char ch) {
- return latin1Lower[uchar(ch)] == needle1;
- };
+ auto ciMatch = CaseInsensitiveL1::matcher(needle[0].toLatin1());
const qsizetype nlen1 = needle.size() - 1;
- for (auto it = std::find_if(begin + from, end, ciMatch); it < end;
+ for (auto it = std::find_if(begin + from, end, ciMatch); it != end;
it = std::find_if(it + 1, end, ciMatch)) {
// In this comparison we skip the first character because we know it's a match
if (!nlen1 || QLatin1StringView(it + 1, nlen1).compare(needle.sliced(1), cs) == 0)
@@ -10754,27 +10027,13 @@ qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLat
return -1;
}
-#ifdef __cpp_lib_boyer_moore_searcher
- const auto ciHasher = [](char a) { return latin1Lower[uchar(a)]; };
- const auto ciEqual = [](char a, char b) {
- return latin1Lower[uchar(a)] == latin1Lower[uchar(b)];
- };
- const auto it =
- std::search(haystack.begin() + from, haystack.end(),
- std::boyer_moore_searcher(needle.begin(), needle.end(), ciHasher, ciEqual));
- return it == haystack.end() ? -1 : std::distance(haystack.begin(), it);
-#else
- QVarLengthArray<char16_t> h(adjustedSize);
- const auto begin = haystack.end() - adjustedSize;
- qt_from_latin1(h.data(), begin, adjustedSize);
- QVarLengthArray<char16_t> n(needle.size());
- qt_from_latin1(n.data(), needle.latin1(), needle.size());
- qsizetype res = QtPrivate::findString(QStringView(h.constData(), h.size()), 0,
- QStringView(n.constData(), n.size()), cs);
- if (res == -1)
- return -1;
- return res + std::distance(haystack.begin(), begin);
-#endif
+ QLatin1StringMatcher matcher(needle, Qt::CaseSensitivity::CaseInsensitive);
+ return matcher.indexIn(haystack, from);
+}
+
+qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, char16_t needle, Qt::CaseSensitivity cs) noexcept
+{
+ return qLastIndexOf(haystack, QChar(needle), from, cs);
}
qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
@@ -10798,14 +10057,16 @@ qsizetype QtPrivate::lastIndexOf(QLatin1StringView haystack, qsizetype from, QLa
}
#if QT_CONFIG(regularexpression)
-qsizetype QtPrivate::indexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
+qsizetype QtPrivate::indexOf(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
{
if (!re.isValid()) {
qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::indexOf");
return -1;
}
- QRegularExpressionMatch match = re.match(haystack, from);
+ QRegularExpressionMatch match = stringHaystack
+ ? re.match(*stringHaystack, from)
+ : re.matchView(viewHaystack, from);
if (match.hasMatch()) {
const qsizetype ret = match.capturedStart();
if (rmatch)
@@ -10816,15 +10077,22 @@ qsizetype QtPrivate::indexOf(QStringView haystack, const QRegularExpression &re,
return -1;
}
-qsizetype QtPrivate::lastIndexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
+qsizetype QtPrivate::indexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
+{
+ return indexOf(haystack, nullptr, re, from, rmatch);
+}
+
+qsizetype QtPrivate::lastIndexOf(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
{
if (!re.isValid()) {
qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::lastIndexOf");
return -1;
}
- qsizetype endpos = (from < 0) ? (haystack.size() + from + 1) : (from + 1);
- QRegularExpressionMatchIterator iterator = re.globalMatch(haystack);
+ qsizetype endpos = (from < 0) ? (viewHaystack.size() + from + 1) : (from + 1);
+ QRegularExpressionMatchIterator iterator = stringHaystack
+ ? re.globalMatch(*stringHaystack)
+ : re.globalMatchView(viewHaystack);
qsizetype lastIndex = -1;
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
@@ -10841,19 +10109,31 @@ qsizetype QtPrivate::lastIndexOf(QStringView haystack, const QRegularExpression
return lastIndex;
}
-bool QtPrivate::contains(QStringView haystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
+qsizetype QtPrivate::lastIndexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
+{
+ return lastIndexOf(haystack, nullptr, re, from, rmatch);
+}
+
+bool QtPrivate::contains(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
{
if (!re.isValid()) {
qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::contains");
return false;
}
- QRegularExpressionMatch m = re.match(haystack);
+ QRegularExpressionMatch m = stringHaystack
+ ? re.match(*stringHaystack)
+ : re.matchView(viewHaystack);
bool hasMatch = m.hasMatch();
if (hasMatch && rmatch)
*rmatch = std::move(m);
return hasMatch;
}
+bool QtPrivate::contains(QStringView haystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
+{
+ return contains(haystack, nullptr, re, rmatch);
+}
+
qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re)
{
if (!re.isValid()) {
@@ -10862,13 +10142,19 @@ qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re)
}
qsizetype count = 0;
qsizetype index = -1;
- qsizetype len = haystack.length();
+ qsizetype len = haystack.size();
while (index <= len - 1) {
- QRegularExpressionMatch match = re.match(haystack, index + 1);
+ QRegularExpressionMatch match = re.matchView(haystack, index + 1);
if (!match.hasMatch())
break;
- index = match.capturedStart();
count++;
+
+ // Search again, from the next character after the beginning of this
+ // capture. If the capture starts with a surrogate pair, both together
+ // count as "one character".
+ index = match.capturedStart();
+ if (index < len && haystack[index].isHighSurrogate())
+ ++index;
}
return count;
}
@@ -10888,20 +10174,24 @@ qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re)
*/
QString QString::toHtmlEscaped() const
{
+ const auto pos = std::u16string_view(*this).find_first_of(u"<>&\"");
+ if (pos == std::u16string_view::npos)
+ return *this;
QString rich;
- const int len = length();
+ const qsizetype len = size();
rich.reserve(qsizetype(len * 1.1));
- for (int i = 0; i < len; ++i) {
- if (at(i) == u'<')
+ rich += qToStringViewIgnoringNull(*this).first(pos);
+ for (auto ch : qToStringViewIgnoringNull(*this).sliced(pos)) {
+ if (ch == u'<')
rich += "&lt;"_L1;
- else if (at(i) == u'>')
+ else if (ch == u'>')
rich += "&gt;"_L1;
- else if (at(i) == u'&')
+ else if (ch == u'&')
rich += "&amp;"_L1;
- else if (at(i) == u'"')
+ else if (ch == u'"')
rich += "&quot;"_L1;
else
- rich += at(i);
+ rich += ch;
}
rich.squeeze();
return rich;
@@ -11003,25 +10293,6 @@ QString QString::toHtmlEscaped() const
*/
/*!
- \fn Qt::Literals::StringLiterals::operator""_L1(const char *str, size_t size)
-
- \relates QLatin1StringView
- \since 6.4
-
- Literal operator that creates a QLatin1StringView out of the first \a size
- characters in the char string literal \a str.
-
- The following code creates a QLatin1StringView:
- \code
- using namespace Qt::Literals::StringLiterals;
-
- auto str = "hello"_L1;
- \endcode
-
- \sa Qt::Literals::StringLiterals
-*/
-
-/*!
\internal
*/
void QAbstractConcatenable::appendLatin1To(QLatin1StringView in, QChar *out) noexcept
@@ -11029,16 +10300,6 @@ void QAbstractConcatenable::appendLatin1To(QLatin1StringView in, QChar *out) noe
qt_from_latin1(reinterpret_cast<char16_t *>(out), in.data(), size_t(in.size()));
}
-double QStringView::toDouble(bool *ok) const
-{
- return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator);
-}
-
-float QStringView::toFloat(bool *ok) const
-{
- return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
-}
-
/*!
\fn template <typename T> qsizetype erase(QString &s, const T &t)
\relates QString
@@ -11062,4 +10323,67 @@ float QStringView::toFloat(bool *ok) const
\sa erase
*/
+/*!
+ \macro const char *qPrintable(const QString &str)
+ \relates QString
+
+ Returns \a str as a \c{const char *}. This is equivalent to
+ \a{str}.toLocal8Bit().constData().
+
+ The char pointer will be invalid after the statement in which
+ qPrintable() is used. This is because the array returned by
+ QString::toLocal8Bit() will fall out of scope.
+
+ \note qDebug(), qInfo(), qWarning(), qCritical(), qFatal() expect
+ %s arguments to be UTF-8 encoded, while qPrintable() converts to
+ local 8-bit encoding. Therefore qUtf8Printable() should be used
+ for logging strings instead of qPrintable().
+
+ \sa qUtf8Printable()
+*/
+
+/*!
+ \macro const char *qUtf8Printable(const QString &str)
+ \relates QString
+ \since 5.4
+
+ Returns \a str as a \c{const char *}. This is equivalent to
+ \a{str}.toUtf8().constData().
+
+ The char pointer will be invalid after the statement in which
+ qUtf8Printable() is used. This is because the array returned by
+ QString::toUtf8() will fall out of scope.
+
+ Example:
+
+ \snippet code/src_corelib_text_qstring.cpp qUtf8Printable
+
+ \sa qPrintable(), qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
+*/
+
+/*!
+ \macro const wchar_t *qUtf16Printable(const QString &str)
+ \relates QString
+ \since 5.7
+
+ Returns \a str as a \c{const ushort *}, but cast to a \c{const wchar_t *}
+ to avoid warnings. This is equivalent to \a{str}.utf16() plus some casting.
+
+ The only useful thing you can do with the return value of this macro is to
+ pass it to QString::asprintf() for use in a \c{%ls} conversion. In particular,
+ the return value is \e{not} a valid \c{const wchar_t*}!
+
+ In general, the pointer will be invalid after the statement in which
+ qUtf16Printable() is used. This is because the pointer may have been
+ obtained from a temporary expression, which will fall out of scope.
+
+ Example:
+
+ \snippet code/src_corelib_text_qstring.cpp qUtf16Printable
+
+ \sa qPrintable(), qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
+*/
+
QT_END_NAMESPACE
+
+#undef REHASH