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.cpp9674
1 files changed, 4015 insertions, 5659 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index d327264218..f0bf0c50a3 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Copyright (C) 2019 Mail.ru Group.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2019 Mail.ru Group.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstringlist.h"
#if QT_CONFIG(regularexpression)
@@ -45,6 +9,7 @@
#endif
#include "qunicodetables_p.h"
#include <private/qstringconverter_p.h>
+#include <private/qtools_p.h>
#include "qlocale_tools_p.h"
#include "private/qsimd_p.h"
#include <qnumeric.h>
@@ -52,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
@@ -73,38 +40,286 @@
#include <wchar.h>
#include "qchar.cpp"
+#include "qlatin1stringmatcher.h"
#include "qstringmatcher.cpp"
#include "qstringiterator_p.h"
#include "qstringalgorithms_p.h"
#include "qthreadstorage.h"
+#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; \
+ hashHaystack <<= 1
QT_BEGIN_NAMESPACE
-template <typename T, typename Cmp = std::less<>>
-static constexpr bool points_into_range(const T *p, const T *b, const T *e, Cmp less = {}) noexcept
+using namespace Qt::StringLiterals;
+using namespace QtMiscUtils;
+
+const char16_t QString::_empty = 0;
+
+// in qstringmatcher.cpp
+qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs);
+
+namespace {
+enum StringComparisonMode {
+ CompareStringsForEquality,
+ CompareStringsForOrdering
+};
+
+template <typename Pointer>
+char32_t foldCaseHelper(Pointer ch, Pointer start) = delete;
+
+template <>
+char32_t foldCaseHelper<const QChar*>(const QChar* ch, const QChar* start)
+{
+ return foldCase(reinterpret_cast<const char16_t*>(ch),
+ reinterpret_cast<const char16_t*>(start));
+}
+
+template <>
+char32_t foldCaseHelper<const char*>(const char* ch, const char*)
+{
+ return foldCase(char16_t(uchar(*ch)));
+}
+
+template <typename T>
+char16_t valueTypeToUtf16(T t) = delete;
+
+template <>
+char16_t valueTypeToUtf16<QChar>(QChar t)
+{
+ return t.unicode();
+}
+
+template <>
+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
+
+ Returns the index position of the first occurrence of the
+ character \a ch in the string given by \a str and \a len,
+ searching forward from index
+ position \a from. Returns -1 if \a ch could not be found.
+*/
+template <typename Haystack>
+static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
+ qsizetype from, Qt::CaseSensitivity cs) noexcept
+{
+ if (haystack.size() == 0)
+ return -1;
+ if (from < 0)
+ from += haystack.size();
+ else if (std::size_t(from) > std::size_t(haystack.size()))
+ from = haystack.size() - 1;
+ if (from >= 0) {
+ char16_t c = needle.unicode();
+ const auto b = haystack.data();
+ auto n = b + from;
+ if (cs == Qt::CaseSensitive) {
+ for (; n >= b; --n)
+ if (valueTypeToUtf16(*n) == c)
+ return n - b;
+ } else {
+ c = foldCase(c);
+ for (; n >= b; --n)
+ if (foldCase(valueTypeToUtf16(*n)) == c)
+ return n - b;
+ }
+ }
+ return -1;
+}
+template <> qsizetype
+qLastIndexOf(QString, QChar, qsizetype, Qt::CaseSensitivity) noexcept = delete; // unwanted, would detach
+
+template<typename Haystack, typename Needle>
+static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from,
+ Needle needle0, Qt::CaseSensitivity cs) noexcept
+{
+ const qsizetype sl = needle0.size();
+ if (sl == 1)
+ return qLastIndexOf(haystack0, needle0.front(), from, cs);
+
+ const qsizetype l = haystack0.size();
+ if (from < 0)
+ from += l;
+ if (from == l && sl == 0)
+ return from;
+ const qsizetype delta = l - sl;
+ if (std::size_t(from) > std::size_t(l) || delta < 0)
+ return -1;
+ if (from > delta)
+ from = delta;
+
+ auto sv = [sl](const typename Haystack::value_type *v) { return Haystack(v, sl); };
+
+ auto haystack = haystack0.data();
+ const auto needle = needle0.data();
+ const auto *end = haystack;
+ haystack += from;
+ const std::size_t sl_minus_1 = sl ? sl - 1 : 0;
+ const auto *n = needle + sl_minus_1;
+ const auto *h = haystack + sl_minus_1;
+ std::size_t hashNeedle = 0, hashHaystack = 0;
+
+ if (cs == Qt::CaseSensitive) {
+ for (qsizetype idx = 0; idx < sl; ++idx) {
+ hashNeedle = (hashNeedle << 1) + valueTypeToUtf16(*(n - idx));
+ hashHaystack = (hashHaystack << 1) + valueTypeToUtf16(*(h - idx));
+ }
+ hashHaystack -= valueTypeToUtf16(*haystack);
+
+ while (haystack >= end) {
+ hashHaystack += valueTypeToUtf16(*haystack);
+ if (hashHaystack == hashNeedle
+ && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
+ return haystack - end;
+ --haystack;
+ REHASH(valueTypeToUtf16(haystack[sl]));
+ }
+ } else {
+ for (qsizetype idx = 0; idx < sl; ++idx) {
+ hashNeedle = (hashNeedle << 1) + foldCaseHelper(n - idx, needle);
+ hashHaystack = (hashHaystack << 1) + foldCaseHelper(h - idx, end);
+ }
+ hashHaystack -= foldCaseHelper(haystack, end);
+
+ while (haystack >= end) {
+ hashHaystack += foldCaseHelper(haystack, end);
+ if (hashHaystack == hashNeedle
+ && QtPrivate::compareStrings(sv(haystack), needle0, Qt::CaseInsensitive) == 0)
+ return haystack - end;
+ --haystack;
+ REHASH(foldCaseHelper(haystack + sl, end));
+ }
+ }
+ return -1;
+}
+
+template <typename Haystack, typename Needle>
+bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
+{
+ if (haystack.isNull())
+ return needle.isNull();
+ const auto haystackLen = haystack.size();
+ const auto needleLen = needle.size();
+ if (haystackLen == 0)
+ return needleLen == 0;
+ if (needleLen > haystackLen)
+ return false;
+
+ return QtPrivate::compareStrings(haystack.first(needleLen), needle, cs) == 0;
+}
+
+template <typename Haystack, typename Needle>
+bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
+{
+ if (haystack.isNull())
+ return needle.isNull();
+ const auto haystackLen = haystack.size();
+ const auto needleLen = needle.size();
+ if (haystackLen == 0)
+ return needleLen == 0;
+ if (haystackLen < needleLen)
+ return false;
+
+ 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 !less(p, b) && less(p, e);
+ return returnIfExited;
}
+} // unnamed namespace
/*
* Note on the use of SIMD in qstring.cpp:
@@ -143,32 +358,38 @@ extern "C" void qt_fromlatin1_mips_asm_unroll8 (char16_t*, const char*, uint);
extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const char16_t *src, int length);
#endif
-// internal
-qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs);
-static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept;
-template <typename Haystack>
-static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept;
-template <>
-inline qsizetype qLastIndexOf(QString haystack, QChar needle,
- qsizetype from, Qt::CaseSensitivity cs) noexcept = delete; // unwanted, would detach
-
-static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
-static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
-static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
-static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
-static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
-static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
-
-#if defined(__SSE2__) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
+#if defined(__SSE2__) && defined(Q_CC_GNU)
// 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);
+ }
+
+ // use MOVQ followed by PUNPCKLBW
+ __m128i data = _mm_loadl_epi64(dataptr);
+ return _mm_unpacklo_epi8(data, _mm_setzero_si128());
+}
-#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || QT_HAS_FEATURE(address_sanitizer))
+[[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);
@@ -179,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;
@@ -187,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
@@ -261,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();
@@ -270,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);
@@ -321,10 +745,10 @@ 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__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+#elif defined(__ARM_NEON__)
const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
const uint16x8_t ch_vec = vdupq_n_u16(c);
for (const char16_t *next = n + 8; next <= e; n = next, next += 8) {
@@ -337,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;
+ return std::find(n, e, c);
}
-#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;
-}
-
-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.
@@ -466,18 +787,21 @@ 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
-# 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;
+ bool loops = true;
+ 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;
}
-# endif
+
while (ptr + 16 <= end) {
__m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
quint32 mask = _mm_movemask_epi8(data);
@@ -487,6 +811,9 @@ bool qt_is_ascii(const char *&ptr, const char *end) noexcept
return false;
}
ptr += 16;
+
+ if (!loops)
+ break;
}
if (ptr + 8 <= end) {
__m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
@@ -503,11 +830,9 @@ bool qt_is_ascii(const char *&ptr, const char *end) noexcept
while (ptr + 4 <= end) {
quint32 data = qFromUnaligned<quint32>(ptr);
if (data &= 0x80808080U) {
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- uint idx = qCountLeadingZeroBits(data);
-#else
- uint idx = qCountTrailingZeroBits(data);
-#endif
+ uint idx = QSysInfo::ByteOrder == QSysInfo::BigEndian
+ ? qCountLeadingZeroBits(data)
+ : qCountTrailingZeroBits(data);
ptr += idx / 8;
return false;
}
@@ -522,7 +847,7 @@ bool qt_is_ascii(const char *&ptr, const char *end) noexcept
return true;
}
-bool QtPrivate::isAscii(QLatin1String s) noexcept
+bool QtPrivate::isAscii(QLatin1StringView s) noexcept
{
const char *ptr = s.begin();
const char *end = s.end();
@@ -530,19 +855,19 @@ bool QtPrivate::isAscii(QLatin1String s) noexcept
return qt_is_ascii(ptr, end);
}
-static bool isAscii(const QChar *&ptr, const QChar *end)
+static bool isAscii_helper(const char16_t *&ptr, const char16_t *end)
{
#ifdef __SSE2__
const char *ptr8 = reinterpret_cast<const char *>(ptr);
const char *end8 = reinterpret_cast<const char *>(end);
bool ok = simdTestMask(ptr8, end8, 0xff80ff80);
- ptr = reinterpret_cast<const QChar *>(ptr8);
+ ptr = reinterpret_cast<const char16_t *>(ptr8);
if (!ok)
return false;
#endif
while (ptr != end) {
- if (ptr->unicode() & 0xff80)
+ if (*ptr & 0xff80)
return false;
++ptr;
}
@@ -551,46 +876,27 @@ static bool isAscii(const QChar *&ptr, const QChar *end)
bool QtPrivate::isAscii(QStringView s) noexcept
{
- const QChar *ptr = s.begin();
- const QChar *end = s.end();
+ const char16_t *ptr = s.utf16();
+ const char16_t *end = ptr + s.size();
- return isAscii(ptr, end);
+ return isAscii_helper(ptr, end);
}
bool QtPrivate::isLatin1(QStringView s) noexcept
{
- const QChar *ptr = s.begin();
- const QChar *end = s.end();
+ const char16_t *ptr = s.utf16();
+ const char16_t *end = ptr + s.size();
-#if defined(__SSE4_1__)
+#ifdef __SSE2__
const char *ptr8 = reinterpret_cast<const char *>(ptr);
const char *end8 = reinterpret_cast<const char *>(end);
if (!simdTestMask(ptr8, end8, 0xff00ff00))
return false;
- ptr = reinterpret_cast<const QChar *>(ptr8);
-#elif defined(__SSE2__)
- // Testing if every other byte is non-zero can be done efficiently by
- // using PUNPCKHBW (unpack high order bytes) and comparing that to zero.
- 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));
- __m128i high = _mm_unpackhi_epi8(data1, data2);
- __m128i comparison = _mm_cmpeq_epi16(high, _mm_setzero_si128());
- if (_mm_movemask_epi8(comparison))
- return false;
- ptr += 16;
- }
- if (ptr + 16 < end) {
- __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
- __m128i high = _mm_unpackhi_epi8(data1, data1);
- __m128i comparison = _mm_cmpeq_epi16(high, _mm_setzero_si128());
- if (_mm_movemask_epi8(comparison))
- return false;
- }
+ ptr = reinterpret_cast<const char16_t *>(ptr8);
#endif
while (ptr != end) {
- if ((*ptr++).unicode() > 0xff)
+ if (*ptr++ > 0xff)
return false;
}
return true;
@@ -598,7 +904,7 @@ bool QtPrivate::isLatin1(QStringView s) noexcept
bool QtPrivate::isValidUtf16(QStringView s) noexcept
{
- Q_CONSTEXPR char32_t InvalidCodePoint = UINT_MAX;
+ constexpr char32_t InvalidCodePoint = UINT_MAX;
QStringIterator i(s);
while (i.hasNext()) {
@@ -619,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);
+ if constexpr (UseAvx2) {
+ // 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);
-
- // 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
@@ -669,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));
@@ -713,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 use eactly the same method as for SSE except:
+ // 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;
@@ -814,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--) {
@@ -826,7 +1180,7 @@ static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype len
#endif
}
-static void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length)
+void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length)
{
qt_to_latin1_internal<true>(dst, src, length);
}
@@ -836,58 +1190,80 @@ void qt_to_latin1_unchecked(uchar *dst, const char16_t *src, qsizetype length)
qt_to_latin1_internal<false>(dst, src, length);
}
-// Unicode case-insensitive comparison
-static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QChar *be)
+// Unicode case-insensitive comparison (argument order matches QStringView)
+Q_NEVER_INLINE static int ucstricmp(qsizetype alen, const char16_t *a, qsizetype blen, const char16_t *b)
{
if (a == b)
- return (ae - be);
-
- const QChar *e = ae;
- if (be - b < ae - a)
- e = a + (be - b);
+ return qt_lencmp(alen, blen);
char32_t alast = 0;
char32_t blast = 0;
- while (a < e) {
+ qsizetype l = qMin(alen, blen);
+ qsizetype i;
+ for (i = 0; i < l; ++i) {
// qDebug() << Qt::hex << alast << blast;
// qDebug() << Qt::hex << "*a=" << *a << "alast=" << alast << "folded=" << foldCase (*a, alast);
// qDebug() << Qt::hex << "*b=" << *b << "blast=" << blast << "folded=" << foldCase (*b, blast);
- int diff = foldCase(a->unicode(), alast) - foldCase(b->unicode(), blast);
+ int diff = foldCase(a[i], alast) - foldCase(b[i], blast);
if ((diff))
return diff;
- ++a;
- ++b;
}
- if (a == ae) {
- if (b == be)
+ if (i == alen) {
+ if (i == blen)
return 0;
return -1;
}
return 1;
}
-// Case-insensitive comparison between a Unicode string and a QLatin1String
-static int ucstricmp(const QChar *a, const QChar *ae, const char *b, const char *be)
+// Case-insensitive comparison between a QStringView and a QLatin1StringView
+// (argument order matches those types)
+Q_NEVER_INLINE static int ucstricmp(qsizetype alen, const char16_t *a, qsizetype blen, const char *b)
{
- auto e = ae;
- if (be - b < ae - a)
- e = a + (be - b);
-
- while (a < e) {
- int diff = foldCase(a->unicode()) - foldCase(char16_t{uchar(*b)});
+ qsizetype l = qMin(alen, blen);
+ qsizetype i;
+ for (i = 0; i < l; ++i) {
+ int diff = foldCase(a[i]) - foldCase(char16_t{uchar(b[i])});
if ((diff))
return diff;
- ++a;
- ++b;
}
- if (a == ae) {
- if (b == be)
+ if (i == alen) {
+ if (i == blen)
return 0;
return -1;
}
return 1;
}
+// Case-insensitive comparison between a Unicode string and a UTF-8 string
+Q_NEVER_INLINE static int ucstricmp8(const char *utf8, const char *utf8end, const QChar *utf16, const QChar *utf16end)
+{
+ auto src1 = reinterpret_cast<const uchar *>(utf8);
+ auto end1 = reinterpret_cast<const uchar *>(utf8end);
+ QStringIterator src2(utf16, utf16end);
+
+ while (src1 < end1 && src2.hasNext()) {
+ char32_t uc1 = 0;
+ char32_t *output = &uc1;
+ uchar b = *src1++;
+ const qsizetype res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, output, src1, end1);
+ if (res < 0) {
+ // decoding error
+ uc1 = QChar::ReplacementCharacter;
+ } else {
+ uc1 = QChar::toCaseFolded(uc1);
+ }
+
+ char32_t uc2 = QChar::toCaseFolded(src2.next());
+ int diff = uc1 - uc2; // can't underflow
+ if (diff)
+ return diff;
+ }
+
+ // the shorter string sorts first
+ return (end1 > src1) - int(src2.hasNext());
+}
+
#if defined(__mips_dsp)
// From qstring_mips_dsp_asm.S
extern "C" int qt_ucstrncmp_mips_dsp_asm(const char16_t *a,
@@ -896,98 +1272,24 @@ extern "C" int qt_ucstrncmp_mips_dsp_asm(const char16_t *a,
#endif
// Unicode case-sensitive compare two same-sized strings
-static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
+template <StringComparisonMode Mode>
+static int ucstrncmp(const char16_t *a, const char16_t *b, size_t l)
{
-#ifdef __OPTIMIZE_SIZE__
- const QChar *end = a + l;
- while (a < end) {
- if (int diff = (int)a->unicode() - (int)b->unicode())
- return diff;
- ++a;
- ++b;
- }
- return 0;
-#else
-#if defined(__mips_dsp)
+ // 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));
if (l >= 8) {
- return qt_ucstrncmp_mips_dsp_asm(reinterpret_cast<const char16_t*>(a),
- reinterpret_cast<const char16_t*>(b),
- l);
+ return qt_ucstrncmp_mips_dsp_asm(a, b, l);
}
-#endif // __mips_dsp
-#ifdef __SSE2__
- const QChar *end = a + l;
- qptrdiff offset = 0;
-
- // Using the PMOVMSKB instruction, we get two bits for each character
- // we compare.
- int retval;
- auto isDifferent = [a, b, &offset, &retval](__m128i a_data, __m128i b_data) {
- __m128i result = _mm_cmpeq_epi16(a_data, b_data);
- uint mask = ~uint(_mm_movemask_epi8(result));
- if (ushort(mask) == 0)
- return false;
- uint idx = qCountTrailingZeroBits(mask);
- retval = a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode();
- return true;
- };
-
- // we're going to read a[0..15] and b[0..15] (32 bytes)
- for ( ; 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
- uint idx = qCountTrailingZeroBits(mask);
- return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode();
- }
- }
-
- // 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].unicode() - b[offset + i].unicode();
- };
- return UnrollTailLoop<3>::exec(l, 0, lambda, lambda);
-#endif
-#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+# elif defined(__SSE2__)
+ return ucstrncmp_sse2<Mode>(a, b, l);
+# elif defined(__ARM_NEON__)
if (l >= 8) {
- const QChar *end = a + l;
+ const char16_t *end = a + l;
const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
while (end - a > 7) {
uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
@@ -996,8 +1298,10 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
if (r) {
// found a different QChar
+ if (Mode == CompareStringsForEquality)
+ return 1;
uint idx = qCountTrailingZeroBits(r);
- return (int)a[idx].unicode() - (int)b[idx].unicode();
+ return a[idx] - b[idx];
}
a += 8;
b += 8;
@@ -1005,156 +1309,31 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
l &= 7;
}
const auto lambda = [=](size_t i) -> int {
- return a[i].unicode() - b[i].unicode();
+ return a[i] - b[i];
};
return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
-#endif // __ARM_NEON__
- if (!l)
- return 0;
-
- // check alignment
- if ((reinterpret_cast<quintptr>(a) & 2) == (reinterpret_cast<quintptr>(b) & 2)) {
- // both addresses have the same alignment
- if (reinterpret_cast<quintptr>(a) & 2) {
- // both addresses are not aligned to 4-bytes boundaries
- // compare the first character
- if (*a != *b)
- return a->unicode() - b->unicode();
- --l;
- ++a;
- ++b;
-
- // now both addresses are 4-bytes aligned
- }
+# endif // MIPS DSP or __SSE2__ or __ARM_NEON__
+#endif // __OPTIMIZE_SIZE__
- // both addresses are 4-bytes aligned
- // do a fast 32-bit comparison
- const quint32 *da = reinterpret_cast<const quint32 *>(a);
- const quint32 *db = reinterpret_cast<const quint32 *>(b);
- const quint32 *e = da + (l >> 1);
- for ( ; da != e; ++da, ++db) {
- if (*da != *db) {
- a = reinterpret_cast<const QChar *>(da);
- b = reinterpret_cast<const QChar *>(db);
- if (*a != *b)
- return a->unicode() - b->unicode();
- return a[1].unicode() - b[1].unicode();
- }
- }
+ if (Mode == CompareStringsForEquality || QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return memcmp(a, b, l * sizeof(char16_t));
- // do we have a tail?
- a = reinterpret_cast<const QChar *>(da);
- b = reinterpret_cast<const QChar *>(db);
- return (l & 1) ? a->unicode() - b->unicode() : 0;
- } else {
- // one of the addresses isn't 4-byte aligned but the other is
- const QChar *e = a + l;
- for ( ; a != e; ++a, ++b) {
- if (*a != *b)
- return a->unicode() - b->unicode();
- }
+ for (size_t i = 0; i < l; ++i) {
+ if (int diff = a[i] - b[i])
+ return diff;
}
return 0;
-#endif
}
-static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
+template <StringComparisonMode Mode>
+static int ucstrncmp(const char16_t *a, const char *b, size_t l)
{
- const char16_t *uc = reinterpret_cast<const char16_t *>(a);
+ const uchar *c = reinterpret_cast<const uchar *>(b);
+ 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;
- 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
- 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) {
@@ -1167,101 +1346,114 @@ static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
return 0;
}
-template <typename Number>
-Q_DECL_CONSTEXPR int lencmp(Number lhs, Number rhs) noexcept
+// Unicode case-sensitive equality
+template <typename Char2>
+static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b)
{
- return lhs == rhs ? 0 :
- lhs > rhs ? 1 :
- /* else */ -1 ;
+ if constexpr (std::is_same_v<decltype(a), decltype(b)>) {
+ if (a == b)
+ return true;
+ }
+ return ucstrncmp<CompareStringsForEquality>(a, b, alen) == 0;
}
// Unicode case-sensitive comparison
-static int ucstrcmp(const QChar *a, size_t alen, const QChar *b, size_t blen)
+template <typename Char2>
+static int ucstrcmp(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
{
- if (a == b && alen == blen)
- return 0;
+ if constexpr (std::is_same_v<decltype(a), decltype(b)>) {
+ if (a == b && alen == blen)
+ return 0;
+ }
const size_t l = qMin(alen, blen);
- int cmp = ucstrncmp(a, b, l);
- return cmp ? cmp : lencmp(alen, blen);
+ int cmp = ucstrncmp<CompareStringsForOrdering>(a, b, l);
+ return cmp ? cmp : qt_lencmp(alen, blen);
}
-static int ucstrcmp(const QChar *a, size_t alen, const char *b, size_t blen)
+using CaseInsensitiveL1 = QtPrivate::QCaseInsensitiveLatin1Hash;
+
+static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar, qsizetype rSize)
{
- const size_t l = qMin(alen, blen);
- const int cmp = ucstrncmp(a, reinterpret_cast<const uchar*>(b), l);
- return cmp ? cmp : lencmp(alen, blen);
-}
-
-static int latin1nicmp(const char *lhsChar, int lSize, const char *rhsChar, int rSize)
-{
- 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
- };
- // We're called with QLatin1String's .data() and .size():
+ // We're called with QLatin1StringView's .data() and .size():
Q_ASSERT(lSize >= 0 && rSize >= 0);
if (!lSize)
return rSize ? -1 : 0;
if (!rSize)
return 1;
- const int 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
- for (int i = 0; i < size; i++) {
- Q_ASSERT(lhs[i] && rhs[i]);
- if (int res = latin1Lower[lhs[i]] - latin1Lower[rhs[i]])
+ const qsizetype size = std::min(lSize, rSize);
+
+ Q_ASSERT(lhsChar && rhsChar); // since both lSize and rSize are positive
+ for (qsizetype i = 0; i < size; i++) {
+ if (int res = CaseInsensitiveL1::difference(lhsChar[i], rhsChar[i]))
return res;
}
- return lencmp(lSize, rSize);
+ return qt_lencmp(lSize, rSize);
}
-static int qt_compare_strings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::equalStrings(QStringView lhs, QStringView rhs) noexcept
{
- if (cs == Qt::CaseSensitive)
- return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size());
- else
- return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ Q_ASSERT(lhs.size() == rhs.size());
+ return ucstreq(lhs.utf16(), lhs.size(), rhs.utf16());
}
-static int qt_compare_strings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::equalStrings(QStringView lhs, QLatin1StringView rhs) noexcept
{
- if (cs == Qt::CaseSensitive)
- return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size());
- else
- return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ Q_ASSERT(lhs.size() == rhs.size());
+ return ucstreq(lhs.utf16(), lhs.size(), rhs.latin1());
}
-static int qt_compare_strings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::equalStrings(QLatin1StringView lhs, QStringView rhs) noexcept
{
- return -qt_compare_strings(rhs, lhs, cs);
+ return QtPrivate::equalStrings(rhs, lhs);
}
-static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::equalStrings(QLatin1StringView lhs, QLatin1StringView rhs) noexcept
{
- if (lhs.isEmpty())
- return lencmp(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 = qstrncmp(lhs.data(), rhs.data(), l);
- return r ? r : lencmp(lhs.size(), rhs.size());
+ 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
+{
+ return QUtf8::compareUtf8(lhs, rhs) == 0;
+}
+
+bool QtPrivate::equalStrings(QStringView lhs, QBasicUtf8StringView<false> rhs) noexcept
+{
+ return QtPrivate::equalStrings(rhs, lhs);
+}
+
+bool QtPrivate::equalStrings(QLatin1StringView lhs, QBasicUtf8StringView<false> rhs) noexcept
+{
+ return QUtf8::compareUtf8(QByteArrayView(rhs), lhs) == 0;
+}
+
+bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QLatin1StringView rhs) noexcept
+{
+ return QtPrivate::equalStrings(rhs, lhs);
+}
+
+bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs) noexcept
+{
+#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
+{
+ if (lhs.size() != rhs.size() && lhs.isUtf8() == rhs.isUtf8())
+ return false;
+ return lhs.visit([rhs](auto lhs) {
+ return rhs.visit([lhs](auto rhs) {
+ return QtPrivate::equalStrings(lhs, rhs);
+ });
+ });
}
/*!
@@ -1271,16 +1463,19 @@ static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSens
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.
Consider sorting user-visible strings with QString::localeAwareCompare().
+
+ \sa {Comparing Strings}
*/
int QtPrivate::compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
{
- return qt_compare_strings(lhs, rhs, cs);
+ if (cs == Qt::CaseSensitive)
+ return ucstrcmp(lhs.utf16(), lhs.size(), rhs.utf16(), rhs.size());
+ return ucstricmp(lhs.size(), lhs.utf16(), rhs.size(), rhs.utf16());
}
/*!
@@ -1291,36 +1486,41 @@ 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.
Consider sorting user-visible strings with QString::localeAwareCompare().
+
+ \sa {Comparing Strings}
*/
-int QtPrivate::compareStrings(QStringView lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept
+int QtPrivate::compareStrings(QStringView lhs, QLatin1StringView rhs, Qt::CaseSensitivity cs) noexcept
{
- return qt_compare_strings(lhs, rhs, cs);
+ if (cs == Qt::CaseSensitive)
+ return ucstrcmp(lhs.utf16(), lhs.size(), rhs.latin1(), rhs.size());
+ return ucstricmp(lhs.size(), lhs.utf16(), rhs.size(), rhs.latin1());
}
/*!
\relates QStringView
\internal
- \since 5.10
+ \since 6.0
\overload
+*/
+int QtPrivate::compareStrings(QStringView lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return -compareStrings(rhs, lhs, cs);
+}
- 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.
-
- 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.
- Consider sorting user-visible strings with QString::localeAwareCompare().
+/*!
+ \relates QStringView
+ \internal
+ \since 5.10
+ \overload
*/
-int QtPrivate::compareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+int QtPrivate::compareStrings(QLatin1StringView lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
{
- return qt_compare_strings(lhs, rhs, cs);
+ return -compareStrings(rhs, lhs, cs);
}
/*!
@@ -1331,53 +1531,130 @@ int QtPrivate::compareStrings(QLatin1String lhs, QStringView rhs, Qt::CaseSensit
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.
Consider sorting user-visible strings with QString::localeAwareCompare().
+
+ \sa {Comparing Strings}
*/
-int QtPrivate::compareStrings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) noexcept
+int QtPrivate::compareStrings(QLatin1StringView lhs, QLatin1StringView rhs, Qt::CaseSensitivity cs) noexcept
{
- return qt_compare_strings(lhs, rhs, cs);
+ if (lhs.isEmpty())
+ 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 : qt_lencmp(lhs.size(), rhs.size());
}
-#define REHASH(a) \
- if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
- hashHaystack -= std::size_t(a) << sl_minus_1; \
- hashHaystack <<= 1
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
+*/
+int QtPrivate::compareStrings(QLatin1StringView lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
+{
+ return -QUtf8::compareUtf8(QByteArrayView(rhs), lhs, cs);
+}
+
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
+*/
+int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
+{
+ if (cs == Qt::CaseSensitive)
+ return QUtf8::compareUtf8(lhs, rhs);
+ return ucstricmp8(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
-inline bool qIsUpper(char ch)
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
+*/
+int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QLatin1StringView rhs, Qt::CaseSensitivity cs) noexcept
{
- return ch >= 'A' && ch <= 'Z';
+ return -compareStrings(rhs, lhs, cs);
}
-inline bool qIsDigit(char ch)
+/*!
+ \relates QStringView
+ \internal
+ \since 6.0
+ \overload
+*/
+int QtPrivate::compareStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs, Qt::CaseSensitivity cs) noexcept
{
- return ch >= '0' && ch <= '9';
+ return QUtf8::compareUtf8(QByteArrayView(lhs), QByteArrayView(rhs), cs);
}
-inline char qToLower(char ch)
+int QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs) noexcept
{
- if (ch >= 'A' && ch <= 'Z')
- return ch - 'A' + 'a';
- else
- return ch;
+ return lhs.visit([rhs, cs](auto lhs) {
+ return rhs.visit([lhs, cs](auto rhs) {
+ return QtPrivate::compareStrings(lhs, rhs, cs);
+ });
+ });
}
+// ### Qt 7: do not allow anything but ASCII digits
+// in arg()'s replacements.
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+static bool supportUnicodeDigitValuesInArg()
+{
+ static const bool result = []() {
+ static const char supportUnicodeDigitValuesEnvVar[]
+ = "QT_USE_UNICODE_DIGIT_VALUES_IN_STRING_ARG";
+
+ if (qEnvironmentVariableIsSet(supportUnicodeDigitValuesEnvVar))
+ return qEnvironmentVariableIntValue(supportUnicodeDigitValuesEnvVar) != 0;
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) // keep it in sync with the test
+ return true;
+#else
+ return false;
+#endif
+ }();
+
+ return result;
+}
+#endif
+
+static int qArgDigitValue(QChar ch) noexcept
+{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ if (supportUnicodeDigitValuesInArg())
+ return ch.digitValue();
+#endif
+ if (ch >= u'0' && ch <= u'9')
+ return int(ch.unicode() - u'0');
+ return -1;
+}
+
+#if QT_CONFIG(regularexpression)
+Q_DECL_COLD_FUNCTION
+void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *where);
+#endif
/*!
\macro QT_RESTRICTED_CAST_FROM_ASCII
\relates QString
- Defining this macro disables most automatic conversions from source
- literals and 8-bit data to unicode QStrings, but allows the use of
+ Disables most automatic conversions from source literals and 8-bit data
+ to unicode QStrings, but allows the use of
the \c{QChar(char)} and \c{QString(const char (&ch)[N]} constructors,
- and the \c{QString::operator=(const char (&ch)[N])} assignment operator
- giving most of the type-safety benefits of \c QT_NO_CAST_FROM_ASCII
+ and the \c{QString::operator=(const char (&ch)[N])} assignment operator.
+ This gives most of the type-safety benefits of \l QT_NO_CAST_FROM_ASCII
but does not require user code to wrap character and string literals
- with QLatin1Char, QLatin1String or similar.
+ with QLatin1Char, QLatin1StringView or similar.
Using this macro together with source strings outside the 7-bit range,
non-literals, or literals with embedded NUL characters is undefined.
@@ -1388,19 +1665,24 @@ inline char qToLower(char ch)
/*!
\macro QT_NO_CAST_FROM_ASCII
\relates QString
+ \relates QChar
- Disables automatic conversions from 8-bit strings (char *) to unicode QStrings
+ Disables automatic conversions from 8-bit strings (\c{char *}) to Unicode
+ QStrings, as well as from 8-bit \c{char} types (\c{char} and
+ \c{unsigned char}) to QChar.
- \sa QT_NO_CAST_TO_ASCII, QT_RESTRICTED_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY
+ \sa QT_NO_CAST_TO_ASCII, QT_RESTRICTED_CAST_FROM_ASCII,
+ QT_NO_CAST_FROM_BYTEARRAY
*/
/*!
\macro QT_NO_CAST_TO_ASCII
\relates QString
- disables automatic conversion from QString to 8-bit strings (char *)
+ Disables automatic conversion from QString to 8-bit strings (\c{char *}).
- \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY
+ \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII,
+ QT_NO_CAST_FROM_BYTEARRAY
*/
/*!
@@ -1428,10 +1710,18 @@ inline char qToLower(char ch)
\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
@@ -1447,17 +1737,15 @@ inline char qToLower(char ch)
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).
-
- \tableofcontents
+ 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).
- \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":
@@ -1468,23 +1756,24 @@ inline char qToLower(char ch)
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
0-based indexes, just like C++ arrays. To access the character at
a particular index position, you can use \l operator[](). On
- non-const strings, \l operator[]() returns a reference to a
+ non-\c{const} strings, \l operator[]() returns a reference to a
character that can be used on the left side of an assignment. For
example:
@@ -1495,9 +1784,9 @@ inline char qToLower(char ch)
\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
- left(), right(), or mid() functions to extract several characters
+ first(), last(), or sliced() functions to extract several characters
at a time.
A QString can embed '\\0' characters (QChar::Null). The size()
@@ -1517,11 +1806,11 @@ inline char qToLower(char ch)
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
@@ -1529,32 +1818,62 @@ inline char qToLower(char ch)
\snippet qstring/main.cpp 5
+ 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,
+ 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 significantly increased.
+
+ 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
+ by at least one position in memory.
+
If you are building a QString gradually and know in advance
approximately how many characters the QString will contain, you
can call reserve(), asking QString to preallocate a certain amount
of memory. You can also call capacity() to find out how much
- memory QString actually allocated.
-
- The replace() and remove() functions' first two arguments are the
- position from which to start erasing and the number of characters
- that should be erased. If you want to replace all occurrences of
- a particular substring with another, use one of the two-parameter
- replace() overloads.
-
- 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().
+ memory the QString actually has allocated.
+
+ QString provides \l{STL-style iterators} (QString::const_iterator and
+ QString::iterator). In practice, iterators are handy when working with
+ generic algorithms provided by the C++ standard library.
+
+ \note Iterators over a QString, and references to individual characters
+ within one, cannot be relied on to remain valid when any non-\c{const}
+ 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
+ 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
+ copy of its data. This invalidates all iterators over the string and
+ 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
@@ -1563,41 +1882,57 @@ inline char qToLower(char ch)
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().
-
- 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 a better choice for sorting user-interface strings.
+ 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-const function is called on the QString.
+ non-\c{const} function is called on the QString.
+
+ \section2 Comparing strings
+
+ QStrings can be compared using overloaded operators such as \l
+ operator<(), \l operator<=(), \l operator==(), \l operator>=(),
+ 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 strings data and QString
+ \section1 Converting between encoded string data and QString
- QString provides the following three functions that return a
+ QString provides the following functions that return a
\c{const char *} version of the string as QByteArray: toUtf8(),
toLatin1(), and toLocal8Bit().
@@ -1622,26 +1957,21 @@ inline char qToLower(char ch)
Latin-1, but there is always the risk that an implicit conversion
from or to \c{const char *} is done using the wrong 8-bit
encoding. To minimize these risks, you can turn off these implicit
- conversions by defining the following two preprocessor symbols:
+ conversions by defining some of the following preprocessor symbols:
\list
- \li \c QT_NO_CAST_FROM_ASCII disables automatic conversions from
+ \li \l QT_NO_CAST_FROM_ASCII disables automatic conversions from
C string literals and pointers to Unicode.
- \li \c QT_RESTRICTED_CAST_FROM_ASCII allows automatic conversions
- from C characters and character arrays, but disables automatic
+ \li \l QT_RESTRICTED_CAST_FROM_ASCII allows automatic conversions
+ from C characters and character arrays but disables automatic
conversions from character pointers to Unicode.
- \li \c QT_NO_CAST_TO_ASCII disables automatic conversion from QString
+ \li \l QT_NO_CAST_TO_ASCII disables automatic conversion from QString
to C strings.
\endlist
- One way to define these preprocessor symbols globally for your
- application is to add the following entry to your \l {Creating Project Files}{qmake project file}:
-
- \snippet code/src_corelib_text_qstring.cpp 0
-
You then need to explicitly call fromUtf8(), fromLatin1(),
or fromLocal8Bit() to construct a QString from an
- 8-bit string, or use the lightweight QLatin1String class, for
+ 8-bit string, or use the lightweight QLatin1StringView class. For
example:
\snippet code/src_corelib_text_qstring.cpp 1
@@ -1662,7 +1992,7 @@ inline char qToLower(char ch)
\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
@@ -1670,12 +2000,12 @@ inline char qToLower(char ch)
\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
- (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:
@@ -1683,43 +2013,46 @@ inline char qToLower(char ch)
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 Argument Formats
+ \section1 Number formats
- In member functions where an argument \e format can be specified
- (e.g., arg(), number()), the argument \e format can be one of the
- following:
+ When a QString::arg() \c{'%'} format specifier includes the \c{'L'} locale
+ qualifier, and the base is ten (its default), the default locale is
+ used. This can be set using \l{QLocale::setDefault()}. For more refined
+ control of localized string representations of numbers, see
+ QLocale::toString(). All other number formatting done by QString follows the
+ C locale's representation of numbers.
- \table
- \header \li Format \li Meaning
- \row \li \c e \li format as [-]9.9e[+|-]999
- \row \li \c E \li format as [-]9.9E[+|-]999
- \row \li \c f \li format as [-]9.9
- \row \li \c g \li use \c e or \c f format, whichever is the most concise
- \row \li \c G \li use \c E or \c f format, whichever is the most concise
- \endtable
+ When QString::arg() applies left-padding to numbers, the fill character
+ \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.
- A \e precision is also specified with the argument \e format. For
- the 'e', 'E', and 'f' formats, the \e precision represents the
- number of digits \e after the decimal point. For the 'g' and 'G'
- formats, the \e precision represents the maximum number of
- significant digits (trailing zeroes are omitted).
+ \section2 Floating-point formats
- \section1 More Efficient String Construction
+ 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)}.
- 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.
+ If the selected \e format includes an exponent, localized forms follow the
+ locale's convention on digits in the exponent. For non-localized formatting,
+ the exponent shows its sign and includes at least two digits, left-padding
+ with zero if needed.
- A slightly less efficient way is to use QLatin1String. 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.
+ \section1 More efficient string construction
+
+ 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
@@ -1728,16 +2061,15 @@ inline char qToLower(char ch)
\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
@@ -1753,61 +2085,59 @@ inline char qToLower(char ch)
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:
-
- \snippet qstring/stringbuilder.cpp 3
-
- and the \c{'+'} will automatically be performed as the
- \c{QStringBuilder} \c{'%'} everywhere.
-
- \section1 Maximum size and out-of-memory conditions
+ 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{'%'}.
- The current version of QString is limited to just under 2 GB (2^31 bytes)
- in size. The exact value is architecture-dependent, since it depends on the
- overhead required for managing the data block, but is no more than 32
- bytes. Raw data blocks are also limited by the use of \c int type in the
- current version to 2 GB minus 1 byte. Since QString uses two bytes per
- character, that translates to just under 2^30 characters in one QString.
+ \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:
- In case memory allocation fails, QString will throw a \c std::bad_alloc
- exception. Out of memory conditions in the Qt containers are the only case
- where Qt will throw exceptions.
+ \snippet qstring/stringbuilder.cpp 6
- 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.
+ 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:
- \sa fromRawData(), QChar, QLatin1String, QByteArray, QStringRef
-*/
+ \snippet qstring/stringbuilder.cpp 7
-/*!
- \enum QString::SplitBehavior
+ \section1 Maximum size and out-of-memory conditions
- \obsolete
- Use Qt::SplitBehavior instead.
+ 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 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.
- This enum specifies how the split() function should behave with
- respect to empty strings.
+ 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 cases where Qt
+ will throw exceptions. If exceptions are disabled, then running out of
+ memory is undefined behavior.
- \value KeepEmptyParts If a field is empty, keep it in the result.
- \value SkipEmptyParts If a field is empty, don't include it in the result.
+ \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 split()
+ \sa fromRawData(), QChar, QStringView, QLatin1StringView, QByteArray
*/
/*! \typedef QString::ConstIterator
@@ -1866,7 +2196,7 @@ inline char qToLower(char ch)
/*!
\typedef QString::pointer
- The QString::const_pointer typedef provides an STL-style
+ The QString::pointer typedef provides an STL-style
pointer to a QString element (QChar).
*/
@@ -1876,8 +2206,13 @@ inline char qToLower(char ch)
/*! \fn QString::iterator QString::begin()
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in
- the string.
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the
+ first character in the string.
+
+//! [iterator-invalidation-func-desc]
+ \warning The returned iterator is invalidated on detachment or when the
+ QString is modified.
+//! [iterator-invalidation-func-desc]
\sa constBegin(), end()
*/
@@ -1890,24 +2225,30 @@ inline char qToLower(char ch)
/*! \fn QString::const_iterator QString::cbegin() const
\since 5.0
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character
- in the string.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
+ first character in the string.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa begin(), cend()
*/
/*! \fn QString::const_iterator QString::constBegin() const
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character
- in the string.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the
+ first character in the string.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa begin(), constEnd()
*/
/*! \fn QString::iterator QString::end()
- Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character
- after the last character in the string.
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing just after
+ the last character in the string.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa begin(), constEnd()
*/
@@ -1920,16 +2261,20 @@ inline char qToLower(char ch)
/*! \fn QString::const_iterator QString::cend() const
\since 5.0
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- character after the last character in the list.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
+ after the last character in the string.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa cbegin(), end()
*/
/*! \fn QString::const_iterator QString::constEnd() const
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- character after the last character in the list.
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing just
+ after the last character in the string.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa constBegin(), end()
*/
@@ -1937,8 +2282,10 @@ inline char qToLower(char ch)
/*! \fn QString::reverse_iterator QString::rbegin()
\since 5.6
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- character in the string, in reverse order.
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to
+ the first character in the string, in reverse order.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa begin(), crbegin(), rend()
*/
@@ -1951,8 +2298,10 @@ inline char qToLower(char ch)
/*! \fn QString::const_reverse_iterator QString::crbegin() const
\since 5.6
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- character in the string, in reverse order.
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator
+ pointing to the first character in the string, in reverse order.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa begin(), rbegin(), rend()
*/
@@ -1960,8 +2309,10 @@ inline char qToLower(char ch)
/*! \fn QString::reverse_iterator QString::rend()
\since 5.6
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last character in the string, in reverse order.
+ Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing just
+ after the last character in the string, in reverse order.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa end(), crend(), rbegin()
*/
@@ -1974,8 +2325,10 @@ inline char qToLower(char ch)
/*! \fn QString::const_reverse_iterator QString::crend() const
\since 5.6
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to one
- past the last character in the string, in reverse order.
+ Returns a const \l{STL-style iterators}{STL-style} reverse iterator
+ pointing just after the last character in the string, in reverse order.
+
+ \include qstring.cpp iterator-invalidation-func-desc
\sa end(), rend(), rbegin()
*/
@@ -1983,9 +2336,9 @@ inline char qToLower(char ch)
/*!
\fn QString::QString()
- Constructs a null string. Null strings are also empty.
+ Constructs a null string. Null strings are also considered empty.
- \sa isEmpty()
+ \sa isEmpty(), isNull(), {Distinction Between Null and Empty Strings}
*/
/*!
@@ -2003,24 +2356,40 @@ inline char qToLower(char ch)
given const char pointer is converted to Unicode using the
fromUtf8() function.
- You can disable this constructor by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ You can disable this constructor 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.
- \note Defining \c QT_RESTRICTED_CAST_FROM_ASCII also disables
+ \note Defining \l QT_RESTRICTED_CAST_FROM_ASCII also disables
this constructor, but enables a \c{QString(const char (&ch)[N])}
constructor instead. Using non-literal input, or input with
embedded NUL characters, or non-7-bit characters is undefined
in this case.
- \sa fromLatin1(), fromLocal8Bit(), fromUtf8(), QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII
+ \sa fromLatin1(), fromLocal8Bit(), fromUtf8()
+*/
+
+/*! \fn QString::QString(const char8_t *str)
+
+ Constructs a string initialized with the UTF-8 string \a str. The
+ given const char8_t pointer is converted to Unicode using the
+ fromUtf8() function.
+
+ \since 6.1
+ \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()
*/
@@ -2032,37 +2401,40 @@ inline char qToLower(char ch)
windows) and ucs4 if the size of wchar_t is 4 bytes (most Unix
systems).
- \sa fromUtf16(), fromLatin1(), fromLocal8Bit(), fromUtf8(), fromUcs4(), fromStdU16String(), fromStdU32String()
+ \sa fromUtf16(), fromLatin1(), fromLocal8Bit(), fromUtf8(), fromUcs4(),
+ fromStdU16String(), fromStdU32String()
*/
-/*! \fn QString QString::fromWCharArray(const wchar_t *string, int size)
+/*! \fn QString QString::fromWCharArray(const wchar_t *string, qsizetype size)
\since 4.2
Returns a copy of the \a string, where the encoding of \a string depends on
- the size of wchar. If wchar is 4 bytes, the \a string is interpreted as UCS-4,
- if wchar is 2 bytes it is interpreted as UTF-16.
+ the size of wchar. If wchar is 4 bytes, the \a string is interpreted as
+ UCS-4, if wchar is 2 bytes it is interpreted as UTF-16.
- If \a size is -1 (default), the \a string has to be \\0'-terminated.
+ If \a size is -1 (default), the \a string must be '\\0'-terminated.
- \sa fromUtf16(), fromLatin1(), fromLocal8Bit(), fromUtf8(), fromUcs4(), fromStdWString()
+ \sa fromUtf16(), fromLatin1(), fromLocal8Bit(), fromUtf8(), fromUcs4(),
+ fromStdWString()
*/
/*! \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
that accepts a std::wstring object.
- \sa utf16(), toLatin1(), toUtf8(), toLocal8Bit(), toStdU16String(), toStdU32String()
+ \sa utf16(), toLatin1(), toUtf8(), toLocal8Bit(), toStdU16String(),
+ toStdU32String()
*/
-int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
+qsizetype QString::toUcs4_helper(const char16_t *uc, qsizetype length, char32_t *out)
{
- int count = 0;
+ qsizetype count = 0;
QStringIterator i(QStringView(uc, length));
while (i.hasNext())
@@ -2071,7 +2443,7 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
return count;
}
-/*! \fn int QString::toWCharArray(wchar_t *array) const
+/*! \fn qsizetype QString::toWCharArray(wchar_t *array) const
\since 4.2
Fills the \a array with the data contained in this QString object.
@@ -2087,7 +2459,8 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
\note This function does not append a null character to the array.
- \sa utf16(), toUcs4(), toLatin1(), toUtf8(), toLocal8Bit(), toStdWString(), QStringView::toWCharArray()
+ \sa utf16(), toUcs4(), toLatin1(), toUtf8(), toLocal8Bit(), toStdWString(),
+ QStringView::toWCharArray()
*/
/*! \fn QString::QString(const QString &other)
@@ -2117,20 +2490,18 @@ int QString::toUcs4_helper(const ushort *uc, int length, uint *out)
\sa fromRawData()
*/
-QString::QString(const QChar *unicode, int size)
+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(Data::allocate(0), 0);
+ d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size + 1), size);
+ d = DataPointer(size, size);
+ Q_CHECK_PTR(d.data());
memcpy(d.data(), unicode, size * sizeof(QChar));
d.data()[size] = '\0';
}
@@ -2143,36 +2514,41 @@ QString::QString(const QChar *unicode, int size)
\sa fill()
*/
-QString::QString(int size, QChar ch)
+QString::QString(qsizetype size, QChar ch)
{
if (size <= 0) {
- d = DataPointer(Data::allocate(0), 0);
+ d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size + 1), 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);
}
}
-/*! \fn QString::QString(int size, Qt::Initialization)
+/*! \fn QString::QString(qsizetype size, Qt::Initialization)
\internal
Constructs a string of the given \a size without initializing the
characters. This is only used in \c QStringBuilder::toString().
*/
-QString::QString(int size, Qt::Initialization)
+QString::QString(qsizetype size, Qt::Initialization)
{
- d = DataPointer(Data::allocate(size + 1), size);
- d.data()[size] = '\0';
+ if (size <= 0) {
+ d = DataPointer::fromRawData(&_empty, 0);
+ } else {
+ d = DataPointer(size, size);
+ Q_CHECK_PTR(d.data());
+ d.data()[size] = '\0';
+ }
}
-/*! \fn QString::QString(QLatin1String str)
+/*! \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()
*/
@@ -2182,7 +2558,8 @@ QString::QString(int size, Qt::Initialization)
*/
QString::QString(QChar ch)
{
- d = DataPointer(Data::allocate(2), 1);
+ d = DataPointer(1, 1);
+ Q_CHECK_PTR(d.data());
d.data()[0] = ch.unicode();
d.data()[1] = '\0';
}
@@ -2190,16 +2567,18 @@ QString::QString(QChar ch)
/*! \fn QString::QString(const QByteArray &ba)
Constructs a string initialized with the byte array \a ba. The
- given byte array is converted to Unicode using fromUtf8(). Stops
- copying at the first 0 character, otherwise copies the entire byte
- array.
+ given byte array is converted to Unicode using fromUtf8().
- You can disable this constructor by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ You can disable this constructor 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 fromLatin1(), fromLocal8Bit(), fromUtf8(), QT_NO_CAST_FROM_ASCII
+ \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.
+
+ \sa fromLatin1(), fromLocal8Bit(), fromUtf8()
*/
/*! \fn QString::QString(const Null &)
@@ -2243,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.
@@ -2250,15 +2641,18 @@ QString::QString(QChar ch)
extended to make it \a size characters long with the extra
characters added to the end. The new characters are uninitialized.
- If \a size is less than the current size, characters are removed
- from the end.
+ If \a size is less than the current size, characters beyond position
+ \a size are excluded from the string.
+
+ \note While resize() will grow the capacity if needed, it never shrinks
+ capacity. To shed excess capacity, use squeeze().
Example:
\snippet qstring/main.cpp 45
If you want to append a certain number of identical characters to
- the string, use the \l {QString::}{resize(int, QChar)} overload.
+ the string, use the \l {QString::}{resize(qsizetype, QChar)} overload.
If you want to expand the string so that it reaches a certain
width and fill the new positions with a particular character, use
@@ -2268,41 +2662,59 @@ QString::QString(QChar ch)
\snippet qstring/main.cpp 47
- \sa truncate(), reserve()
+ \sa truncate(), reserve(), squeeze()
*/
-void QString::resize(int size)
+void QString::resize(qsizetype size)
{
if (size < 0)
size = 0;
- if (d->needsDetach() || size > capacity())
- reallocData(uint(size) + 1u, true);
+ 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';
}
/*!
\overload
\since 5.7
- Unlike \l {QString::}{resize(int)}, this overload
+ Unlike \l {QString::}{resize(qsizetype)}, this overload
initializes the new characters to \a fillChar:
\snippet qstring/main.cpp 46
*/
-void QString::resize(int size, QChar fillChar)
+void QString::resize(qsizetype newSize, QChar fillChar)
{
- const int oldSize = length();
- resize(size);
- const int 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());
}
-/*! \fn int QString::capacity() const
+
+/*!
+ \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
the string without forcing a reallocation.
@@ -2315,22 +2727,37 @@ void QString::resize(int size, QChar fillChar)
\note a statically allocated string will report a capacity of 0,
even if it's not empty.
+ \note The free space position in the allocated memory block is undefined. In
+ other words, one should not assume that the free memory is always located
+ after the initialized elements.
+
\sa reserve(), squeeze()
*/
/*!
- \fn void QString::reserve(int size)
+ \fn void QString::reserve(qsizetype size)
- Attempts to allocate memory for at least \a size characters. If
- you know in advance how large the string will be, you can call
- this function, and if you resize the string often you are likely
- to get better performance. If \a size is an underestimate, the
- worst that will happen is that the QString will be a bit slower.
+ Ensures the string has space for at least \a size characters.
- The sole purpose of this function is to provide a means of fine
- tuning QString's memory usage. In general, you will rarely ever
- need to call this function. If you want to change the size of the
- string, call resize().
+ 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 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.
+
+ \warning reserve() reserves memory but does not change the size of the
+ string. Accessing data beyond the end of the string is undefined behavior.
+ If you need to access memory beyond the current end of the string,
+ use resize().
This function is useful for code that needs to build up a long
string and wants to avoid repeated reallocation. In this example,
@@ -2340,7 +2767,7 @@ void QString::resize(int size, QChar fillChar)
\snippet qstring/main.cpp 44
- \sa squeeze(), capacity()
+ \sa squeeze(), capacity(), resize()
*/
/*!
@@ -2355,28 +2782,44 @@ void QString::resize(int size, QChar fillChar)
\sa reserve(), capacity()
*/
-void QString::reallocData(uint alloc, bool grow)
+void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
{
- auto allocOptions = d->detachFlags();
- if (grow)
- allocOptions |= QArrayData::GrowsForward;
+ if (!alloc) {
+ d = DataPointer::fromRawData(&_empty, 0);
+ return;
+ }
- if (d->needsDetach()) {
- DataPointer dd(Data::allocate(alloc, allocOptions), qMin(int(alloc) - 1, d.size));
- ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
+ // don't use reallocate path when reducing capacity and there's free space
+ // at the beginning: might shift data pointer outside of allocated space
+ const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
+
+ if (d->needsDetach() || cannotUseReallocate) {
+ 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));
dd.data()[dd.size] = 0;
d = dd;
} else {
- d->reallocate(alloc, allocOptions);
+ d->reallocate(alloc, option);
}
}
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-void QString::expand(int i)
+void QString::reallocGrowData(qsizetype n)
{
- resize(qMax(i + 1, size()), QLatin1Char(' '));
+ if (!n) // expected to always allocate
+ n = 1;
+
+ if (d->needsDetach()) {
+ DataPointer dd(DataPointer::allocateGrow(d, n, QArrayData::GrowsAtEnd));
+ Q_CHECK_PTR(dd.data());
+ dd->copyAppend(d.data(), d.data() + d.size);
+ dd.data()[dd.size] = 0;
+ d = dd;
+ } else {
+ d->reallocate(d.constAllocatedCapacity() + n, QArrayData::Grow);
+ }
}
-#endif
/*! \fn void QString::clear()
@@ -2405,15 +2848,16 @@ QString &QString::operator=(const QString &other) noexcept
\since 5.2
*/
-/*! \fn QString &QString::operator=(QLatin1String str)
+/*! \fn QString &QString::operator=(QLatin1StringView str)
\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=(QLatin1String other)
+QString &QString::operator=(QLatin1StringView other)
{
- if (isDetached() && other.size() <= capacity()) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
+ const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
+ if (isDetached() && other.size() <= capacityAtEnd) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
d.size = other.size();
d.data()[other.size()] = 0;
qt_from_latin1(d.data(), other.latin1(), other.size());
@@ -2428,15 +2872,12 @@ QString &QString::operator=(QLatin1String other)
\overload operator=()
Assigns \a ba to this string. The byte array is converted to Unicode
- using the fromUtf8() function. This function stops conversion at the
- first NUL character found, or the end of the \a ba byte array.
+ using the fromUtf8() function.
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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 QT_NO_CAST_FROM_ASCII
*/
/*! \fn QString &QString::operator=(const char *str)
@@ -2446,12 +2887,10 @@ QString &QString::operator=(QLatin1String other)
Assigns \a str to this string. The const char pointer is converted
to Unicode using the fromUtf8() function.
- You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII
- or \c QT_RESTRICTED_CAST_FROM_ASCII when you compile your applications.
+ You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
+ or \l QT_RESTRICTED_CAST_FROM_ASCII when you compile your applications.
This can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII
*/
/*!
@@ -2461,19 +2900,11 @@ QString &QString::operator=(QLatin1String other)
*/
QString &QString::operator=(QChar ch)
{
- if (isDetached() && capacity() >= 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);
}
/*!
- \fn QString& QString::insert(int position, const QString &str)
+ \fn QString& QString::insert(qsizetype position, const QString &str)
Inserts the string \a str at the given index \a position and
returns a reference to this string.
@@ -2482,144 +2913,227 @@ QString &QString::operator=(QChar ch)
\snippet qstring/main.cpp 26
- If the given \a position is greater than size(), the array is
- first extended using resize().
+//! [string-grow-at-insertion]
+ This string grows to accommodate the insertion. If \a position is beyond
+ the end of the string, space characters are appended to the string to reach
+ this \a position, followed by \a str.
+//! [string-grow-at-insertion]
\sa append(), prepend(), replace(), remove()
*/
-
/*!
- \fn QString& QString::insert(int position, const QStringRef &str)
- \since 5.5
- \overload insert()
-
- Inserts the string reference \a str at the given index \a position and
- returns a reference to this string.
-
- If the given \a position is greater than size(), the array is
- first extended using resize().
-*/
-
-
-/*!
- \fn QString& QString::insert(int position, QStringView str)
+ \fn QString& QString::insert(qsizetype position, QStringView str)
\since 6.0
\overload insert()
Inserts the string view \a str at the given index \a position and
returns a reference to this string.
- If the given \a position is greater than size(), the array is
- first extended using resize().
+ \include qstring.cpp string-grow-at-insertion
*/
/*!
- \fn QString& QString::insert(int position, const char *str)
+ \fn QString& QString::insert(qsizetype position, const char *str)
\since 5.5
\overload insert()
Inserts the C string \a str at the given index \a position and
returns a reference to this string.
- If the given \a position is greater than size(), the array is
- first extended using resize().
+ \include qstring.cpp string-grow-at-insertion
- This function is not available when \c QT_NO_CAST_FROM_ASCII is
+ This function is not available when \l QT_NO_CAST_FROM_ASCII is
defined.
-
- \sa QT_NO_CAST_FROM_ASCII
*/
-
/*!
- \fn QString& QString::insert(int position, const QByteArray &str)
+ \fn QString& QString::insert(qsizetype position, const QByteArray &str)
\since 5.5
\overload insert()
- Inserts the byte array \a str at the given index \a position and
- returns a reference to this string.
+ Interprets the contents of \a str as UTF-8, inserts the Unicode string
+ it encodes at the given index \a position and returns a reference to
+ this string.
- If the given \a position is greater than size(), the array is
- first extended using resize().
+ \include qstring.cpp string-grow-at-insertion
- This function is not available when \c QT_NO_CAST_FROM_ASCII is
+ This function is not available when \l QT_NO_CAST_FROM_ASCII is
defined.
+*/
- \sa QT_NO_CAST_FROM_ASCII
+/*! \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(int position, QLatin1String str)
+ \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
*/
-QString &QString::insert(int i, QLatin1String str)
+QString &QString::insert(qsizetype i, QLatin1StringView str)
{
const char *s = str.latin1();
if (i < 0 || !s || !(*s))
return *this;
- int len = str.size();
- if (Q_UNLIKELY(i > size()))
- resize(i + len, QLatin1Char(' '));
- else
- resize(size() + len);
+ 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 > 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, uint(len));
return *this;
}
/*!
- \fn QString& QString::insert(int position, const QChar *unicode, int size)
+ \fn QString& QString::insert(qsizetype position, const QChar *unicode, qsizetype size)
\overload insert()
Inserts the first \a size characters of the QChar array \a unicode
at the given index \a position in the string.
+
+ This string grows to accommodate the insertion. If \a position is beyond
+ the end of the string, space characters are appended to the string to reach
+ this \a position, followed by \a size characters of the QChar array
+ \a unicode.
*/
-QString& QString::insert(int i, const QChar *unicode, int size)
+QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size)
{
if (i < 0 || size <= 0)
return *this;
- const auto s = reinterpret_cast<const char16_t *>(unicode);
- if (points_into_range(s, d.data(), d.data() + d.size))
- return insert(i, QStringView{QVarLengthArray(s, s + size)});
-
- if (Q_UNLIKELY(i > int(d.size)))
- resize(i + size, QLatin1Char(' '));
- else
- resize(d.size + size);
+ // 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));
+ }
- ::memmove(d.data() + i + size, d.data() + i, (d.size - i - size) * sizeof(QChar));
- memcpy(d.data() + i, s, size * sizeof(QChar));
return *this;
}
/*!
- \fn QString& QString::insert(int position, QChar ch)
+ \fn QString& QString::insert(qsizetype position, QChar ch)
\overload insert()
Inserts \a ch at the given index \a position in the string.
+
+ This string grows to accommodate the insertion. If \a position is beyond
+ the end of the string, space characters are appended to the string to reach
+ this \a position, followed by \a ch.
*/
-QString& QString::insert(int i, QChar ch)
+QString& QString::insert(qsizetype i, QChar ch)
{
if (i < 0)
i += d.size;
- if (i < 0)
- return *this;
- if (Q_UNLIKELY(i > size()))
- resize(i + 1, QLatin1Char(' '));
- else
- resize(d.size + 1);
- ::memmove(d.data() + i + 1, d.data() + i, (d.size - i - 1) * sizeof(QChar));
- d.data()[i] = ch.unicode();
- return *this;
+ return insert(i, &ch, 1);
}
/*!
@@ -2644,32 +3158,39 @@ QString &QString::append(const QString &str)
{
if (!str.isNull()) {
if (isNull()) {
- operator=(str);
- } else {
- if (d->needsDetach() || size() + str.size() > capacity())
- reallocData(uint(size() + str.size()) + 1u, true);
- memcpy(d.data() + d.size, str.d.data(), str.d.size * sizeof(QChar));
- d.size += str.d.size;
- d.data()[d.size] = '\0';
+ 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());
}
}
return *this;
}
/*!
+ \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
Appends \a len characters from the QChar array \a str to this string.
*/
-QString &QString::append(const QChar *str, int len)
+QString &QString::append(const QChar *str, qsizetype len)
{
if (str && len > 0) {
- if (d->needsDetach() || size() + len > capacity())
- reallocData(uint(size() + len) + 1u, true);
- memcpy(d.data() + d.size, str, len * sizeof(QChar));
- d.size += len;
- d.data()[d.size] = '\0';
+ static_assert(sizeof(QChar) == sizeof(char16_t), "Unexpected difference in sizes");
+ // the following should be safe as QChar uses char16_t as underlying data
+ const char16_t *char16String = reinterpret_cast<const char16_t *>(str);
+ d->growAppend(char16String, char16String + len);
+ d.data()[d.size] = u'\0';
}
return *this;
}
@@ -2677,20 +3198,23 @@ QString &QString::append(const QChar *str, int 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(QLatin1String str)
+QString &QString::append(QLatin1StringView str)
{
- const char *s = str.latin1();
- if (s) {
- int len = str.size();
- if (d->needsDetach() || size() + len > capacity())
- reallocData(uint(size() + len) + 1u, true);
- char16_t *i = d.data() + d.size;
- qt_from_latin1(i, s, uint(len));
- i[len] = '\0';
- d.size += len;
- }
+ 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;
}
@@ -2701,12 +3225,10 @@ QString &QString::append(QLatin1String str)
Appends the byte array \a ba to this string. The given byte array
is converted to Unicode using the fromUtf8() function.
- You can disable this function by defining \c QT_NO_CAST_FROM_ASCII
+ You can disable this function 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 QT_NO_CAST_FROM_ASCII
*/
/*! \fn QString &QString::append(const char *str)
@@ -2716,12 +3238,10 @@ QString &QString::append(QLatin1String str)
Appends the string \a str to this string. The given const char
pointer is converted to Unicode using the fromUtf8() function.
- You can disable this function by defining \c QT_NO_CAST_FROM_ASCII
+ You can disable this function 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 QT_NO_CAST_FROM_ASCII
*/
/*!
@@ -2731,9 +3251,8 @@ QString &QString::append(QLatin1String str)
*/
QString &QString::append(QChar ch)
{
- if (d->needsDetach() || size() + 1 > capacity())
- reallocData(uint(d.size) + 2u, true);
- d.data()[d.size++] = ch.unicode();
+ d.detachAndGrow(QArrayData::GrowsAtEnd, 1, nullptr, nullptr);
+ d->copyAppend(1, ch.unicode());
d.data()[d.size] = '\0';
return *this;
}
@@ -2743,6 +3262,10 @@ QString &QString::append(QChar ch)
Prepends the string \a str to the beginning of this string and
returns a reference to this string.
+ This operation is typically very fast (\l{constant time}), because
+ QString preallocates extra space at the beginning of the string data,
+ so it can grow without reallocating the entire string each time.
+
Example:
\snippet qstring/main.cpp 36
@@ -2750,26 +3273,25 @@ QString &QString::append(QChar ch)
\sa append(), insert()
*/
-/*! \fn QString &QString::prepend(QLatin1String str)
+/*! \fn QString &QString::prepend(QLatin1StringView str)
\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(const QChar *str, int len)
- \since 5.5
+/*! \fn QString &QString::prepend(QUtf8StringView str)
+ \since 6.5
\overload prepend()
- Prepends \a len characters from the QChar array \a str to this string and
- returns a reference to this string.
+ Prepends the UTF-8 string view \a str to this string.
*/
-/*! \fn QString &QString::prepend(const QStringRef &str)
+/*! \fn QString &QString::prepend(const QChar *str, qsizetype len)
\since 5.5
\overload prepend()
- Prepends the string reference \a str to the beginning of this string and
+ Prepends \a len characters from the QChar array \a str to this string and
returns a reference to this string.
*/
@@ -2788,12 +3310,10 @@ QString &QString::append(QChar ch)
Prepends the byte array \a ba to this string. The byte array is
converted to Unicode using the fromUtf8() function.
- You can disable this function by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ You can disable this function 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 QT_NO_CAST_FROM_ASCII
*/
/*! \fn QString &QString::prepend(const char *str)
@@ -2803,12 +3323,10 @@ QString &QString::append(QChar ch)
Prepends the string \a str to this string. The const char pointer
is converted to Unicode using the fromUtf8() function.
- You can disable this function by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ You can disable this function 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 QT_NO_CAST_FROM_ASCII
*/
/*! \fn QString &QString::prepend(QChar ch)
@@ -2819,7 +3337,112 @@ QString &QString::append(QChar ch)
*/
/*!
- \fn QString &QString::remove(int position, int n)
+ \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
position index, and returns a reference to the string.
@@ -2828,23 +3451,42 @@ 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]
+ Element removal will preserve the string's capacity and not reduce the
+ amount of allocated memory. To shed extra capacity and free as much memory
+ as possible, call squeeze() after the last change to the string's size.
+//! [shrinking-erase]
+
\sa insert(), replace()
*/
-QString &QString::remove(int pos, int len)
+QString &QString::remove(qsizetype pos, qsizetype len)
{
if (pos < 0) // count from end of string
pos += size();
- if (uint(pos) >= uint(size())) {
- // range problems
- } else if (len >= size() - pos) {
- resize(pos); // truncate
- } else if (len > 0) {
- detach();
- memmove(d.data() + pos, d.data() + pos + len,
- (d.size - pos - len + 1) * sizeof(QChar));
- d.size -= len;
+
+ 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;
}
@@ -2857,42 +3499,55 @@ static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs
return;
// avoid detach if nothing to do:
- int i = s.indexOf(needle, 0, cs);
+ qsizetype i = s.indexOf(needle, 0, 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).
+ \include qstring.cpp shrinking-erase
+
\sa replace()
*/
QString &QString::remove(const QString &str, Qt::CaseSensitivity cs)
{
const auto s = str.d.data();
- if (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);
@@ -2903,28 +3558,61 @@ 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).
+ \include qstring.cpp shrinking-erase
+
\sa replace()
*/
-QString &QString::remove(QLatin1String str, Qt::CaseSensitivity cs)
+QString &QString::remove(QLatin1StringView str, Qt::CaseSensitivity cs)
{
removeStringImpl(*this, str, cs);
return *this;
}
/*!
+ \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:
@@ -2932,24 +3620,41 @@ QString &QString::remove(QLatin1String str, Qt::CaseSensitivity cs)
This is the same as \c replace(ch, "", cs).
+ \include qstring.cpp shrinking-erase
+
\sa replace()
*/
QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
{
- const int 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);
+ const qsizetype idx = indexOf(ch, 0, cs);
+ 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;
}
@@ -2963,11 +3668,114 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
\snippet qstring/main.cpp 96
+ \include qstring.cpp shrinking-erase
+
\sa indexOf(), lastIndexOf(), replace()
*/
/*!
- \fn QString &QString::replace(int position, int n, const QString &after)
+ \fn template <typename Predicate> QString &QString::removeIf(Predicate pred)
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the string. Returns a reference to the string.
+
+ \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)
Replaces \a n characters beginning at index \a position with
the string \a after and returns a reference to this string.
@@ -2982,38 +3790,38 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
\sa insert(), remove()
*/
-QString &QString::replace(int pos, int len, const QString &after)
+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(int position, int n, const QChar *unicode, int 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(int pos, int len, const QChar *unicode, int size)
+QString &QString::replace(qsizetype pos, qsizetype len, const QChar *after, qsizetype alen)
{
- if (uint(pos) > uint(this->size()))
+ if (size_t(pos) > size_t(this->size()))
return *this;
if (len > this->size() - pos)
len = this->size() - pos;
- uint index = pos;
- replace_helper(&index, 1, len, unicode, size);
+ size_t index = pos;
+ replace_helper(*this, QSpan(&index, 1), len, QStringView{after, alen});
return *this;
}
/*!
- \fn QString &QString::replace(int position, int n, QChar after)
+ \fn QString &QString::replace(qsizetype position, qsizetype n, QChar after)
\overload replace()
Replaces \a n characters beginning at index \a position with the
character \a after and returns a reference to this string.
*/
-QString &QString::replace(int pos, int len, QChar after)
+QString &QString::replace(qsizetype pos, qsizetype len, QChar after)
{
return replace(pos, len, &after, 1);
}
@@ -3023,8 +3831,7 @@ QString &QString::replace(int pos, int 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:
@@ -3041,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, int 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(uint *indices, int nIndices, int blen, const QChar *after, int 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 (int i = 0; i < nIndices; ++i)
- memcpy(d.data() + indices[i], after, alen * sizeof(QChar));
- } else if (alen < blen) {
- // replace from front
- detach();
- uint to = indices[0];
- if (alen)
- memcpy(d.data()+to, after, alen*sizeof(QChar));
- to += alen;
- uint movestart = indices[0] + blen;
- for (int i = 1; i < nIndices; ++i) {
- int 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;
- }
- int 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
- int adjust = nIndices*(alen-blen);
- int newLen = d.size + adjust;
- int moveend = d.size;
- resize(newLen);
-
- while (nIndices) {
- --nIndices;
- int movestart = indices[nIndices] + blen;
- int insertstart = indices[nIndices] + nIndices*(alen-blen);
- int 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()
@@ -3133,11 +3856,10 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
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, int blen,
- const QChar *after, int alen,
+QString &QString::replace(const QChar *before, qsizetype blen,
+ const QChar *after, qsizetype alen,
Qt::CaseSensitivity cs)
{
if (d.size == 0) {
@@ -3149,51 +3871,25 @@ QString &QString::replace(const QChar *before, int 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;
-
- int index = 0;
- while (1) {
- uint indices[1024];
- uint 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);
+ qsizetype index = 0;
- 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;
}
@@ -3202,8 +3898,7 @@ QString &QString::replace(const QChar *before, int 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)
{
@@ -3216,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());
- int index = 0;
- while (1) {
- uint indices[1024];
- uint 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 == -1)) // 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;
}
@@ -3253,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 int 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;
}
@@ -3289,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(QLatin1String before, QLatin1String after, Qt::CaseSensitivity cs)
+QString &QString::replace(QLatin1StringView before, QLatin1StringView after, Qt::CaseSensitivity cs)
{
- int alen = after.size();
- int 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);
}
@@ -3312,19 +4009,21 @@ QString &QString::replace(QLatin1String before, QLatin1String after, Qt::CaseSen
\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(QLatin1String before, const QString &after, Qt::CaseSensitivity cs)
+QString &QString::replace(QLatin1StringView before, const QString &after, Qt::CaseSensitivity cs)
{
- int 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);
}
@@ -3335,16 +4034,17 @@ QString &QString::replace(QLatin1String before, const QString &after, Qt::CaseSe
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, QLatin1String after, Qt::CaseSensitivity cs)
+QString &QString::replace(const QString &before, QLatin1StringView after, Qt::CaseSensitivity cs)
{
- int 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);
}
@@ -3355,444 +4055,513 @@ QString &QString::replace(const QString &before, QLatin1String after, Qt::CaseSe
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, QLatin1String after, Qt::CaseSensitivity cs)
+QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity cs)
{
- int 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);
}
-
/*!
- \relates QString
- Returns \c true if string \a s1 is equal to string \a s2; otherwise
- returns \c false.
+ \fn bool QString::operator==(const QString &lhs, const QString &rhs)
+ \overload operator==()
- The comparison is based exclusively on the numeric Unicode values of
- the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- localeAwareCompare().
-*/
-bool operator==(const QString &s1, const QString &s2) noexcept
-{
- if (s1.d.size != s2.d.size)
- return false;
+ Returns \c true if string \a lhs is equal to string \a rhs; otherwise
+ returns \c false.
- return qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
-}
+ \include qstring.cpp compare-isNull-vs-isEmpty
+
+ \sa {Comparing Strings}
+*/
/*!
+ \fn bool QString::operator==(const QString &lhs, const QLatin1StringView &rhs)
+
\overload operator==()
- Returns \c true if this string is equal to \a other; otherwise
+
+ Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false.
*/
-bool QString::operator==(QLatin1String other) const noexcept
-{
- if (size() != other.size())
- return false;
- return qt_compare_strings(*this, other, Qt::CaseSensitive) == 0;
-}
+/*!
+ \fn bool QString::operator==(const QLatin1StringView &lhs, const QString &rhs)
+
+ \overload operator==()
+
+ 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. This function stops conversion at the
- first NUL character found, or the end of the byte array.
+ The \a rhs byte array is converted to a QUtf8StringView.
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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.
-
- \sa QT_NO_CAST_FROM_ASCII
+ 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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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 QString::operator<(const QString &lhs, const QString &rhs)
- \sa QT_NO_CAST_FROM_ASCII
+ \overload operator<()
+
+ Returns \c true if string \a lhs is lexically less than string
+ \a rhs; otherwise returns \c false.
+
+ \sa {Comparing Strings}
*/
/*!
- \relates QString
- Returns \c true if string \a s1 is lexically less than string
- \a s2; otherwise returns \c false.
+ \fn bool QString::operator<(const QString &lhs, const QLatin1StringView &rhs)
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
+ \overload operator<()
+
+ Returns \c true if \a lhs is lexically less than \a rhs;
+ otherwise returns \c false.
*/
-bool operator<(const QString &s1, const QString &s2) noexcept
-{
- return qt_compare_strings(s1, s2, Qt::CaseSensitive) < 0;
-}
/*!
- \overload operator<()
+ \fn bool QString::operator<(const QLatin1StringView &lhs, const QString &rhs)
+
+ \overload operator<()
- Returns \c true if this string is lexically less than the parameter
- string called \a other; otherwise returns \c false.
+ Returns \c true if \a lhs is lexically less than \a rhs;
+ otherwise returns \c false.
*/
-bool QString::operator<(QLatin1String other) const noexcept
-{
- return qt_compare_strings(*this, other, Qt::CaseSensitive) < 0;
-}
-/*! \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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ You can disable this operator
+ \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 QT_NO_CAST_FROM_ASCII
*/
-/*! \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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \fn bool operator<=(const QString &s1, const QString &s2)
-
- \relates QString
+/*! \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.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- localeAwareCompare().
+ \sa {Comparing Strings}
*/
-/*! \fn bool QString::operator<=(QLatin1String other) const
+/*!
+ \fn bool QString::operator<=(const QString &lhs, const QLatin1StringView &rhs)
- Returns \c true if this string is lexically less than or equal to
- parameter string \a other. Otherwise returns \c false.
+ \overload operator<=()
+
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QString::operator<=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<=()
+
+ 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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \fn bool operator>(const QString &s1, const QString &s2)
- \relates QString
+/*! \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.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- localeAwareCompare().
+ \sa {Comparing Strings}
*/
/*!
- \overload operator>()
+ \fn bool QString::operator>(const QString &lhs, const QLatin1StringView &rhs)
+
+ \overload operator>()
- Returns \c true if this string is lexically greater than the parameter
- string \a other; otherwise returns \c false.
+ Returns \c true if \a lhs is lexically greater than \a rhs;
+ otherwise returns \c false.
*/
-bool QString::operator>(QLatin1String other) const noexcept
-{
- return qt_compare_strings(*this, other, Qt::CaseSensitive) > 0;
-}
-/*! \fn bool QString::operator>(const QByteArray &other) const
+/*!
+ \fn bool QString::operator>(const QLatin1StringView &lhs, const QString &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.
+ Returns \c true if \a lhs is lexically greater than \a rhs;
+ otherwise returns \c false.
+*/
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+/*! \fn bool QString::operator>(const QString &lhs, const QByteArray &rhs)
+
+ \overload operator>()
+
+ 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 to ensure that all user-visible strings
go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
*/
-/*! \fn bool QString::operator>(const char *other) const
+/*! \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 \c QT_NO_CAST_FROM_ASCII
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \fn bool operator>=(const QString &s1, const QString &s2)
- \relates QString
+/*! \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.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- localeAwareCompare().
+ \sa {Comparing Strings}
*/
-/*! \fn bool QString::operator>=(QLatin1String other) const
+/*!
+ \fn bool QString::operator>=(const QString &lhs, const QLatin1StringView &rhs)
+
+ \overload operator>=()
+
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
+ otherwise returns \c false.
+*/
- Returns \c true if this string is lexically greater than or equal to parameter
- string \a other. Otherwise returns \c false.
+/*!
+ \fn bool QString::operator>=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>=()
+
+ 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 \c QT_NO_CAST_FROM_ASCII
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \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 \c QT_NO_CAST_FROM_ASCII
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \fn bool operator!=(const QString &s1, const QString &s2)
- \relates QString
+/*! \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.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- localeAwareCompare().
+ \sa {Comparing Strings}
*/
-/*! \fn bool QString::operator!=(QLatin1String other) const
+/*! \fn bool QString::operator!=(const QString &lhs, const QLatin1StringView &rhs)
- Returns \c true if this string is not equal to parameter string \a other.
+ 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 \c QT_NO_CAST_FROM_ASCII
+ 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 QT_NO_CAST_FROM_ASCII
*/
-/*! \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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ 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 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.
- \sa QT_NO_CAST_FROM_ASCII
+ 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.
*/
-#if QT_STRINGVIEW_LEVEL < 2
/*!
- Returns the index position of the first occurrence of the string \a
- str in this string, searching forward from index position \a
- 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()
*/
-int QString::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
+qsizetype QString::indexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(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 int QString::indexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
+ \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()
*/
-int QString::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
+qsizetype QString::indexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs));
+ return QtPrivate::findString(QStringView(unicode(), size()), from, str, cs);
}
/*!
+ \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}
+*/
+
+/*!
+ \include qstring.qdocinc {qstring-last-index-of} {string} {str}
+
+ \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:
+
+ \snippet qstring/main.cpp 29
+
+ \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
+ 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(), contains(), count()
*/
-int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
+qsizetype QString::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(qFindChar(QStringView(unicode(), length()), ch, from, cs));
+ return QtPrivate::lastIndexOf(QStringView(*this), from, str, cs);
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
+ \fn qsizetype QString::lastIndexOf(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ \since 6.2
+ \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 (default), the search starts at the last
- character; if \a from is -2, at the next to last character and so
- on. Returns -1 if \a str is not found.
+ 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:
@@ -3800,74 +4569,109 @@ int QString::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
\sa indexOf(), contains(), count()
*/
-int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::lastIndexOf(QStringView(*this), from, str, cs));
-}
-#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 (default), the search starts at the last
- character; if \a from is -2, at the next to last character and so
- on. Returns -1 if \a str is not found.
+ \include qstring.qdocinc {qstring-last-index-of} {Latin-1 string viewed by} {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}
Example:
\snippet qstring/main.cpp 29
+ \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
+ 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(), contains(), count()
*/
-int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
+qsizetype QString::lastIndexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(QtPrivate::lastIndexOf(*this, from, str, cs));
+ return QtPrivate::lastIndexOf(*this, from, str, cs);
}
/*!
+ \fn qsizetype QString::lastIndexOf(QLatin1StringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ \since 6.2
\overload lastIndexOf()
- Returns the index position of the last occurrence of the character
- \a ch, searching backward from position \a from.
+ Returns the index position of the last occurrence of the string \a
+ str in this string. Returns -1 if \a str is not found.
+
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
+
+ Example:
+
+ \snippet qstring/main.cpp 29
+
+ \sa indexOf(), contains(), count()
*/
-int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(qLastIndexOf(QStringView(*this), ch, from, cs));
-}
/*!
- \fn int QString::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
+ \fn qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
+ \overload lastIndexOf()
+
+ \include qstring.qdocinc {qstring-last-index-of} {character} {ch}
+*/
+
+/*!
+ \fn QString::lastIndexOf(QChar ch, Qt::CaseSensitivity) const
+ \since 6.3
+ \overload lastIndexOf()
+*/
+
+/*!
+ \fn qsizetype QString::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
\since 5.14
\overload lastIndexOf()
- Returns the index position of the last occurrence of the string view \a
- str in this string, searching backward from index position \a
- from. If \a from is -1 (default), the search starts at the last
- character; if \a from is -2, at the next to last character and so
- on. Returns -1 if \a str is not found.
+ \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
+ 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(), contains(), count()
*/
+/*!
+ \fn qsizetype QString::lastIndexOf(QStringView str, 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 in this string. Returns -1 if \a str is not found.
+
+ \include qstring.qdocinc {search-comparison-case-sensitivity} {search}
+
+ \sa indexOf(), contains(), count()
+*/
#if QT_CONFIG(regularexpression)
struct QStringCapture
{
- int pos;
- int len;
+ qsizetype pos;
+ qsizetype len;
int no;
};
Q_DECLARE_TYPEINFO(QStringCapture, Q_PRIMITIVE_TYPE);
@@ -3893,7 +4697,7 @@ Q_DECLARE_TYPEINFO(QStringCapture, Q_PRIMITIVE_TYPE);
QString &QString::replace(const QRegularExpression &re, const QString &after)
{
if (!re.isValid()) {
- qWarning("QString::replace: invalid QRegularExpression object");
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString::replace");
return *this;
}
@@ -3902,18 +4706,18 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
if (!iterator.hasNext()) // no matches at all
return *this;
- reallocData(uint(d.size) + 1u);
+ reallocData(d.size, QArrayData::KeepSize);
- int numCaptures = re.captureCount();
+ qsizetype numCaptures = re.captureCount();
// 1. build the backreferences list, holding where the backreferences
// are in the replacement string
- QList<QStringCapture> backReferences;
- const int al = after.length();
+ QVarLengthArray<QStringCapture> backReferences;
+ const qsizetype al = after.size();
const QChar *ac = after.unicode();
- for (int i = 0; i < al - 1; i++) {
- if (ac[i] == QLatin1Char('\\')) {
+ for (qsizetype i = 0; i < al - 1; i++) {
+ if (ac[i] == u'\\') {
int no = ac[i + 1].digitValue();
if (no > 0 && no <= numCaptures) {
QStringCapture backReference;
@@ -3938,33 +4742,34 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
// - the part before the match
// - the after string, with the proper replacements for the backreferences
- int newLength = 0; // length of the new string, with all the replacements
- int lastEnd = 0;
- QList<QStringRef> chunks;
+ qsizetype newLength = 0; // length of the new string, with all the replacements
+ qsizetype lastEnd = 0;
+ QVarLengthArray<QStringView> chunks;
+ const QStringView copyView{ copy }, afterView{ after };
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
- int len;
+ qsizetype len;
// add the part before the match
len = match.capturedStart() - lastEnd;
if (len > 0) {
- chunks << copy.midRef(lastEnd, len);
+ chunks << copyView.mid(lastEnd, len);
newLength += len;
}
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) {
- chunks << after.midRef(lastEnd, len);
+ chunks << afterView.mid(lastEnd, len);
newLength += len;
}
// backreference itself
len = match.capturedLength(backReference.no);
if (len > 0) {
- chunks << copy.midRef(match.capturedStart(backReference.no), len);
+ chunks << copyView.mid(match.capturedStart(backReference.no), len);
newLength += len;
}
@@ -3972,9 +4777,9 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
}
// add the last part of the after string
- len = after.length() - lastEnd;
+ len = afterView.size() - lastEnd;
if (len > 0) {
- chunks << after.midRef(lastEnd, len);
+ chunks << afterView.mid(lastEnd, len);
newLength += len;
}
@@ -3982,18 +4787,18 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
}
// 3. trailing string after the last match
- if (copy.length() > lastEnd) {
- chunks << copy.midRef(lastEnd);
- newLength += copy.length() - lastEnd;
+ if (copyView.size() > lastEnd) {
+ chunks << copyView.mid(lastEnd);
+ newLength += copyView.size() - lastEnd;
}
// 4. assemble the chunks together
resize(newLength);
- int i = 0;
+ qsizetype i = 0;
QChar *uc = data();
- for (const QStringRef &chunk : qAsConst(chunks)) {
- int len = chunk.length();
- memcpy(uc + i, chunk.unicode(), len * sizeof(QChar));
+ for (const QStringView &chunk : std::as_const(chunks)) {
+ qsizetype len = chunk.size();
+ memcpy(uc + i, chunk.constData(), len * sizeof(QChar));
i += len;
}
@@ -4005,16 +4810,14 @@ 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()
*/
-int QString::count(const QString &str, Qt::CaseSensitivity cs) const
+qsizetype QString::count(const QString &str, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(QtPrivate::count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs));
+ return QtPrivate::count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs);
}
/*!
@@ -4022,52 +4825,45 @@ int 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()
*/
-int QString::count(QChar ch, Qt::CaseSensitivity cs) const
+qsizetype QString::count(QChar ch, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(QtPrivate::count(QStringView(unicode(), size()), ch, cs));
+ return QtPrivate::count(QStringView(unicode(), size()), ch, cs);
}
/*!
\since 6.0
\overload count()
Returns the number of (potentially overlapping) occurrences of the
- string reference \a str in this string.
+ 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()
*/
-int QString::count(QStringView str, Qt::CaseSensitivity cs) const
+qsizetype QString::count(QStringView str, Qt::CaseSensitivity cs) const
{
- // ### Qt6: qsizetype
- return int(QtPrivate::count(*this, str, cs));
+ 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(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+/*! \fn bool QString::contains(QLatin1StringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
\since 5.3
\overload contains()
@@ -4084,20 +4880,6 @@ int QString::count(QStringView str, Qt::CaseSensitivity cs) const
character \a ch; otherwise returns \c false.
*/
-#if QT_STRINGVIEW_LEVEL < 2
-/*! \fn bool QString::contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 4.8
-
- Returns \c true if this string contains an occurrence of the string
- reference \a str; otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa indexOf(), count()
-*/
-#endif // QT_STRINGVIEW_LEVEL < 2
-
/*! \fn bool QString::contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
\since 5.14
\overload contains()
@@ -4105,8 +4887,7 @@ int 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()
*/
@@ -4127,22 +4908,9 @@ int QString::count(QStringView str, Qt::CaseSensitivity cs) const
\snippet qstring/main.cpp 93
*/
-int QString::indexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const
+qsizetype QString::indexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const
{
- if (!re.isValid()) {
- qWarning("QString::indexOf: invalid QRegularExpression object");
- return -1;
- }
-
- QRegularExpressionMatch match = re.match(*this, from);
- if (match.hasMatch()) {
- const int ret = match.capturedStart();
- if (rmatch)
- *rmatch = std::move(match);
- return ret;
- }
-
- return -1;
+ return QtPrivate::indexOf(QStringView(*this), this, re, from, rmatch);
}
/*!
@@ -4150,7 +4918,11 @@ int QString::indexOf(const QRegularExpression &re, int from, QRegularExpressionM
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. 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
@@ -4159,31 +4931,44 @@ int QString::indexOf(const QRegularExpression &re, int from, QRegularExpressionM
Example:
\snippet qstring/main.cpp 94
+
+ \note Due to how the regular expression matching algorithm works,
+ this function will actually match repeatedly from the beginning of
+ the string until the position \a from is reached.
+
+ \note When searching for a regular expression \a re that may match
+ 0 characters, 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.
*/
-int QString::lastIndexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const
+qsizetype QString::lastIndexOf(const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch) const
{
- if (!re.isValid()) {
- qWarning("QString::lastIndexOf: invalid QRegularExpression object");
- return -1;
- }
+ return QtPrivate::lastIndexOf(QStringView(*this), this, re, from, rmatch);
+}
- int endpos = (from < 0) ? (size() + from + 1) : (from + 1);
- QRegularExpressionMatchIterator iterator = re.globalMatch(*this);
- int lastIndex = -1;
- while (iterator.hasNext()) {
- QRegularExpressionMatch match = iterator.next();
- int start = match.capturedStart();
- if (start < endpos) {
- lastIndex = start;
- if (rmatch)
- *rmatch = std::move(match);
- } else {
- break;
- }
- }
+/*!
+ \fn qsizetype QString::lastIndexOf(const QRegularExpression &re, QRegularExpressionMatch *rmatch = nullptr) const
+ \since 6.2
+ \overload lastIndexOf()
- return lastIndex;
-}
+ Returns the index position of the last match of the regular
+ expression \a re in the string. 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
+ pointed to by \a rmatch.
+
+ Example:
+
+ \snippet qstring/main.cpp 94
+
+ \note Due to how the regular expression matching algorithm works,
+ this function will actually match repeatedly from the beginning of
+ the string until the end of the string is reached.
+*/
/*!
\since 5.1
@@ -4200,15 +4985,7 @@ int QString::lastIndexOf(const QRegularExpression &re, int from, QRegularExpress
bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch) const
{
- if (!re.isValid()) {
- qWarning("QString::contains: invalid QRegularExpression object");
- return false;
- }
- QRegularExpressionMatch m = re.match(*this);
- bool hasMatch = m.hasMatch();
- if (hasMatch && rmatch)
- *rmatch = std::move(m);
- return hasMatch;
+ return QtPrivate::contains(QStringView(*this), this, re, rmatch);
}
/*!
@@ -4218,38 +4995,31 @@ bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *rm
Returns the number of times the regular expression \a re matches
in the string.
- This function counts overlapping matches, so in the example
- below, there are four instances of "ana" or "ama":
+ For historical reasons, this function counts overlapping matches,
+ so in the example below, there are four instances of "ana" or
+ "ama":
\snippet qstring/main.cpp 95
+
+ This behavior is different from simply iterating over the matches
+ in the string using QRegularExpressionMatchIterator.
+
+ \sa QRegularExpression::globalMatch()
*/
-int QString::count(const QRegularExpression &re) const
+qsizetype QString::count(const QRegularExpression &re) const
{
- if (!re.isValid()) {
- qWarning("QString::count: invalid QRegularExpression object");
- return 0;
- }
- int count = 0;
- int index = -1;
- int len = length();
- while (index < len - 1) {
- QRegularExpressionMatch match = re.match(*this, index + 1);
- if (!match.hasMatch())
- break;
- index = match.capturedStart();
- count++;
- }
- return count;
+ return QtPrivate::count(QStringView(*this), re);
}
#endif // QT_CONFIG(regularexpression)
-/*! \fn int QString::count() const
-
+#if QT_DEPRECATED_SINCE(6, 4)
+/*! \fn qsizetype QString::count() const
+ \deprecated [6.4] Use size() or length() instead.
\overload count()
Same as size().
*/
-
+#endif
/*!
\enum QString::SectionFlag
@@ -4279,7 +5049,7 @@ int QString::count(const QRegularExpression &re) const
*/
/*!
- \fn QString QString::section(QChar sep, int start, int end = -1, SectionFlags flags) const
+ \fn QString QString::section(QChar sep, qsizetype start, qsizetype end = -1, SectionFlags flags) const
This function returns a section of the string.
@@ -4315,19 +5085,19 @@ int QString::count(const QRegularExpression &re) const
\sa split()
*/
-QString QString::section(const QString &sep, int start, int end, SectionFlags flags) const
+QString QString::section(const QString &sep, qsizetype start, qsizetype end, SectionFlags flags) const
{
- const QList<QStringRef> sections = splitRef(
+ const QList<QStringView> sections = QStringView{ *this }.split(
sep, Qt::KeepEmptyParts, (flags & SectionCaseInsensitiveSeps) ? Qt::CaseInsensitive : Qt::CaseSensitive);
- const int sectionsSize = sections.size();
+ const qsizetype sectionsSize = sections.size();
if (!(flags & SectionSkipEmpty)) {
if (start < 0)
start += sectionsSize;
if (end < 0)
end += sectionsSize;
} else {
- int skip = 0;
- for (int k = 0; k < sectionsSize; ++k) {
+ qsizetype skip = 0;
+ for (qsizetype k = 0; k < sectionsSize; ++k) {
if (sections.at(k).isEmpty())
skip++;
}
@@ -4340,14 +5110,14 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl
return QString();
QString ret;
- int first_i = start, last_i = end;
- for (int x = 0, i = 0; x <= end && i < sectionsSize; ++i) {
- const QStringRef &section = sections.at(i);
+ qsizetype first_i = start, last_i = end;
+ for (qsizetype x = 0, i = 0; x <= end && i < sectionsSize; ++i) {
+ const QStringView &section = sections.at(i);
const bool empty = section.isEmpty();
if (x >= start) {
- if(x == start)
+ if (x == start)
first_i = i;
- if(x == end)
+ if (x == end)
last_i = i;
if (x > start && i > 0)
ret += sep;
@@ -4363,19 +5133,20 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl
return ret;
}
-#if !(defined(QT_NO_REGEXP) && !QT_CONFIG(regularexpression))
+#if QT_CONFIG(regularexpression)
class qt_section_chunk {
public:
qt_section_chunk() {}
- qt_section_chunk(int l, QStringRef s) : length(l), string(std::move(s)) {}
- int length;
- QStringRef string;
+ qt_section_chunk(qsizetype l, QStringView s) : length(l), string(std::move(s)) {}
+ qsizetype length;
+ QStringView string;
};
-Q_DECLARE_TYPEINFO(qt_section_chunk, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(qt_section_chunk, Q_RELOCATABLE_TYPE);
-static QString extractSections(const QList<qt_section_chunk> &sections, int start, int end, QString::SectionFlags flags)
+static QString extractSections(QSpan<qt_section_chunk> sections, qsizetype start, qsizetype end,
+ QString::SectionFlags flags)
{
- const int sectionsSize = sections.size();
+ const qsizetype sectionsSize = sections.size();
if (!(flags & QString::SectionSkipEmpty)) {
if (start < 0)
@@ -4383,10 +5154,10 @@ static QString extractSections(const QList<qt_section_chunk> &sections, int star
if (end < 0)
end += sectionsSize;
} else {
- int skip = 0;
- for (int k = 0; k < sectionsSize; ++k) {
- const qt_section_chunk &section = sections.at(k);
- if (section.length == section.string.length())
+ qsizetype skip = 0;
+ for (qsizetype k = 0; k < sectionsSize; ++k) {
+ const qt_section_chunk &section = sections[k];
+ if (section.length == section.string.size())
skip++;
}
if (start < 0)
@@ -4398,11 +5169,11 @@ static QString extractSections(const QList<qt_section_chunk> &sections, int star
return QString();
QString ret;
- int x = 0;
- int first_i = start, last_i = end;
- for (int i = 0; x <= end && i < sectionsSize; ++i) {
- const qt_section_chunk &section = sections.at(i);
- const bool empty = (section.length == section.string.length());
+ 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[i];
+ const bool empty = (section.length == section.string.size());
if (x >= start) {
if (x == start)
first_i = i;
@@ -4418,21 +5189,19 @@ static QString extractSections(const QList<qt_section_chunk> &sections, int star
}
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);
}
return ret;
}
-#endif
-#if QT_CONFIG(regularexpression)
/*!
\overload section()
\since 5.0
@@ -4447,10 +5216,10 @@ static QString extractSections(const QList<qt_section_chunk> &sections, int star
\sa split(), simplified()
*/
-QString QString::section(const QRegularExpression &re, int start, int end, SectionFlags flags) const
+QString QString::section(const QRegularExpression &re, qsizetype start, qsizetype end, SectionFlags flags) const
{
if (!re.isValid()) {
- qWarning("QString::section: invalid QRegularExpression object");
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString::section");
return QString();
}
@@ -4462,67 +5231,63 @@ QString QString::section(const QRegularExpression &re, int start, int end, Secti
if (flags & SectionCaseInsensitiveSeps)
sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption);
- QList<qt_section_chunk> sections;
- int 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();
m = match.capturedStart();
- sections.append(qt_section_chunk(last_len, QStringRef(this, last_m, m - last_m)));
+ sections.append(qt_section_chunk(last_len, QStringView{ *this }.sliced(last_m, m - last_m)));
last_m = m;
last_len = match.capturedLength();
}
- sections.append(qt_section_chunk(last_len, QStringRef(this, last_m, n - last_m)));
+ sections.append(qt_section_chunk(last_len, QStringView{ *this }.sliced(last_m, n - last_m)));
return extractSections(sections, start, end, flags);
}
#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.
- \obsolete Use first() instead in new code.
+ If you know that \a n cannot be out of bounds, use first() instead in new
+ code, because it is faster.
The entire string is returned if \a n is greater than or equal
to size(), or less than zero.
- \snippet qstring/main.cpp 31
-
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
-QString QString::left(int n) const
-{
- if (uint(n) >= uint(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.
- \obsolete Use last() instead in new code.
+ If you know that \a n cannot be out of bounds, use last() instead in new
+ code, because it is faster.
The entire string is returned if \a n is greater than or equal
to size(), or less than zero.
- \snippet qstring/main.cpp 48
-
- \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
+ \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QString QString::right(int n) const
-{
- if (uint(n) >= uint(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.
- \obsolete Use sliced() instead in new code.
+ If you know that \a position and \a n cannot be out of bounds, use sliced()
+ instead in new code, because it is faster.
Returns a null string if the \a position index exceeds the
length of the string. If there are less than \a n characters
@@ -4530,14 +5295,9 @@ QString QString::right(int n) const
\a n is -1 (default), the function returns all characters that
are available from the specified \a position.
- Example:
-
- \snippet qstring/main.cpp 34
-
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), sliced(), chopped(), chop(), truncate(), slice()
*/
-
-QString QString::mid(int position, int n) const
+QString QString::mid(qsizetype position, qsizetype n) const &
{
qsizetype p = position;
qsizetype l = n;
@@ -4546,22 +5306,37 @@ QString QString::mid(int position, int n) const
case QContainerImplHelper::Null:
return QString();
case QContainerImplHelper::Empty:
- {
- QPair<Data *, char16_t *> pair = Data::allocate(0);
- DataPointer empty = { pair.first, pair.second, 0 };
- return QString(empty);
- }
+ return QString(DataPointer::fromRawData(&_empty, 0));
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
- return QString(constData() + p, l);
+ return sliced(p, l);
+ }
+ 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();
+ 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
@@ -4569,22 +5344,28 @@ QString QString::mid(int position, int n) const
\note The behavior is undefined when \a n < 0 or \a n > size().
- \sa last(), sliced(), from(), startsWith(), chopped(), chop(), truncate()
+ \snippet qstring/main.cpp 31
+
+ \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.
\note The behavior is undefined when \a n < 0 or \a n > size().
- \sa first(), sliced(), from(), endsWith(), chopped(), chop(), truncate()
+ \snippet qstring/main.cpp 48
+
+ \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,
@@ -4593,23 +5374,64 @@ QString QString::mid(int position, int n) const
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
- \sa first(), last(), chopped(), chop(), truncate()
+ \snippet qstring/main.cpp 34
+
+ \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::from(qsizetype pos) const
+ \fn QString QString::sliced(qsizetype pos) const &
+ \fn QString QString::sliced(qsizetype pos) &&
\since 6.0
+ \overload
Returns a string that contains the portion of this string starting at
position \a pos and extending to its end.
\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::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::chopped(int len) const
+ \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
@@ -4617,16 +5439,14 @@ QString QString::mid(int position, int n) const
\note The behavior is undefined if \a len is negative or greater than size().
- \sa endsWith(), left(), right(), mid(), 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
@@ -4634,16 +5454,15 @@ QString QString::mid(int position, int n) const
*/
bool QString::startsWith(const QString& s, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(*this, s, cs);
+ return qt_starts_with_impl(QStringView(*this), QStringView(s), cs);
}
-#endif
/*!
\overload startsWith()
*/
-bool QString::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const
+bool QString::startsWith(QLatin1StringView s, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(*this, s, cs);
+ return qt_starts_with_impl(QStringView(*this), s, cs);
}
/*!
@@ -4654,7 +5473,11 @@ bool QString::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const
*/
bool QString::startsWith(QChar c, Qt::CaseSensitivity cs) const
{
- return qt_starts_with(*this, c, cs);
+ if (!size())
+ return false;
+ if (cs == Qt::CaseSensitive)
+ return at(0) == c;
+ return foldCase(at(0)) == foldCase(c);
}
/*!
@@ -4662,22 +5485,19 @@ bool QString::startsWith(QChar c, Qt::CaseSensitivity cs) const
\since 5.10
\overload
- Returns \c true if the string starts with the string-view \a str;
+ 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
@@ -4685,9 +5505,8 @@ bool QString::startsWith(QChar c, Qt::CaseSensitivity cs) const
*/
bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(*this, s, cs);
+ 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
@@ -4696,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()
*/
@@ -4705,9 +5523,9 @@ bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
/*!
\overload endsWith()
*/
-bool QString::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const
+bool QString::endsWith(QLatin1StringView s, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(*this, s, cs);
+ return qt_ends_with_impl(QStringView(*this), s, cs);
}
/*!
@@ -4718,7 +5536,32 @@ bool QString::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const
*/
bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
{
- return qt_ends_with(*this, c, cs);
+ if (!size())
+ return false;
+ if (cs == Qt::CaseSensitive)
+ return at(size() - 1) == c;
+ 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);
}
/*!
@@ -4736,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.nextUnchecked();
- if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff)
- return false;
- }
-
- return true;
+ return QtPrivate::isUpper(qToStringViewIgnoringNull(*this));
}
/*!
@@ -4762,15 +5597,7 @@ bool QString::isUpper() const
*/
bool QString::isLower() const
{
- QStringIterator it(*this);
-
- while (it.hasNext()) {
- const char32_t uc = it.nextUnchecked();
- if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff)
- return false;
- }
-
- return true;
+ return QtPrivate::isLower(qToStringViewIgnoringNull(*this));
}
static QByteArray qt_convert_to_latin1(QStringView string);
@@ -4781,6 +5608,21 @@ QByteArray QString::toLatin1_helper(const QString &string)
}
/*!
+ \since 6.0
+ \internal
+ \relates QAnyStringView
+
+ Returns a UTF-16 representation of \a string as a QString.
+
+ \sa QString::toLatin1(), QStringView::toLatin1(), QtPrivate::convertToUtf8(),
+ QtPrivate::convertToLocal8Bit(), QtPrivate::convertToUcs4()
+*/
+QString QtPrivate::convertToQString(QAnyStringView string)
+{
+ return string.visit([] (auto string) { return string.toString(); });
+}
+
+/*!
\since 5.10
\internal
\relates QStringView
@@ -4797,12 +5639,13 @@ QByteArray QtPrivate::convertToLatin1(QStringView string)
return qt_convert_to_latin1(string);
}
+Q_NEVER_INLINE
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
@@ -4818,27 +5661,41 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
// We can return our own buffer to the caller.
// Conversion to Latin-1 always shrinks the buffer by half.
- const char16_t *data = s.d.data();
- int length = s.d.size;
+ // This relies on the fact that we use QArrayData for everything behind the scenes
- // Move the d pointer over to the bytearray.
+ // First, do the in-place conversion. Since isDetached() == true, the data
+ // was allocated by QArrayData, so the null terminator must be there.
+ qsizetype length = s.size();
+ char16_t *sdata = s.d->data();
+ Q_ASSERT(sdata[length] == u'\0');
+ qt_to_latin1(reinterpret_cast<uchar *>(sdata), sdata, length + 1);
+
+ // Move the internals over to the byte array.
// Kids, avert your eyes. Don't try this at home.
+ auto ba_d = std::move(s.d).reinterpreted<char>();
- // this relies on the fact that we use QArrayData for everything behind the scenes which has the same layout
- static_assert(sizeof(QByteArray::DataPointer) == sizeof(QString::DataPointer), "sizes have to be equal");
- QByteArray::DataPointer ba_d(reinterpret_cast<QByteArray::Data *>(s.d.d_ptr()), reinterpret_cast<char *>(s.d.data()), length);
- ba_d.ref();
- s.clear();
+ // Some sanity checks
+ Q_ASSERT(ba_d.d->allocatedCapacity() >= ba_d.size);
+ Q_ASSERT(s.isNull());
+ Q_ASSERT(s.isEmpty());
+ Q_ASSERT(s.constData() == QString().constData());
- char *ddata = ba_d.data();
+ return QByteArray(std::move(ba_d));
+}
- // multiply the allocated capacity by sizeof(char16_t)
- ba_d.d_ptr()->alloc *= sizeof(char16_t);
+// 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);
+}
- // do the in-place conversion
- qt_to_latin1(reinterpret_cast<uchar *>(ddata), data, length);
- ddata[length] = '\0';
- return QByteArray(ba_d);
+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;
}
/*!
@@ -4859,20 +5716,18 @@ 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
*/
-QByteArray QString::toLocal8Bit_helper(const QChar *data, int size)
+QByteArray QString::toLocal8Bit_helper(const QChar *data, qsizetype size)
{
return qt_convert_to_local_8bit(QStringView(data, size));
}
@@ -4892,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
@@ -4928,7 +5783,7 @@ static QByteArray qt_convert_to_utf8(QStringView str)
if (str.isNull())
return QByteArray();
- return QUtf8::convertFromUnicode(str.data(), str.length());
+ return QUtf8::convertFromUnicode(str);
}
/*!
@@ -4962,7 +5817,8 @@ static QList<uint> qt_convert_to_ucs4(QStringView string);
The returned list is not \\0'-terminated.
- \sa fromUtf8(), toUtf8(), toLatin1(), toLocal8Bit(), QStringEncoder, fromUcs4(), toWCharArray()
+ \sa fromUtf8(), toUtf8(), toLatin1(), toLocal8Bit(), QStringEncoder,
+ fromUcs4(), toWCharArray()
*/
QList<uint> QString::toUcs4() const
{
@@ -4971,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())
@@ -5002,31 +5858,40 @@ QList<uint> QtPrivate::convertToUcs4(QStringView string)
return qt_convert_to_ucs4(string);
}
-QString::DataPointer QString::fromLatin1_helper(const char *str, int size)
+/*!
+ \fn QString QString::fromLatin1(QByteArrayView str)
+ \overload
+ \since 6.0
+
+ Returns a QString initialized with the Latin-1 string \a str.
+
+ \note: any null ('\\0') bytes in the byte array will be included in this
+ string, converted to Unicode null characters (U+0000).
+*/
+QString QString::fromLatin1(QByteArrayView ba)
{
DataPointer d;
- if (!str) {
+ if (!ba.data()) {
// nothing to do
- } else if (size == 0 || (!*str && size < 0)) {
- d = DataPointer(Data::allocate(0), 0);
+ } else if (ba.size() == 0) {
+ d = DataPointer::fromRawData(&_empty, 0);
} else {
- if (size < 0)
- size = qstrlen(str);
- d = DataPointer(Data::allocate(size + 1), size);
- d.data()[size] = '\0';
+ d = DataPointer(ba.size(), ba.size());
+ Q_CHECK_PTR(d.data());
+ d.data()[ba.size()] = '\0';
char16_t *dst = d.data();
- qt_from_latin1(dst, str, uint(size));
+ qt_from_latin1(dst, ba.data(), size_t(ba.size()));
}
- return d;
+ return QString(std::move(d));
}
-/*! \fn QString QString::fromLatin1(const char *str, int size)
+/*!
+ \fn QString QString::fromLatin1(const char *str, qsizetype size)
Returns a QString initialized with the first \a size characters
of the Latin-1 string \a str.
- If \a size is -1 (default), it is taken to be strlen(\a
- str).
+ If \a size is \c{-1}, \c{strlen(str)} is used instead.
\sa toLatin1(), fromUtf8(), fromLocal8Bit()
*/
@@ -5037,17 +5902,20 @@ QString::DataPointer QString::fromLatin1_helper(const char *str, int size)
\since 5.0
Returns a QString initialized with the Latin-1 string \a str.
+
+ \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.
*/
-/*! \fn QString QString::fromLocal8Bit(const char *str, int size)
+/*!
+ \fn QString QString::fromLocal8Bit(const char *str, qsizetype size)
Returns a QString initialized with the first \a size characters
of the 8-bit string \a str.
- If \a size is -1 (default), it is taken to be strlen(\a
- str).
+ 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()
*/
@@ -5058,26 +5926,41 @@ QString::DataPointer QString::fromLatin1_helper(const char *str, int size)
\since 5.0
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.
+*/
+
+/*!
+ \fn QString QString::fromLocal8Bit(QByteArrayView str)
+ \overload
+ \since 6.0
+
+ 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).
*/
-QString QString::fromLocal8Bit_helper(const char *str, int size)
+QString QString::fromLocal8Bit(QByteArrayView ba)
{
- if (!str)
+ if (ba.isNull())
return QString();
- if (size == 0 || (!*str && size < 0)) {
- QPair<Data *, char16_t *> pair = Data::allocate(0);
- QString::DataPointer empty = { pair.first, pair.second, 0 };
- return QString(empty);
- }
+ if (ba.isEmpty())
+ return QString(DataPointer::fromRawData(&_empty, 0));
QStringDecoder toUtf16(QStringDecoder::System, QStringDecoder::Flag::Stateless);
- return toUtf16(str, size);
+ return toUtf16(ba);
}
-/*! \fn QString QString::fromUtf8(const char *str, int size)
+/*! \fn QString QString::fromUtf8(const char *str, qsizetype size)
Returns a QString initialized with the first \a size bytes
of the UTF-8 string \a str.
- If \a size is -1 (default), it is taken to be strlen(\a
- str).
+ If \a size is \c{-1}, \c{strlen(str)} is used instead.
UTF-8 is a Unicode codec and can represent all characters in a Unicode
string like QString. However, invalid sequences are possible with UTF-8
@@ -5095,6 +5978,14 @@ QString QString::fromLocal8Bit_helper(const char *str, int size)
*/
/*!
+ \fn QString QString::fromUtf8(const char8_t *str)
+ \overload
+ \since 6.1
+
+ This overload is only available when compiling in C++20 mode.
+*/
+
+/*!
\fn QString QString::fromUtf8(const char8_t *str, qsizetype size)
\overload
\since 6.0
@@ -5108,16 +5999,32 @@ QString QString::fromLocal8Bit_helper(const char *str, int size)
\since 5.0
Returns a QString initialized with the UTF-8 string \a str.
+
+ \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.
*/
-QString QString::fromUtf8_helper(const char *str, int size)
+
+/*!
+ \fn QString QString::fromUtf8(QByteArrayView str)
+ \overload
+ \since 6.0
+
+ Returns a QString initialized with the UTF-8 string \a str.
+
+ \note: any null ('\\0') bytes in the byte array will be included in this
+ string, converted to Unicode null characters (U+0000).
+*/
+QString QString::fromUtf8(QByteArrayView ba)
{
- if (!str)
+ if (ba.isNull())
return QString();
-
- Q_ASSERT(size != -1);
- return QUtf8::convertToUnicode(str, size);
+ if (ba.isEmpty())
+ return QString(DataPointer::fromRawData(&_empty, 0));
+ return QUtf8::convertToUnicode(ba);
}
+#ifndef QT_BOOTSTRAPPED
/*!
\since 5.3
Returns a QString initialized with the first \a size characters
@@ -5129,38 +6036,31 @@ QString QString::fromUtf8_helper(const char *str, int size)
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.
\sa utf16(), setUtf16(), fromStdU16String()
*/
-QString QString::fromUtf16(const char16_t *unicode, int size)
+QString QString::fromUtf16(const char16_t *unicode, qsizetype size)
{
if (!unicode)
return QString();
- if (size < 0) {
- size = 0;
- while (unicode[size] != 0)
- ++size;
- }
+ if (size < 0)
+ size = QtPrivate::qustrlen(unicode);
QStringDecoder toUtf16(QStringDecoder::Utf16, QStringDecoder::Flag::Stateless);
- return toUtf16(reinterpret_cast<const char *>(unicode), size*2);
+ return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 2));
}
/*!
- \fn QString QString::fromUtf16(const ushort *str, int size)
- \obsolete
-
- Use the \c char16_t overload.
+ \fn QString QString::fromUtf16(const ushort *str, qsizetype size)
+ \deprecated [6.0] Use the \c char16_t overload instead.
*/
/*!
- \fn QString QString::fromUcs4(const uint *str, int size)
+ \fn QString QString::fromUcs4(const uint *str, qsizetype size)
\since 4.2
- \obsolete
-
- Use the \c char32_t overload instead.
+ \deprecated [6.0] Use the \c char32_t overload instead.
*/
/*!
@@ -5171,9 +6071,10 @@ QString QString::fromUtf16(const char16_t *unicode, int size)
If \a size is -1 (default), \a unicode must be \\0'-terminated.
- \sa toUcs4(), fromUtf16(), utf16(), setUtf16(), fromWCharArray(), fromStdU32String()
+ \sa toUcs4(), fromUtf16(), utf16(), setUtf16(), fromWCharArray(),
+ fromStdU32String()
*/
-QString QString::fromUcs4(const char32_t *unicode, int size)
+QString QString::fromUcs4(const char32_t *unicode, qsizetype size)
{
if (!unicode)
return QString();
@@ -5183,20 +6084,20 @@ QString QString::fromUcs4(const char32_t *unicode, int size)
++size;
}
QStringDecoder toUtf16(QStringDecoder::Utf32, QStringDecoder::Flag::Stateless);
- return toUtf16(reinterpret_cast<const char *>(unicode), size*4);
+ return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 4));
}
-
+#endif // !QT_BOOTSTRAPPED
/*!
Resizes the string to \a size characters and copies \a unicode
into the string.
- If \a unicode is 0, nothing is copied, but the string is still
+ If \a unicode is \nullptr, nothing is copied, but the string is still
resized to \a size.
\sa unicode(), setUtf16()
*/
-QString& QString::setUnicode(const QChar *unicode, int size)
+QString& QString::setUnicode(const QChar *unicode, qsizetype size)
{
resize(size);
if (unicode && size)
@@ -5205,12 +6106,12 @@ QString& QString::setUnicode(const QChar *unicode, int size)
}
/*!
- \fn QString &QString::setUtf16(const ushort *unicode, int size)
+ \fn QString &QString::setUtf16(const ushort *unicode, qsizetype size)
Resizes the string to \a size characters and copies \a unicode
into the string.
- If \a unicode is 0, nothing is copied, but the string is still
+ If \a unicode is \nullptr, nothing is copied, but the string is still
resized to \a size.
Note that unlike fromUtf16(), this function does not consider BOMs and
@@ -5250,16 +6151,14 @@ 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};
}
}
/*!
\fn QStringView QtPrivate::trimmed(QStringView s)
- \fn QLatin1String QtPrivate::trimmed(QLatin1String s)
+ \fn QLatin1StringView QtPrivate::trimmed(QLatin1StringView s)
\internal
\relates QStringView
\since 5.10
@@ -5270,14 +6169,14 @@ namespace {
\c true. This includes the ASCII characters '\\t', '\\n', '\\v',
'\\f', '\\r', and ' '.
- \sa QString::trimmed(), QStringView::trimmed(), QLatin1String::trimmed()
+ \sa QString::trimmed(), QStringView::trimmed(), QLatin1StringView::trimmed()
*/
QStringView QtPrivate::trimmed(QStringView s) noexcept
{
return qt_trimmed(s);
}
-QLatin1String QtPrivate::trimmed(QLatin1String s) noexcept
+QLatin1StringView QtPrivate::trimmed(QLatin1StringView s) noexcept
{
return qt_trimmed(s);
}
@@ -5310,7 +6209,7 @@ QString QString::trimmed_helper(QString &str)
return QStringAlgorithms<QString>::trimmed_helper(str);
}
-/*! \fn const QChar QString::at(int position) const
+/*! \fn const QChar QString::at(qsizetype position) const
Returns the character at the given index \a position in the
string.
@@ -5322,7 +6221,7 @@ QString QString::trimmed_helper(QString &str)
*/
/*!
- \fn QChar &QString::operator[](int position)
+ \fn QChar &QString::operator[](qsizetype position)
Returns the character at the specified \a position in the string as a
modifiable reference.
@@ -5335,7 +6234,7 @@ QString QString::trimmed_helper(QString &str)
*/
/*!
- \fn const QChar QString::operator[](int position) const
+ \fn const QChar QString::operator[](qsizetype position) const
\overload operator[]()
*/
@@ -5401,7 +6300,7 @@ QString QString::trimmed_helper(QString &str)
*/
/*!
- \fn void QString::truncate(int position)
+ \fn void QString::truncate(qsizetype position)
Truncates the string at the given \a position index.
@@ -5414,10 +6313,10 @@ QString QString::trimmed_helper(QString &str)
If \a position is negative, it is equivalent to passing zero.
- \sa chop(), resize(), left(), QStringRef::truncate()
+ \sa chop(), resize(), first(), QStringView::truncate()
*/
-void QString::truncate(int pos)
+void QString::truncate(qsizetype pos)
{
if (pos < size())
resize(pos);
@@ -5436,9 +6335,9 @@ void QString::truncate(int pos)
If you want to remove characters from the \e beginning of the
string, use remove() instead.
- \sa truncate(), resize(), remove(), QStringRef::chop()
+ \sa truncate(), resize(), remove(), QStringView::chop()
*/
-void QString::chop(int n)
+void QString::chop(qsizetype n)
{
if (n > 0)
resize(d.size - n);
@@ -5456,20 +6355,16 @@ void QString::chop(int n)
\sa resize()
*/
-QString& QString::fill(QChar ch, int size)
+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;
}
/*!
- \fn int QString::length() const
+ \fn qsizetype QString::length() const
Returns the number of characters in this string. Equivalent to
size().
@@ -5478,7 +6373,7 @@ QString& QString::fill(QChar ch, int size)
*/
/*!
- \fn int QString::size() const
+ \fn qsizetype QString::size() const
Returns the number of characters in this string.
@@ -5490,6 +6385,16 @@ QString& QString::fill(QChar ch, int 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.
@@ -5535,11 +6440,18 @@ QString& QString::fill(QChar ch, int size)
\sa append(), prepend()
*/
-/*! \fn QString &QString::operator+=(QLatin1String str)
+/*! \fn QString &QString::operator+=(QLatin1StringView str)
\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)
@@ -5551,12 +6463,10 @@ QString& QString::fill(QChar ch, int size)
are embedded in the \a ba byte array, they will be included in the
transformation.
- You can disable this function by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
+ You can disable this function 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 QT_NO_CAST_FROM_ASCII
*/
/*! \fn QString &QString::operator+=(const char *str)
@@ -5566,19 +6476,10 @@ QString& QString::fill(QChar ch, int size)
Appends the string \a str to this string. The const char pointer
is converted to Unicode using the fromUtf8() function.
- You can disable this function by defining \c QT_NO_CAST_FROM_ASCII
+ You can disable this function 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 QT_NO_CAST_FROM_ASCII
-*/
-
-/*! \fn QString &QString::operator+=(const QStringRef &str)
-
- \overload operator+=()
-
- Appends the string section referenced by \a str to this string.
*/
/*! \fn QString &QString::operator+=(QStringView str)
@@ -5596,85 +6497,68 @@ QString& QString::fill(QChar ch, int size)
*/
/*!
- \fn bool operator==(const char *s1, const QString &s2)
+ \fn bool QString::operator==(const char * const &lhs, const QString &rhs)
- \overload operator==()
- \relates QString
+ \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 operator!=(const char *s1, const QString &s2)
- \relates QString
+ \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 operator<(const char *s1, const QString &s2)
- \relates QString
+ \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}.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
+ \sa {Comparing Strings}
*/
/*!
- \fn bool operator<=(const char *s1, const QString &s2)
- \relates QString
+ \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}.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- QString::localeAwareCompare().
+ \sa {Comparing Strings}
*/
/*!
- \fn bool operator>(const char *s1, const QString &s2)
- \relates QString
+ \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}.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
+ \sa {Comparing Strings}
*/
/*!
- \fn bool operator>=(const char *s1, const QString &s2)
- \relates QString
+ \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}.
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
+ \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
@@ -5682,7 +6566,7 @@ QString& QString::fill(QChar ch, int 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
@@ -5693,7 +6577,7 @@ QString& QString::fill(QChar ch, int 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
@@ -5707,12 +6591,11 @@ QString& QString::fill(QChar ch, int 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
@@ -5721,11 +6604,16 @@ QString& QString::fill(QChar ch, int size)
\snippet qstring/main.cpp 16
- \sa operator==(), operator<(), operator>()
+//! [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}
*/
/*!
- \fn int QString::compare(const QString &s1, QLatin1String s2, Qt::CaseSensitivity cs)
+ \fn int QString::compare(const QString &s1, QLatin1StringView s2, Qt::CaseSensitivity cs)
\since 4.2
\overload compare()
@@ -5734,7 +6622,7 @@ QString& QString::fill(QChar ch, int size)
*/
/*!
- \fn int QString::compare(QLatin1String s1, const QString &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
+ \fn int QString::compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
\since 4.2
\overload compare()
@@ -5763,36 +6651,33 @@ QString& QString::fill(QChar ch, int 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).
*/
int QString::compare(const QString &other, Qt::CaseSensitivity cs) const noexcept
{
- return qt_compare_strings(*this, other, cs);
+ return QtPrivate::compareStrings(*this, other, cs);
}
-#endif
/*!
\internal
\since 4.5
*/
-int QString::compare_helper(const QChar *data1, int length1, const QChar *data2, int length2,
+int QString::compare_helper(const QChar *data1, qsizetype length1, const QChar *data2, qsizetype length2,
Qt::CaseSensitivity cs) noexcept
{
Q_ASSERT(length1 >= 0);
Q_ASSERT(length2 >= 0);
Q_ASSERT(data1 || length1 == 0);
Q_ASSERT(data2 || length2 == 0);
- return qt_compare_strings(QStringView(data1, length1), QStringView(data2, length2), cs);
+ return QtPrivate::compareStrings(QStringView(data1, length1), QStringView(data2, length2), cs);
}
/*!
@@ -5801,29 +6686,26 @@ int QString::compare_helper(const QChar *data1, int length1, const QChar *data2,
Same as compare(*this, \a other, \a cs).
*/
-int QString::compare(QLatin1String other, Qt::CaseSensitivity cs) const noexcept
+int QString::compare(QLatin1StringView other, Qt::CaseSensitivity cs) const noexcept
{
- return qt_compare_strings(*this, other, cs);
+ return QtPrivate::compareStrings(*this, other, cs);
}
/*!
\internal
\since 5.0
*/
-int QString::compare_helper(const QChar *data1, int length1, const char *data2, int length2,
- Qt::CaseSensitivity cs)
+int QString::compare_helper(const QChar *data1, qsizetype length1, const char *data2, qsizetype length2,
+ Qt::CaseSensitivity cs) noexcept
{
Q_ASSERT(length1 >= 0);
Q_ASSERT(data1 || length1 == 0);
if (!data2)
- return length1;
+ return qt_lencmp(length1, 0);
if (Q_UNLIKELY(length2 < 0))
- length2 = int(strlen(data2));
- // ### make me nothrow in all cases
- QVarLengthArray<ushort> s2(length2);
- const auto beg = reinterpret_cast<QChar *>(s2.data());
- const auto end = QUtf8::convertToUnicode(beg, data2, length2);
- return qt_compare_strings(QStringView(data1, length1), QStringView(beg, end - beg), cs);
+ length2 = qsizetype(strlen(data2));
+ return QtPrivate::compareStrings(QStringView(data1, length1),
+ QUtf8StringView(data2, length2), cs);
}
/*!
@@ -5836,16 +6718,120 @@ int QString::compare_helper(const QChar *data1, int length1, const char *data2,
\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
*/
-int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2,
- Qt::CaseSensitivity cs) noexcept
+int QLatin1StringView::compare_helper(const QChar *data1, qsizetype length1, QLatin1StringView s2,
+ Qt::CaseSensitivity cs) noexcept
{
Q_ASSERT(length1 >= 0);
Q_ASSERT(data1 || length1 == 0);
- return qt_compare_strings(QStringView(data1, length1), s2, cs);
+ return QtPrivate::compareStrings(QStringView(data1, length1), s2, cs);
}
/*!
@@ -5859,10 +6845,7 @@ int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2,
platform-dependent manner. Use this function to present sorted
lists of strings to the user.
- On \macos and iOS this function compares according the
- "Order for sorted lists" setting in the International preferences panel.
-
- \sa compare(), QLocale
+ \sa compare(), QLocale, {Comparing Strings}
*/
/*!
@@ -5879,6 +6862,8 @@ int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2,
lists of strings to the user.
Same as \c {localeAwareCompare(*this, other)}.
+
+ \sa {Comparing Strings}
*/
/*!
@@ -5893,6 +6878,8 @@ int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2,
The comparison is performed in a locale- and also
platform-dependent manner. Use this function to present sorted
lists of strings to the user.
+
+ \sa {Comparing Strings}
*/
@@ -5914,22 +6901,20 @@ int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2,
lists of strings to the user.
Same as \c {localeAwareCompare(*this, other)}.
+
+ \sa {Comparing Strings}
*/
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());
}
-#if QT_CONFIG(icu)
-Q_GLOBAL_STATIC(QThreadStorage<QCollator>, defaultCollator)
-#endif
-
/*!
\internal
\since 4.5
*/
-int QString::localeAwareCompare_helper(const QChar *data1, int length1,
- const QChar *data2, int length2)
+int QString::localeAwareCompare_helper(const QChar *data1, qsizetype length1,
+ const QChar *data2, qsizetype length2)
{
Q_ASSERT(length1 >= 0);
Q_ASSERT(data1 || length1 == 0);
@@ -5938,13 +6923,11 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
// do the right thing for null and empty
if (length1 == 0 || length2 == 0)
- return qt_compare_strings(QStringView(data1, length1), QStringView(data2, length2),
+ return QtPrivate::compareStrings(QStringView(data1, length1), QStringView(data2, length2),
Qt::CaseSensitive);
#if QT_CONFIG(icu)
- if (!defaultCollator()->hasLocalData())
- defaultCollator()->setLocalData(QCollator());
- return defaultCollator()->localData().compare(data1, length1, data2, length2);
+ return QCollator::defaultCompare(QStringView(data1, length1), QStringView(data2, length2));
#else
const QString lhs = QString::fromRawData(data1, length1).normalized(QString::NormalizationForm_C);
const QString rhs = QString::fromRawData(data2, length2).normalized(QString::NormalizationForm_C);
@@ -5976,14 +6959,11 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1,
CFRelease(otherString);
return result;
# elif defined(Q_OS_UNIX)
- // declared in <string.h>
- int delta = strcoll(lhs.toLocal8Bit().constData(), rhs.toLocal8Bit().constData());
- if (delta == 0)
- delta = qt_compare_strings(lhs, rhs, Qt::CaseSensitive);
- return delta;
+ // declared in <string.h> (no better than QtPrivate::compareStrings() on Android, sadly)
+ return strcoll(lhs.toLocal8Bit().constData(), rhs.toLocal8Bit().constData());
# else
# error "This case shouldn't happen"
- return qt_compare_strings(lhs, rhs, Qt::CaseSensitive);
+ return QtPrivate::compareStrings(lhs, rhs, Qt::CaseSensitive);
# endif
#endif // !QT_CONFIG(icu)
}
@@ -6016,7 +6996,7 @@ const ushort *QString::utf16() const
{
if (!d->isMutable()) {
// ensure '\0'-termination for ::fromRawData strings
- const_cast<QString*>(this)->reallocData(uint(d.size) + 1u);
+ const_cast<QString*>(this)->reallocData(d.size, QArrayData::KeepSize);
}
return reinterpret_cast<const ushort *>(d.data());
}
@@ -6039,11 +7019,11 @@ const ushort *QString::utf16() const
\sa rightJustified()
*/
-QString QString::leftJustified(int width, QChar fill, bool truncate) const
+QString QString::leftJustified(qsizetype width, QChar fill, bool truncate) const
{
QString result;
- int len = length();
- int padlen = width - len;
+ qsizetype len = size();
+ qsizetype padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
if (len)
@@ -6078,11 +7058,11 @@ QString QString::leftJustified(int width, QChar fill, bool truncate) const
\sa leftJustified()
*/
-QString QString::rightJustified(int width, QChar fill, bool truncate) const
+QString QString::rightJustified(qsizetype width, QChar fill, bool truncate) const
{
QString result;
- int len = length();
- int padlen = width - len;
+ qsizetype len = size();
+ qsizetype padlen = width - len;
if (padlen > 0) {
result.resize(len+padlen);
QChar *uc = (QChar*)result.d.data();
@@ -6106,8 +7086,8 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const
\snippet qstring/main.cpp 75
- The case conversion will always happen in the 'C' locale. For locale dependent
- case folding use QLocale::toLower()
+ The case conversion will always happen in the 'C' locale. For
+ locale-dependent case folding use QLocale::toLower()
\sa toUpper(), QLocale::toLower()
*/
@@ -6130,9 +7110,9 @@ namespace QUnicodeTables {
\endlist
In copy-convert mode, the local variable \c{s} is detached from the input
- \a str. In the in-place convert mode, \a str is in moved-from state (which
- this function requires to be a valid, empty string) and \c{s} contains the
- only copy of the string, without reallocation (thus, \a it is still valid).
+ \a str. In the in-place convert mode, \a str is in moved-from state and
+ \c{s} contains the only copy of the string, without reallocation (thus,
+ \a it is still valid).
There is one pathological case left: when the in-place conversion needs to
reallocate memory to grow the buffer. In that case, we need to adjust the \a
@@ -6143,11 +7123,11 @@ Q_NEVER_INLINE
static QString detachAndConvertCase(T &str, QStringIterator it, QUnicodeTables::Case which)
{
Q_ASSERT(!str.isEmpty());
- QString s = std::move(str); // will copy if T is const QString
+ QString s = std::move(str); // will copy if T is const QString
QChar *pp = s.begin() + it.index(); // will detach if necessary
do {
- const auto folded = fullConvertCase(it.nextUnchecked(), which);
+ const auto folded = fullConvertCase(it.next(), which);
if (Q_UNLIKELY(folded.size() > 1)) {
if (folded.chars[0] == *pp && folded.size() == 2) {
// special case: only second actually changed (e.g. surrogate pairs),
@@ -6156,15 +7136,14 @@ static QString detachAndConvertCase(T &str, QStringIterator it, QUnicodeTables::
*pp++ = folded.chars[1];
} else {
// slow path: the string is growing
- int inpos = it.index() - 1;
- int outpos = pp - s.constBegin();
+ qsizetype inpos = it.index() - 1;
+ qsizetype outpos = pp - s.constBegin();
s.replace(outpos, 1, reinterpret_cast<const QChar *>(folded.data()), folded.size());
pp = const_cast<QChar *>(s.constBegin()) + outpos + folded.size();
- // do we need to adjust the input iterator too?
- // if it is pointing to s's data, str is empty
- if (str.isEmpty())
+ // Adjust the input iterator if we are performing an in-place conversion
+ if constexpr (!std::is_const<T>::value)
it = QStringIterator(s.constBegin(), inpos + folded.size(), s.constEnd());
}
} else {
@@ -6187,9 +7166,9 @@ static QString convertCase(T &str, QUnicodeTables::Case which)
QStringIterator it(p, e);
while (it.hasNext()) {
- const char32_t uc = it.nextUnchecked();
+ const char32_t uc = it.next();
if (qGetProp(uc)->cases[which].diff) {
- it.recedeUnchecked();
+ it.recede();
return detachAndConvertCase(str, it, which);
}
}
@@ -6231,8 +7210,8 @@ QString QString::toCaseFolded_helper(QString &str)
\snippet qstring/main.cpp 81
- The case conversion will always happen in the 'C' locale. For locale dependent
- case folding use QLocale::toUpper()
+ The case conversion will always happen in the 'C' locale. For
+ locale-dependent case folding use QLocale::toUpper()
\sa toLower(), QLocale::toLower()
*/
@@ -6247,7 +7226,6 @@ QString QString::toUpper_helper(QString &str)
return QUnicodeTables::convertCase(str, QUnicodeTables::UpperCase);
}
-// ### Qt 6: Consider whether this function shouldn't be removed See task 202871.
/*!
\since 5.5
@@ -6291,11 +7269,11 @@ 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, cs, len);
+ const QChar *newEnd = QUtf8::convertToUnicode(qs.data() + oldSize, QByteArrayView(cs, len));
qs.resize(newEnd - qs.constData());
}
@@ -6312,26 +7290,28 @@ static uint parse_flag_characters(const char * &c) noexcept
case '-': flags |= QLocaleData::LeftAdjusted; break;
case ' ': flags |= QLocaleData::BlankBeforePositive; break;
case '+': flags |= QLocaleData::AlwaysShowSign; break;
- case '\'': flags |= QLocaleData::ThousandsGroup; break;
+ case '\'': flags |= QLocaleData::GroupDigits; break;
default: return flags;
}
++c;
}
}
-static int parse_field_width(const char * &c)
+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 = qstrtoull(c, &endp, 10, &ok);
- c = endp;
- while (qIsDigit(*c)) // preserve Qt 5.5 behavior of consuming all digits, no matter how many
+ 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 && 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 };
@@ -6385,12 +7365,13 @@ QString QString::vasprintf(const char *cformat, va_list ap)
QString result;
const char *c = cformat;
+ const char *formatEnd = cformat + qstrlen(cformat);
for (;;) {
// Copy non-escape chars to result
const char *cb = c;
while (*c != '\0' && *c != '%')
c++;
- append_utf8(result, cb, int(c - cb));
+ append_utf8(result, cb, qsizetype(c - cb));
if (*c == '\0')
break;
@@ -6400,11 +7381,11 @@ QString QString::vasprintf(const char *cformat, va_list ap)
++c;
if (*c == '\0') {
- result.append(QLatin1Char('%')); // a % at the end of the string - treat as non-escape text
+ result.append(u'%'); // a % at the end of the string - treat as non-escape text
break;
}
if (*c == '%') {
- result.append(QLatin1Char('%')); // %%
+ result.append(u'%'); // %%
++c;
continue;
}
@@ -6412,14 +7393,14 @@ QString QString::vasprintf(const char *cformat, va_list ap)
uint flags = parse_flag_characters(c);
if (*c == '\0') {
- result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
+ result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
break;
}
// Parse field width
int width = -1; // -1 means unspecified
- if (qIsDigit(*c)) {
- width = parse_field_width(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);
if (width < 0)
@@ -6428,7 +7409,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
}
if (*c == '\0') {
- result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
+ result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
break;
}
@@ -6436,8 +7417,9 @@ QString QString::vasprintf(const char *cformat, va_list ap)
int precision = -1; // -1 means unspecified
if (*c == '.') {
++c;
- if (qIsDigit(*c)) {
- precision = parse_field_width(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);
if (precision < 0)
@@ -6447,14 +7429,14 @@ QString QString::vasprintf(const char *cformat, va_list ap)
}
if (*c == '\0') {
- result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
+ result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
break;
}
const LengthMod length_mod = parse_length_modifier(c);
if (*c == '\0') {
- result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
+ result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
break;
}
@@ -6471,8 +7453,10 @@ QString QString::vasprintf(const char *cformat, va_list ap)
case lm_l: i = va_arg(ap, long int); break;
case lm_ll: i = va_arg(ap, qint64); break;
case lm_j: i = va_arg(ap, long int); break;
- case lm_z: i = va_arg(ap, size_t); break;
- case lm_t: i = va_arg(ap, int); break;
+
+ /* ptrdiff_t actually, but it should be the same for us */
+ case lm_z: i = va_arg(ap, qsizetype); break;
+ case lm_t: i = va_arg(ap, qsizetype); break;
default: i = 0; break;
}
subst = QLocaleData::c()->longLongToString(i, precision, 10, width, flags);
@@ -6490,15 +7474,16 @@ QString QString::vasprintf(const char *cformat, va_list ap)
case lm_h: u = va_arg(ap, uint); break;
case lm_l: u = va_arg(ap, ulong); break;
case lm_ll: u = va_arg(ap, quint64); break;
+ case lm_t: u = va_arg(ap, size_t); break;
case lm_z: u = va_arg(ap, size_t); break;
default: u = 0; break;
}
- if (qIsUpper(*c))
+ if (isAsciiUpper(*c))
flags |= QLocaleData::CapitalEorX;
int base = 10;
- switch (qToLower(*c)) {
+ switch (QtMiscUtils::toAsciiLower(*c)) {
case 'o':
base = 8; break;
case 'u':
@@ -6525,11 +7510,11 @@ 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;
- switch (qToLower(*c)) {
+ switch (QtMiscUtils::toAsciiLower(*c)) {
case 'e': form = QLocaleData::DFExponent; break;
case 'a': // not supported - decimal form used instead
case 'f': form = QLocaleData::DFDecimal; break;
@@ -6552,13 +7537,17 @@ QString QString::vasprintf(const char *cformat, va_list ap)
if (length_mod == lm_l) {
const ushort *buff = va_arg(ap, const ushort*);
const ushort *ch = buff;
- while (*ch != 0)
+ while (precision != 0 && *ch != 0) {
++ch;
+ --precision;
+ }
subst.setUtf16(buff, ch - buff);
- } else
+ } else if (precision == -1) {
subst = QString::fromUtf8(va_arg(ap, const char*));
- if (precision != -1)
- subst.truncate(precision);
+ } else {
+ const char *buff = va_arg(ap, const char*);
+ subst = QString::fromUtf8(buff, qstrnlen(buff, precision));
+ }
++c;
break;
}
@@ -6574,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;
}
}
@@ -6617,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.
@@ -6624,12 +7615,13 @@ QString QString::vasprintf(const char *cformat, va_list ap)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toLongLong()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toLongLong()
Example:
@@ -6637,28 +7629,41 @@ QString QString::vasprintf(const char *cformat, va_list ap)
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\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.
@@ -6666,12 +7671,13 @@ qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toULongLong()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toULongLong()
Example:
@@ -6679,24 +7685,14 @@ qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\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);
}
/*!
@@ -6709,12 +7705,13 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toLongLong()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toLongLong()
Example:
@@ -6722,14 +7719,11 @@ qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number(), toULong(), toInt(), QLocale::toInt()
*/
-long QString::toLong(bool *ok, int base) const
-{
- return toIntegral_helper<long>(*this, ok, base);
-}
-
/*!
\fn ulong QString::toULong(bool *ok, int base) const
@@ -6740,12 +7734,13 @@ long QString::toLong(bool *ok, int base) const
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toULongLong()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toULongLong()
Example:
@@ -6753,16 +7748,13 @@ long QString::toLong(bool *ok, int base) const
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number(), QLocale::toUInt()
*/
-ulong QString::toULong(bool *ok, int base) const
-{
- return toIntegral_helper<ulong>(*this, ok, base);
-}
-
-
/*!
+ \fn int QString::toInt(bool *ok, int base) const
Returns the string converted to an \c int using base \a
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
@@ -6770,12 +7762,13 @@ ulong QString::toULong(bool *ok, int base) const
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toInt()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toInt()
Example:
@@ -6783,15 +7776,13 @@ ulong QString::toULong(bool *ok, int base) const
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number(), toUInt(), toDouble(), QLocale::toInt()
*/
-int QString::toInt(bool *ok, int base) const
-{
- return toIntegral_helper<int>(*this, ok, base);
-}
-
/*!
+ \fn uint QString::toUInt(bool *ok, int base) const
Returns the string converted to an \c{unsigned int} using base \a
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
@@ -6799,12 +7790,13 @@ int QString::toInt(bool *ok, int base) const
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toUInt()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toUInt()
Example:
@@ -6812,15 +7804,14 @@ int QString::toInt(bool *ok, int base) const
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number(), toInt(), QLocale::toUInt()
*/
-uint QString::toUInt(bool *ok, int base) const
-{
- return toIntegral_helper<uint>(*this, ok, base);
-}
-
/*!
+ \fn short QString::toShort(bool *ok, int base) const
+
Returns the string converted to a \c short using base \a
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
@@ -6828,12 +7819,13 @@ uint QString::toUInt(bool *ok, int base) const
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toShort()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toShort()
Example:
@@ -6841,15 +7833,14 @@ uint QString::toUInt(bool *ok, int base) const
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number(), toUShort(), toInt(), QLocale::toShort()
*/
-short QString::toShort(bool *ok, int base) const
-{
- return toIntegral_helper<short>(*this, ok, base);
-}
-
/*!
+ \fn ushort QString::toUShort(bool *ok, int base) const
+
Returns the string converted to an \c{unsigned short} using base \a
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
@@ -6857,12 +7848,13 @@ short QString::toShort(bool *ok, int base) const
If \a ok is not \nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If \a base is 0, the C language convention is used: if the string begins
+ with "0x", base 16 is used; otherwise, if the string begins with "0b", base
+ 2 is used; otherwise, if the string begins with "0", base 8 is used;
+ otherwise, base 10 is used.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toUShort()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toUShort()
Example:
@@ -6870,15 +7862,11 @@ short QString::toShort(bool *ok, int base) const
This function ignores leading and trailing whitespace.
+ \note Support for the "0b" prefix was added in Qt 6.4.
+
\sa number(), toShort(), QLocale::toUShort()
*/
-ushort QString::toUShort(bool *ok, int base) const
-{
- return toIntegral_helper<ushort>(*this, ok, base);
-}
-
-
/*!
Returns the string converted to a \c double value.
@@ -6897,8 +7885,8 @@ ushort QString::toUShort(bool *ok, int base) const
\snippet qstring/main.cpp 67
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toDouble()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toDouble()
\snippet qstring/main.cpp 68
@@ -6915,7 +7903,18 @@ ushort QString::toUShort(bool *ok, int base) const
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;
}
/*!
@@ -6932,8 +7931,8 @@ double QString::toDouble(bool *ok) const
notation, and the decimal point. Including the unit or additional characters
leads to a conversion error.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toFloat()
+ The string conversion will always happen in the 'C' locale. For
+ locale-dependent conversion use QLocale::toFloat()
For historical reasons, this function does not handle
thousands group separators. If you need to convert such numbers,
@@ -6953,13 +7952,17 @@ 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
base, and returns a reference to the string.
- The base is 10 by default and must be between 2 and 36. For bases
- other than 10, \a n is treated as an unsigned integer.
+ The base is 10 by default and must be between 2 and 36.
\snippet qstring/main.cpp 56
@@ -7012,26 +8015,17 @@ QString &QString::setNum(qulonglong n, int base)
*/
/*!
- \fn QString &QString::setNum(double n, char format, int precision)
\overload
- Sets the string to the printed value of \a n, formatted according
- to the given \a format and \a precision, and returns a reference
- to the string.
-
- The \a format can be 'e', 'E', 'f', 'g' or 'G' (see
- \l{Argument Formats} for an explanation of the formats).
-
- The formatting always uses QLocale::C, i.e., English/UnitedStates.
- To get a localized string representation of a number, use
- QLocale::toString() with the appropriate locale.
+ Sets the string to the printed value of \a n, formatted according to the
+ given \a format and \a precision, and returns a reference to the string.
- \sa number()
+ \sa number(), QLocale::FloatingPointPrecisionOption, {Number Formats}
*/
-QString &QString::setNum(double n, char f, int prec)
+QString &QString::setNum(double n, char format, int precision)
{
- return *this = number(n, f, prec);
+ return *this = number(n, format, precision);
}
/*!
@@ -7111,7 +8105,12 @@ QString QString::number(qlonglong n, int base)
base = 10;
}
#endif
- return QLocaleData::c()->longLongToString(n, -1, base);
+ bool negative = n < 0;
+ /*
+ Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
+ taking an absolute value has to take a slight detour.
+ */
+ return qulltoBasicLatin(negative ? 1u + qulonglong(-(n + 1)) : qulonglong(n), base, negative);
}
/*!
@@ -7125,31 +8124,26 @@ QString QString::number(qulonglong n, int base)
base = 10;
}
#endif
- return QLocaleData::c()->unsLongLongToString(n, -1, base);
+ return qulltoBasicLatin(n, base, false);
}
/*!
- \fn QString QString::number(double n, char format, int precision)
+ Returns a string representing the floating-point number \a n.
- Returns a string equivalent of the number \a n, formatted
- according to the specified \a format and \a precision. See
- \l{Argument Formats} for details.
+ Returns a string that represents \a n, formatted according to the specified
+ \a format and \a precision.
- Unlike QLocale::toString(), this function does not honor the
- user's locale settings.
+ For formats with an exponent, the exponent will show its sign and have at
+ least two digits, left-padding the exponent with zero if needed.
- \sa setNum(), QLocale::toString()
+ \sa setNum(), QLocale::toString(), QLocale::FloatingPointPrecisionOption, {Number Formats}
*/
-QString QString::number(double n, char f, int prec)
+QString QString::number(double n, char format, int precision)
{
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- uint flags = QLocaleData::ZeroPadExponent;
- if (qIsUpper(f))
- flags |= QLocaleData::CapitalEorX;
-
- switch (qToLower(f)) {
+ switch (QtMiscUtils::toAsciiLower(format)) {
case 'f':
form = QLocaleData::DFDecimal;
break;
@@ -7161,12 +8155,12 @@ QString QString::number(double n, char f, int prec)
break;
default:
#if defined(QT_CHECK_RANGE)
- qWarning("QString::setNum: Invalid format char '%c'", f);
+ qWarning("QString::setNum: Invalid format char '%c'", format);
#endif
break;
}
- return QLocaleData::c()->doubleToString(n, prec, form, -1, flags);
+ return qdtoBasicLatin(n, form, precision, isAsciiUpper(format));
}
namespace {
@@ -7180,12 +8174,12 @@ static ResultList splitString(const StringSource &source, QStringView sep,
typename StringSource::size_type extra = 0;
while ((end = QtPrivate::findString(QStringView(source.constData(), source.size()), start + extra, sep, cs)) != -1) {
if (start != end || behavior == Qt::KeepEmptyParts)
- list.append(source.mid(start, end - start));
+ list.append(source.sliced(start, end - start));
start = end + sep.size();
extra = (sep.size() == 0 ? 1 : 0);
}
if (start != source.size() || behavior == Qt::KeepEmptyParts)
- list.append(source.mid(start));
+ list.append(source.sliced(start));
return list;
}
@@ -7200,7 +8194,7 @@ static ResultList splitString(const StringSource &source, QStringView sep,
\a cs specifies whether \a sep should be matched case
sensitively or case insensitively.
- If \a behavior is QString::SkipEmptyParts, empty entries don't
+ If \a behavior is Qt::SkipEmptyParts, empty entries don't
appear in the result. By default, empty entries are kept.
Example:
@@ -7227,24 +8221,6 @@ QStringList QString::split(const QString &sep, Qt::SplitBehavior behavior, Qt::C
}
/*!
- Splits the string into substring references wherever \a sep occurs, and
- returns the list of those strings.
-
- See QString::split() for how \a sep, \a behavior and \a cs interact to form
- the result.
-
- \note All references are valid as long this string is alive. Destroying this
- string will cause all references to be dangling pointers.
-
- \since 5.14
- \sa QStringRef split()
-*/
-QList<QStringRef> QString::splitRef(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{
- return splitString<QList<QStringRef>>(QStringRef(this), sep, behavior, cs);
-}
-
-/*!
\overload
\since 5.14
*/
@@ -7254,53 +8230,19 @@ QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensit
}
/*!
- \overload
- \since 5.14
-*/
-QList<QStringRef> QString::splitRef(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{
- return splitString<QList<QStringRef>>(QStringRef(this), QStringView(&sep, 1), behavior, cs);
-}
-
-/*!
- Splits the string into substrings references wherever \a sep occurs, and
- returns the list of those strings.
-
- See QString::split() for how \a sep, \a behavior and \a cs interact to form
- the result.
-
- \note All references are valid as long this string is alive. Destroying this
- string will cause all references to be dangling pointers.
-
- \since 5.14
-*/
-QList<QStringRef> QStringRef::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{
- return splitString<QList<QStringRef>>(*this, sep, behavior, cs);
-}
-
-/*!
- \overload
- \since 5.14
-*/
-QList<QStringRef> QStringRef::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
-{
- return splitString<QList<QStringRef>>(*this, QStringView(&sep, 1), behavior, cs);
-}
-
-/*!
\fn QList<QStringView> QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
\fn QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
- Splits the string into substring references wherever \a sep occurs, and
- returns the list of those strings.
+ 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 references are valid as long this string is alive. Destroying this
- string will cause all references 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
*/
@@ -7316,29 +8258,30 @@ 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;
if (!re.isValid()) {
- qWarning("QString::split: invalid QRegularExpression object");
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString::split");
return list;
}
- int start = 0;
- int end = 0;
- QRegularExpressionMatchIterator iterator = re.globalMatch(source);
+ qsizetype start = 0;
+ qsizetype end = 0;
+ QRegularExpressionMatchIterator iterator = (re.*matchingFunction)(source, 0, QRegularExpression::NormalMatch, QRegularExpression::NoMatchOption);
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
end = match.capturedStart();
if (start != end || behavior == Qt::KeepEmptyParts)
- list.append(source.mid(start, end - start));
+ list.append(source.sliced(start, end - start));
start = match.capturedEnd();
}
if (start != source.size() || behavior == Qt::KeepEmptyParts)
- list.append(source.mid(start));
+ list.append(source.sliced(start));
return list;
}
@@ -7373,44 +8316,33 @@ 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 5.14
-
- Splits the string into substring references wherever the regular expression
- \a re matches, and returns the list of those strings. If \a re
- does not match anywhere in the string, splitRef() returns a
- single-element list containing this string reference.
-
- \note All references are valid as long this string is alive. Destroying this
- string will cause all references to be dangling pointers.
-
- \sa split() QStringRef
-*/
-QList<QStringRef> QString::splitRef(const QRegularExpression &re, Qt::SplitBehavior behavior) const
-{
- return splitString<QList<QStringRef>>(QStringRef(this), re, behavior);
-}
-
-/*!
\since 6.0
- Splits the string into substring views wherever the regular expression
- \a re matches, and returns the list of those strings. If \a re
- does not match anywhere in the string, splitRef() returns a
- single-element list containing this string reference.
-
- \note All references are valid as long this string is alive. Destroying this
- string will cause all references to be dangling pointers.
+ Splits the string into substring views wherever the regular expression \a re
+ matches, and returns the list of those strings. If \a re does not match
+ anywhere in the string, split() returns a single-element list containing
+ this string as view.
- \sa split() QStringRef
+ \note The views in the returned list are sub-views of this view; as such,
+ they reference the same data as it and only remain valid for as long as that
+ data remains live.
*/
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)
@@ -7426,7 +8358,7 @@ QList<QStringView> QStringView::split(const QRegularExpression &re, Qt::SplitBeh
\value NormalizationForm_KC Compatibility Decomposition followed by Canonical Composition
\sa normalized(),
- {http://www.unicode.org/reports/tr15/}{Unicode Standard Annex #15}
+ {https://www.unicode.org/reports/tr15/}{Unicode Standard Annex #15}
*/
/*!
@@ -7440,7 +8372,7 @@ QList<QStringView> QStringView::split(const QRegularExpression &re, Qt::SplitBeh
\snippet code/src_corelib_text_qstring.cpp 8
*/
-QString QString::repeated(int times) const
+QString QString::repeated(qsizetype times) const
{
if (d.size == 0)
return *this;
@@ -7451,7 +8383,7 @@ QString QString::repeated(int times) const
return QString();
}
- const int resultSize = times * d.size;
+ const qsizetype resultSize = times * d.size;
QString result;
result.reserve(resultSize);
@@ -7460,10 +8392,10 @@ QString QString::repeated(int times) const
memcpy(result.d.data(), d.data(), d.size * sizeof(QChar));
- int sizeSoFar = d.size;
+ qsizetype sizeSoFar = d.size;
char16_t *end = result.d.data() + sizeSoFar;
- const int halfResultSize = resultSize >> 1;
+ const qsizetype halfResultSize = resultSize >> 1;
while (sizeSoFar <= halfResultSize) {
memcpy(end, result.d.data(), sizeSoFar * sizeof(QChar));
end += sizeSoFar;
@@ -7475,29 +8407,32 @@ QString QString::repeated(int times) const
return result;
}
-void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from)
+void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, qsizetype from)
{
- const QChar *p = data->constData() + from;
- if (isAscii(p, p + data->length() - from))
- return;
- if (p > data->constData() + from)
- from = p - data->constData() - 1; // need one before the non-ASCII to perform NFC
+ {
+ // 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->size() - from))
+ return;
+ if (p > start + from)
+ from = p - start - 1; // need one before the non-ASCII to perform NFC
+ }
if (version == QChar::Unicode_Unassigned) {
version = QChar::currentUnicodeVersion();
} 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) {
- int pos = from;
+ qsizetype pos = from;
if (QChar::requiresSurrogates(n.ucs4)) {
char16_t ucs4High = QChar::highSurrogate(n.ucs4);
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();
@@ -7507,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();
@@ -7544,14 +8479,42 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi
return copy;
}
+#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
+ // digit. We can skip the check in case we already know it will
+ // succeed.
+ if (!supportUnicodeDigitValuesInArg())
+ return;
+
+ const auto isNonAsciiDigit = [](QChar c) {
+ return c.unicode() < u'0' || c.unicode() > u'9';
+ };
+
+ if (std::any_of(s.begin(), s.end(), isNonAsciiDigit)) {
+ const auto accumulateDigit = [](int partial, QChar digit) {
+ return partial * 10 + digit.digitValue();
+ };
+ const int parsedNumber = std::accumulate(s.begin(), s.end(), 0, accumulateDigit);
+
+ qWarning("QString::arg(): the replacement \"%%%ls\" contains non-ASCII digits;\n"
+ " it is currently being interpreted as the %d-th substitution.\n"
+ " This is deprecated; support for non-ASCII digits will be dropped\n"
+ " in a future version of Qt.",
+ qUtf16Printable(s.toString()),
+ parsedNumber);
+ }
+}
+#endif
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)
@@ -7584,20 +8547,34 @@ static ArgEscapeData findArgEscapes(QStringView s)
break;
}
- int escape = c->digitValue();
+ int escape = qArgDigitValue(*c);
if (escape == -1)
continue;
+ // ### Qt 7: do not allow anything but ASCII digits
+ // in arg()'s replacements.
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ const QChar *escapeBegin = c;
+ const QChar *escapeEnd = escapeBegin + 1;
+#endif
+
++c;
if (c != uc_end) {
- int next_escape = c->digitValue();
+ const int next_escape = qArgDigitValue(*c);
if (next_escape != -1) {
escape = (10 * escape) + next_escape;
++c;
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ ++escapeEnd;
+#endif
}
}
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ checkArgEscape(QStringView(escapeBegin, escapeEnd));
+#endif
+
if (escape > d.min_escape)
continue;
@@ -7616,101 +8593,85 @@ static ArgEscapeData findArgEscapes(QStringView s)
return d;
}
-static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, int field_width,
+static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetype field_width,
QStringView arg, QStringView larg, QChar fillChar)
{
- const QChar *uc_begin = s.begin();
- const QChar *uc_end = s.end();
-
- int abs_field_width = qAbs(field_width);
- int 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());
+ // Negative field-width for right-padding, positive for left-padding:
+ const qsizetype abs_field_width = qAbs(field_width);
+ const qsizetype result_len =
+ 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 *result_buff = (QChar*) result.unicode();
+ QChar *rc = const_cast<QChar *>(result.unicode());
+ QChar *const result_end = rc + result_len;
+ qsizetype repl_cnt = 0;
- QChar *rc = result_buff;
- const QChar *c = uc_begin;
- int repl_cnt = 0;
+ const QChar *c = s.begin();
+ const QChar *const uc_end = s.end();
while (c != uc_end) {
- /* We don't have to check if we run off the end of the string with c,
- because as long as d.occurrences > 0 we KNOW there are valid escape
- sequences. */
+ Q_ASSERT(d.occurrences > repl_cnt);
+ /* We don't have to check increments of c against uc_end because, as
+ long as d.occurrences > repl_cnt, we KNOW there are valid escape
+ sequences remaining. */
const QChar *text_start = c;
-
while (c->unicode() != '%')
++c;
const QChar *escape_start = c++;
-
- bool locale_arg = false;
- if (c->unicode() == 'L') {
- locale_arg = true;
+ const bool localize = c->unicode() == 'L';
+ if (localize)
++c;
- }
- int escape = c->digitValue();
- if (escape != -1) {
- if (c + 1 != uc_end && (c + 1)->digitValue() != -1) {
- escape = (10 * escape) + (c + 1)->digitValue();
+ int escape = qArgDigitValue(*c);
+ if (escape != -1 && c + 1 != uc_end) {
+ const int digit = qArgDigitValue(c[1]);
+ if (digit != -1) {
++c;
+ escape = 10 * escape + digit;
}
}
if (escape != d.min_escape) {
- memcpy(rc, text_start, (c - text_start)*sizeof(QChar));
+ memcpy(rc, text_start, (c - text_start) * sizeof(QChar));
rc += c - text_start;
- }
- else {
+ } else {
++c;
- memcpy(rc, text_start, (escape_start - text_start)*sizeof(QChar));
+ memcpy(rc, text_start, (escape_start - text_start) * sizeof(QChar));
rc += escape_start - text_start;
- uint pad_chars;
- if (locale_arg)
- pad_chars = qMax(abs_field_width, larg.length()) - larg.length();
- else
- pad_chars = qMax(abs_field_width, arg.length()) - arg.length();
+ const QStringView use = localize ? larg : arg;
+ 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 (uint i = 0; i < pad_chars; ++i)
- *rc++ = fillChar;
+ rc = std::fill_n(rc, pad_chars, fillChar);
}
- if (locale_arg) {
- memcpy(rc, larg.data(), larg.length()*sizeof(QChar));
- rc += larg.length();
- }
- else {
- memcpy(rc, arg.data(), arg.length()*sizeof(QChar));
- rc += arg.length();
- }
+ if (use.size())
+ memcpy(rc, use.data(), use.size() * sizeof(QChar));
+ rc += use.size();
if (field_width < 0) { // right padded
- for (uint i = 0; i < pad_chars; ++i)
- *rc++ = fillChar;
+ rc = std::fill_n(rc, pad_chars, fillChar);
}
if (++repl_cnt == d.occurrences) {
- memcpy(rc, c, (uc_end - c)*sizeof(QChar));
+ memcpy(rc, c, (uc_end - c) * sizeof(QChar));
rc += uc_end - c;
- Q_ASSERT(rc - result_buff == result_len);
+ Q_ASSERT(rc == result_end);
c = uc_end;
}
}
}
- Q_ASSERT(rc == result_buff + result_len);
+ Q_ASSERT(rc == result_end);
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.
@@ -7744,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
@@ -7795,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
@@ -7814,109 +8774,12 @@ QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
is printed and the result is undefined. Place-marker numbers must be
in the range 1 to 99.
*/
-QString QString::arg(QLatin1String 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);
}
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2) const
- \overload arg()
-
- This is the same as \c {str.arg(a1).arg(a2)}, except that the
- strings \a a1 and \a a2 are replaced in one pass. This can make a
- difference if \a a1 contains e.g. \c{%1}:
-
- \snippet qstring/main.cpp 13
-
- A similar problem occurs when the numbered place markers are not
- white space separated:
-
- \snippet qstring/main.cpp 12
- \snippet qstring/main.cpp 97
-
- Let's look at the substitutions:
- \list
- \li First, \c Hello replaces \c {%1} so the string becomes \c {"Hello%3%2"}.
- \li Then, \c 20 replaces \c {%2} so the string becomes \c {"Hello%320"}.
- \li Since the maximum numbered place marker value is 99, \c 50 replaces \c {%32}.
- \endlist
- Thus the string finally becomes \c {"Hello500"}.
-
- In such cases, the following yields the expected results:
-
- \snippet qstring/main.cpp 12
- \snippet qstring/main.cpp 98
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3) const
- \overload arg()
-
- This is the same as calling \c str.arg(a1).arg(a2).arg(a3), except
- that the strings \a a1, \a a2 and \a a3 are replaced in one pass.
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4) const
- \overload arg()
-
- This is the same as calling \c
- {str.arg(a1).arg(a2).arg(a3).arg(a4)}, except that the strings \a
- a1, \a a2, \a a3 and \a a4 are replaced in one pass.
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4, const QString& a5) const
- \overload arg()
-
- This is the same as calling \c
- {str.arg(a1).arg(a2).arg(a3).arg(a4).arg(a5)}, except that the strings
- \a a1, \a a2, \a a3, \a a4, and \a a5 are replaced in one pass.
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4, const QString& a5, const QString& a6) const
- \overload arg()
-
- This is the same as calling \c
- {str.arg(a1).arg(a2).arg(a3).arg(a4).arg(a5).arg(a6))}, except that
- the strings \a a1, \a a2, \a a3, \a a4, \a a5, and \a a6 are
- replaced in one pass.
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4, const QString& a5, const QString& a6, const QString& a7) const
- \overload arg()
-
- This is the same as calling \c
- {str.arg(a1).arg(a2).arg(a3).arg(a4).arg(a5).arg(a6).arg(a7)},
- except that the strings \a a1, \a a2, \a a3, \a a4, \a a5, \a a6,
- and \a a7 are replaced in one pass.
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4, const QString& a5, const QString& a6, const QString& a7, const QString& a8) const
- \overload arg()
-
- This is the same as calling \c
- {str.arg(a1).arg(a2).arg(a3).arg(a4).arg(a5).arg(a6).arg(a7).arg(a8)},
- except that the strings \a a1, \a a2, \a a3, \a a4, \a a5, \a a6, \a
- a7, and \a a8 are replaced in one pass.
-*/
-
-/*!
- \fn QString QString::arg(const QString& a1, const QString& a2, const QString& a3, const QString& a4, const QString& a5, const QString& a6, const QString& a7, const QString& a8, const QString& a9) const
- \overload arg()
-
- This is the same as calling \c
- {str.arg(a1).arg(a2).arg(a3).arg(a4).arg(a5).arg(a6).arg(a7).arg(a8).arg(a9)},
- except that the strings \a a1, \a a2, \a a3, \a a4, \a a5, \a a6, \a
- a7, \a a8, and \a a9 are replaced in one pass.
-*/
-
/*! \fn QString QString::arg(int a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
@@ -7932,15 +8795,13 @@ QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
The '%' can be followed by an 'L', in which case the sequence is
replaced with a localized representation of \a a. The conversion
uses the default locale, set by QLocale::setDefault(). If no default
- locale was specified, the "C" locale is used. The 'L' flag is
+ locale was specified, the system locale is used. The 'L' flag is
ignored if \a base is not 10.
\snippet qstring/main.cpp 12
\snippet qstring/main.cpp 14
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
/*! \fn QString QString::arg(uint a, int fieldWidth, int base, QChar fillChar) const
@@ -7949,9 +8810,7 @@ QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
The \a base argument specifies the base to use when converting the
integer \a a into a string. The base must be between 2 and 36.
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
/*! \fn QString QString::arg(long a, int fieldWidth, int base, QChar fillChar) const
@@ -7975,12 +8834,11 @@ QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
\snippet qstring/main.cpp 12
\snippet qstring/main.cpp 14
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
-/*! \fn QString QString::arg(ulong a, int fieldWidth, int base, QChar fillChar) const
+/*!
+ \fn QString QString::arg(ulong a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
\a fieldWidth specifies the minimum amount of space that \a a is
@@ -7992,9 +8850,7 @@ QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
integer \a a to a string. The base must be between 2 and 36, with 8
giving octal, 10 decimal, and 16 hexadecimal numbers.
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
/*!
@@ -8009,9 +8865,7 @@ QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
integer \a a into a string. The base must be between 2 and 36, with
8 giving octal, 10 decimal, and 16 hexadecimal numbers.
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
{
@@ -8023,22 +8877,26 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
}
unsigned flags = QLocaleData::NoFlags;
- if (fillChar == QLatin1Char('0'))
+ // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
+ if (fillChar == u'0')
flags = QLocaleData::ZeroPadded;
QString arg;
- if (d.occurrences > d.locale_occurrences)
+ if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->longLongToString(a, -1, base, fieldWidth, flags);
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= arg.size());
+ }
- QString locale_arg;
+ QString localeArg;
if (d.locale_occurrences > 0) {
QLocale locale;
if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
- flags |= QLocaleData::ThousandsGroup;
- locale_arg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags);
+ flags |= QLocaleData::GroupDigits;
+ localeArg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags);
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= localeArg.size());
}
- return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar);
+ return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
}
/*!
@@ -8053,9 +8911,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
integer \a a into a string. \a base must be between 2 and 36, with 8
giving octal, 10 decimal, and 16 hexadecimal numbers.
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) const
{
@@ -8067,22 +8923,26 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
}
unsigned flags = QLocaleData::NoFlags;
- if (fillChar == QLatin1Char('0'))
+ // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
+ if (fillChar == u'0')
flags = QLocaleData::ZeroPadded;
QString arg;
- if (d.occurrences > d.locale_occurrences)
+ if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->unsLongLongToString(a, -1, base, fieldWidth, flags);
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= arg.size());
+ }
- QString locale_arg;
+ QString localeArg;
if (d.locale_occurrences > 0) {
QLocale locale;
if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
- flags |= QLocaleData::ThousandsGroup;
- locale_arg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags);
+ flags |= QLocaleData::GroupDigits;
+ localeArg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags);
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= localeArg.size());
}
- return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar);
+ return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
}
/*!
@@ -8099,9 +8959,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
integer \a a into a string. The base must be between 2 and 36, with
8 giving octal, 10 decimal, and 16 hexadecimal numbers.
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
/*!
@@ -8117,9 +8975,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
integer \a a into a string. The base must be between 2 and 36, with
8 giving octal, 10 decimal, and 16 hexadecimal numbers.
- If \a fillChar is '0' (the number 0, ASCII 48), the locale's zero is
- used. For negative numbers, zero padding might appear before the
- minus sign.
+ \sa {Number Formats}
*/
/*!
@@ -8141,11 +8997,10 @@ QString QString::arg(char a, int fieldWidth, QChar fillChar) const
}
/*!
- \fn QString QString::arg(double a, int fieldWidth, char format, int precision, QChar fillChar) const
\overload arg()
Argument \a a is formatted according to the specified \a format and
- \a precision. See \l{Argument Formats} for details.
+ \a precision. See \l{Floating-point Formats} for details.
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
@@ -8154,18 +9009,9 @@ QString QString::arg(char a, int fieldWidth, QChar fillChar) const
\snippet code/src_corelib_text_qstring.cpp 2
- The '%' can be followed by an 'L', in which case the sequence is
- replaced with a localized representation of \a a. The conversion
- uses the default locale, set by QLocale::setDefault(). If no
- default locale was specified, the "C" locale is used.
-
- If \a fillChar is '0' (the number 0, ASCII 48), this function will
- use the locale's zero to pad. For negative numbers, the zero padding
- will probably appear before the minus sign.
-
- \sa QLocale::toString()
+ \sa QLocale::toString(), QLocale::FloatingPointPrecisionOption, {Number Formats}
*/
-QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillChar) const
+QString QString::arg(double a, int fieldWidth, char format, int precision, QChar fillChar) const
{
ArgEscapeData d = findArgEscapes(*this);
@@ -8175,14 +9021,15 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
}
unsigned flags = QLocaleData::NoFlags;
- if (fillChar == QLatin1Char('0'))
+ // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
+ if (fillChar == u'0')
flags |= QLocaleData::ZeroPadded;
- if (qIsUpper(fmt))
+ if (isAsciiUpper(format))
flags |= QLocaleData::CapitalEorX;
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- switch (qToLower(fmt)) {
+ switch (QtMiscUtils::toAsciiLower(format)) {
case 'f':
form = QLocaleData::DFDecimal;
break;
@@ -8194,58 +9041,63 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
break;
default:
#if defined(QT_CHECK_RANGE)
- qWarning("QString::arg: Invalid format char '%c'", fmt);
+ qWarning("QString::arg: Invalid format char '%c'", format);
#endif
break;
}
QString arg;
- if (d.occurrences > d.locale_occurrences)
- arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags | QLocaleData::ZeroPadExponent);
+ if (d.occurrences > d.locale_occurrences) {
+ arg = QLocaleData::c()->doubleToString(a, precision, form, fieldWidth,
+ flags | QLocaleData::ZeroPadExponent);
+ Q_ASSERT(fillChar != u'0' || !qt_is_finite(a)
+ || fieldWidth <= arg.size());
+ }
- QString locale_arg;
+ QString localeArg;
if (d.locale_occurrences > 0) {
QLocale locale;
const QLocale::NumberOptions numberOptions = locale.numberOptions();
if (!(numberOptions & QLocale::OmitGroupSeparator))
- flags |= QLocaleData::ThousandsGroup;
+ flags |= QLocaleData::GroupDigits;
if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
flags |= QLocaleData::AddTrailingZeroes;
- locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags);
+ localeArg = locale.d->m_data->doubleToString(a, precision, form, fieldWidth, flags);
+ Q_ASSERT(fillChar != u'0' || !qt_is_finite(a)
+ || fieldWidth <= localeArg.size());
}
- return replaceArgEscapes(*this, d, fieldWidth, arg, locale_arg, fillChar);
+ return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
}
static inline char16_t to_unicode(const QChar c) { return c.unicode(); }
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)
+static int getEscape(const Char *uc, qsizetype *pos, qsizetype len)
{
- int i = *pos;
+ qsizetype i = *pos;
++i;
- if (i < len && uc[i] == QLatin1Char('L'))
+ if (i < len && uc[i] == u'L')
++i;
if (i < len) {
int escape = to_unicode(uc[i]) - '0';
if (uint(escape) >= 10U)
return -1;
++i;
- while (i < len) {
+ if (i < len) {
+ // there's a second digit
int digit = to_unicode(uc[i]) - '0';
- if (uint(digit) >= 10U)
- break;
- escape = (escape * 10) + digit;
- ++i;
- }
- if (escape <= maxNumber) {
- *pos = i;
- return escape;
+ if (uint(digit) < 10U) {
+ escape = (escape * 10) + digit;
+ ++i;
+ }
}
+ *pos = i;
+ return escape;
}
return -1;
}
@@ -8263,7 +9115,7 @@ static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumbe
the int contains the numerical number as parsed from the placeholder.
3. Next, collect all the non-negative ints found, sort them in ascending order and
remove duplicates.
- 3a. If the result has more entires than multiArg() was given replacement strings,
+ 3a. If the result has more entries than multiArg() was given replacement strings,
we have found placeholders we can't satisfy with replacement strings. That is
fine (there could be another .arg() call coming after this one), so just
truncate the result to the number of actual multiArg() replacement strings.
@@ -8288,13 +9140,13 @@ namespace {
struct Part
{
Part() = default; // for QVarLengthArray; do not use
- Q_DECL_CONSTEXPR Part(QStringView s, int num = -1)
+ constexpr Part(QStringView s, int num = -1)
: tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {}
- Q_DECL_CONSTEXPR Part(QLatin1String s, int num = -1)
+ constexpr Part(QLatin1StringView s, int num = -1)
: tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {}
void reset(QStringView s) noexcept { *this = {s, number}; }
- void reset(QLatin1String s) noexcept { *this = {s, number}; }
+ void reset(QLatin1StringView s) noexcept { *this = {s, number}; }
QtPrivate::ArgBase::Tag tag;
int number;
@@ -8324,13 +9176,13 @@ static ParseResult parseMultiArgFormatString(StringView s)
qsizetype last = 0;
while (i < end) {
- if (uc[i] == QLatin1Char('%')) {
+ if (uc[i] == u'%') {
qsizetype percent = i;
int number = getEscape(uc, &i, len);
if (number != -1) {
if (last != percent)
- result.push_back(Part{s.mid(last, percent - last)}); // literal text (incl. failed placeholders)
- result.push_back(Part{s.mid(percent, i - percent), number}); // parsed placeholder
+ result.push_back(Part{s.sliced(last, percent - last)}); // literal text (incl. failed placeholders)
+ result.push_back(Part{s.sliced(percent, i - percent), number}); // parsed placeholder
last = i;
continue;
}
@@ -8339,7 +9191,7 @@ static ParseResult parseMultiArgFormatString(StringView s)
}
if (last < len)
- result.push_back(Part{s.mid(last, len - last)}); // trailing literal text
+ result.push_back(Part{s.sliced(last, len - last)}); // trailing literal text
return result;
}
@@ -8348,7 +9200,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);
}
@@ -8389,7 +9241,7 @@ static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const A
} // unnamed namespace
-Q_ALWAYS_INLINE QString to_string(QLatin1String s) noexcept { return s; }
+Q_ALWAYS_INLINE QString to_string(QLatin1StringView s) noexcept { return s; }
Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); }
template <typename StringView>
@@ -8402,7 +9254,7 @@ static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPriv
ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);
if (static_cast<size_t>(argIndexToPlaceholderMap.size()) > numArgs) // 3a
- argIndexToPlaceholderMap.resize(int(numArgs));
+ argIndexToPlaceholderMap.resize(qsizetype(numArgs));
else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b
qWarning("QString::arg: %d argument(s) missing in %ls",
int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern)));
@@ -8414,7 +9266,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) {
@@ -8441,36 +9293,16 @@ QString QtPrivate::argToQString(QStringView pattern, size_t n, const ArgBase **a
return argToQStringImpl(pattern, n, args);
}
-QString QtPrivate::argToQString(QLatin1String pattern, size_t n, const ArgBase **args)
+QString QtPrivate::argToQString(QLatin1StringView pattern, size_t n, const ArgBase **args)
{
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.
- \sa QStringRef::isRightToLeft()
+ \sa QStringView::isRightToLeft()
*/
bool QString::isRightToLeft() const
{
@@ -8568,6 +9400,38 @@ bool QString::isRightToLeft() const
Appends the given \a ch character onto the end of this string.
*/
+/*!
+ \since 6.1
+
+ Removes from the string the characters in the half-open range
+ [ \a first , \a last ). Returns an iterator to the character
+ 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)
+{
+ const auto start = std::distance(cbegin(), first);
+ const auto len = std::distance(first, last);
+ remove(start, len);
+ 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
@@ -8615,16 +9479,9 @@ bool QString::isRightToLeft() const
\sa fromUtf16(), setRawData()
*/
-QString QString::fromRawData(const QChar *unicode, int size)
+QString QString::fromRawData(const QChar *unicode, qsizetype size)
{
- QString::DataPointer x;
- if (!unicode) {
- } else if (!size) {
- x = DataPointer(Data::allocate(0), 0);
- } else {
- x = Data::fromRawData(reinterpret_cast<const char16_t *>(unicode), size);
- }
- return QString(x);
+ return QString(DataPointer::fromRawData(const_cast<char16_t *>(reinterpret_cast<const char16_t *>(unicode)), size));
}
/*!
@@ -8641,7 +9498,7 @@ QString QString::fromRawData(const QChar *unicode, int size)
\sa fromRawData()
*/
-QString &QString::setRawData(const QChar *unicode, int size)
+QString &QString::setRawData(const QChar *unicode, qsizetype size)
{
if (!unicode || !size) {
clear();
@@ -8653,8 +9510,7 @@ QString &QString::setRawData(const QChar *unicode, int 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()
*/
@@ -8673,8 +9529,7 @@ QString &QString::setRawData(const QChar *unicode, int 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()
*/
@@ -8690,872 +9545,7 @@ QString &QString::setRawData(const QChar *unicode, int size)
\sa toUcs4(), toStdWString(), toStdU16String()
*/
-/*! \class QLatin1String
- \inmodule QtCore
- \brief The QLatin1String 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 \c 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 QLatin1String, which is
- just a very thin wrapper around a \c{const char *}. Using
- QLatin1String, 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(QLatin1String) constructor,
- QLatin1String 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 QLatin1String
- argument isn't actually overloaded to take QLatin1String, the
- implicit conversion to QString will trigger a memory allocation,
- which is usually what you want to avoid by using QLatin1String
- in the first place. In those cases, using QStringLiteral may be
- the better option.
-
- \sa QString, QLatin1Char, {QStringLiteral()}{QStringLiteral}, QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \typedef QLatin1String::value_type
- \since 5.10
-
- Alias for \c{const char}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1String::difference_type
- \since 5.10
-
- Alias for \c{int}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1String::size_type
- \since 5.10
-
- Alias for \c{int}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1String::reference
- \since 5.10
-
- Alias for \c{value_type &}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1String::const_reference
- \since 5.11
-
- Alias for \c{reference}. Provided for compatibility with the STL.
-*/
-
-/*!
- \typedef QLatin1String::iterator
- \since 5.10
-
- QLatin1String does not support mutable iterators, so this is the same
- as const_iterator.
-
- \sa const_iterator, reverse_iterator
-*/
-
-/*!
- \typedef QLatin1String::const_iterator
- \since 5.10
-
- \sa iterator, const_reverse_iterator
-*/
-
-/*!
- \typedef QLatin1String::reverse_iterator
- \since 5.10
-
- QLatin1String does not support mutable reverse iterators, so this is the
- same as const_reverse_iterator.
-
- \sa const_reverse_iterator, iterator
-*/
-
-/*!
- \typedef QLatin1String::const_reverse_iterator
- \since 5.10
-
- \sa reverse_iterator, const_iterator
-*/
-
-/*! \fn QLatin1String::QLatin1String()
- \since 5.6
-
- Constructs a QLatin1String object that stores a nullptr.
-*/
-
-/*! \fn QLatin1String::QLatin1String(const char *str)
-
- Constructs a QLatin1String 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 QLatin1String object exists.
-
- \sa latin1()
-*/
-
-/*! \fn QLatin1String::QLatin1String(const char *str, int size)
-
- Constructs a QLatin1String 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 QLatin1String object exists.
-
- \sa latin1()
-*/
-
-/*!
- \fn QLatin1String::QLatin1String(const char *first, const char *last)
- \since 5.10
-
- Constructs a QLatin1String 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 QLatin1String::QLatin1String(const QByteArray &str)
-
- Constructs a QLatin1String 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 QLatin1String object exists.
-
- \sa latin1()
-*/
-
-/*!
- \fn QLatin1String::toString() const
- \since 6.0
-
- Converts this Latin-1 string into a QString. Equivalent to
- \code
- return QString(*this);
- \endcode
-*/
-
-/*! \fn const char *QLatin1String::latin1() const
-
- Returns the Latin-1 string stored in this object.
-*/
-
-/*! \fn const char *QLatin1String::data() const
-
- Returns the Latin-1 string stored in this object.
-*/
-
-/*! \fn int QLatin1String::size() const
-
- Returns the size of the Latin-1 string stored in this object.
-*/
-
-/*! \fn bool QLatin1String::isNull() const
- \since 5.10
-
- Returns whether the Latin-1 string stored in this object is null
- (\c{data() == nullptr}) or not.
-
- \sa isEmpty(), data()
-*/
-
-/*! \fn bool QLatin1String::isEmpty() const
- \since 5.10
-
- Returns whether the Latin-1 string stored in this object is empty
- (\c{size() == 0}) or not.
-
- \sa isNull(), size()
-*/
-
-/*! \fn QLatin1Char QLatin1String::at(int 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 QLatin1String::operator[](int 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 QLatin1String::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 QLatin1String::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 int QLatin1String::compare(QStringView str, Qt::CaseSensitivity cs) const
- \fn int QLatin1String::compare(QLatin1String l1, Qt::CaseSensitivity cs) const
- \fn int QLatin1String::compare(QChar ch) const
- \fn int QLatin1String::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 QLatin1String::startsWith(QStringView str, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1String::startsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1String::startsWith(QChar ch) const
- \since 5.10
- \fn bool QLatin1String::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 QLatin1String::endsWith(QStringView str, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1String::endsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
- \since 5.10
- \fn bool QLatin1String::endsWith(QChar ch) const
- \since 5.10
- \fn bool QLatin1String::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 int QLatin1String::indexOf(QStringView str, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \fn int QLatin1String::indexOf(QLatin1String l1, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \fn int QLatin1String::indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 5.14
-
- Returns the index position of the first occurrence of the string-view \a str,
- Latin-1 string \a l1, or character \a ch, respectively, in this Latin-1 string,
- searching forward from index position \a from. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- If \a from is -1, the search starts at the last character; if it is
- -2, at the next to last character and so on.
-
- \sa QString::indexOf()
-*/
-
-/*!
- \fn bool QLatin1String::contains(QStringView str, Qt::CaseSensitivity cs) const
- \fn bool QLatin1String::contains(QLatin1String l1, Qt::CaseSensitivity cs) const
- \fn bool QLatin1String::contains(QChar c, Qt::CaseSensitivity cs) const
- \since 5.14
-
- Returns \c true if this Latin-1 string contains an occurrence of the string-view
- \a str, Latin-1 string \a l1, or character \a ch; otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (the default), the search is
- case-sensitive; otherwise the search is case-insensitive.
-
- \sa indexOf(), QStringView::contains(), QStringView::indexOf(), QString::indexOf()
-*/
-
-/*!
- \fn int QLatin1String::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
- \fn int QLatin1String::lastIndexOf(QLatin1String l1, int from, Qt::CaseSensitivity cs) const
- \fn int QLatin1String::lastIndexOf(QChar c, int from, Qt::CaseSensitivity cs) const
- \since 5.14
-
- Returns the index position of the last occurrence of the string-view \a str,
- Latin-1 string \a l1, or character \a ch, respectively, in this Latin-1 string,
- searching backward from index position \a from. If \a from is -1 (default),
- the search starts at the last character; if \a from is -2, at the next to last
- character and so on. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa indexOf(), QStringView::lastIndexOf(), QStringView::indexOf(), QString::indexOf()
-*/
-
-/*!
- \fn QLatin1String::const_iterator QLatin1String::begin() const
- \since 5.10
-
- 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 QLatin1String::const_iterator QLatin1String::cbegin() const
- \since 5.10
-
- Same as begin().
-
- This function is provided for STL compatibility.
-
- \sa cend(), begin(), crbegin(), data()
-*/
-
-/*!
- \fn QLatin1String::const_iterator QLatin1String::end() const
- \since 5.10
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- character after the last character in the list.
-
- This function is provided for STL compatibility.
-
- \sa begin(), cend(), rend()
-*/
-
-/*! \fn QLatin1String::const_iterator QLatin1String::cend() const
- \since 5.10
-
- Same as end().
-
- This function is provided for STL compatibility.
-
- \sa cbegin(), end(), crend()
-*/
-
-/*!
- \fn QLatin1String::const_reverse_iterator QLatin1String::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 QLatin1String::const_reverse_iterator QLatin1String::crbegin() const
- \since 5.10
-
- Same as rbegin().
-
- This function is provided for STL compatibility.
-
- \sa crend(), rbegin(), cbegin()
-*/
-
-/*!
- \fn QLatin1String::const_reverse_iterator QLatin1String::rend() const
- \since 5.10
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last character in the string, in reverse order.
-
- This function is provided for STL compatibility.
-
- \sa rbegin(), crend(), end()
-*/
-
-/*!
- \fn QLatin1String::const_reverse_iterator QLatin1String::crend() const
- \since 5.10
-
- Same as rend().
-
- This function is provided for STL compatibility.
-
- \sa crbegin(), rend(), cend()
-*/
-
-/*! \fn QLatin1String QLatin1String::mid(int start, int length) const
- \since 5.8
-
- Returns the substring of length \a length starting at position
- \a start in this object.
-
- Returns a null string if the \a start index exceeds the
- length of the string. If there are less than \a length characters
- available in the string starting at \a start, or if
- \a length is negative (default), the function returns all characters
- that are available from \a start.
-
- \sa left(), right(), chopped(), chop(), truncate()
-*/
-
-/*! \fn QLatin1String QLatin1String::left(int length) const
- \since 5.8
-
- Returns the substring of length \a length starting at position
- 0 in this object.
-
- The entire string is returned if \a length is greater than or equal
- to size(), or less than zero.
-
- \sa mid(), right(), chopped(), chop(), truncate()
-*/
-
-/*! \fn QLatin1String QLatin1String::right(int length) const
- \since 5.8
-
- Returns the substring of length \a length starting at position
- size() - \a length in this object.
-
- The entire string is returned if \a length is greater than or equal
- to size(), or less than zero.
-
- \sa mid(), left(), chopped(), chop(), truncate()
-*/
-
-/*!
- \fn QLatin1String QLatin1String::chopped(int 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 mid(), left(), right(), chop(), truncate()
-*/
-
-/*!
- \fn void QLatin1String::truncate(int 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 mid(), left(), right(), chopped(), chop()
-*/
-
-/*!
- \fn void QLatin1String::chop(int 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 mid(), left(), right(), chopped(), truncate()
-*/
-
-/*!
- \fn QLatin1String QLatin1String::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 QLatin1String::operator==(const QString &other) const
-
- Returns \c true if this string is equal to string \a other;
- otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- QString::localeAwareCompare().
-*/
-
-/*!
- \fn bool QLatin1String::operator==(const char *other) const
- \since 4.3
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator==(const 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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*! \fn bool QLatin1String::operator!=(const QString &other) const
-
- Returns \c true if this string is not equal to string \a other;
- otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- QString::localeAwareCompare().
-*/
-
-/*!
- \fn bool QLatin1String::operator!=(const char *other) const
- \since 4.3
- \overload operator!=()
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator!=(const 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 \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator>(const QString &other) const
-
- Returns \c true if this string is lexically greater than string \a
- other; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- QString::localeAwareCompare().
-*/
-
-/*!
- \fn bool QLatin1String::operator>(const char *other) const
- \since 4.3
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII
- when you compile your applications. This can be useful if you want
- to ensure that all user-visible strings go through QObject::tr(),
- for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator>(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII
- when you compile your applications. This can be useful if you want
- to ensure that all user-visible strings go through QObject::tr(),
- for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator<(const QString &other) const
-
- Returns \c true if this string is lexically less than the \a other
- string; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
-*/
-
-/*!
- \fn bool QLatin1String::operator<(const char *other) const
- \since 4.3
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator<(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator>=(const QString &other) const
-
- Returns \c true if this string is lexically greater than or equal
- to string \a other; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- QString::localeAwareCompare().
-*/
-
-/*!
- \fn bool QLatin1String::operator>=(const char *other) const
- \since 4.3
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator>=(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*! \fn bool QLatin1String::operator<=(const QString &other) const
-
- Returns \c true if this string is lexically less than or equal
- to string \a other; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings with
- QString::localeAwareCompare().
-*/
-
-/*!
- \fn bool QLatin1String::operator<=(const char *other) const
- \since 4.3
- \overload
-
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QLatin1String::operator<=(const QByteArray &other) const
- \since 5.0
- \overload
-
- The \a other array is converted to a QString using
- the QString::fromUtf8() function.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. This
- can be useful if you want to ensure that all user-visible strings
- go through QObject::tr(), for example.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-
-/*! \fn bool operator==(QLatin1String s1, QLatin1String s2)
- \relates QLatin1String
-
- Returns \c true if string \a s1 is lexically equal to string \a s2; otherwise
- returns \c false.
-*/
-/*! \fn bool operator!=(QLatin1String s1, QLatin1String s2)
- \relates QLatin1String
-
- Returns \c true if string \a s1 is lexically unequal to string \a s2; otherwise
- returns \c false.
-*/
-/*! \fn bool operator<(QLatin1String s1, QLatin1String s2)
- \relates QLatin1String
-
- Returns \c true if string \a s1 is lexically smaller than string \a s2; otherwise
- returns \c false.
-*/
-/*! \fn bool operator<=(QLatin1String s1, QLatin1String s2)
- \relates QLatin1String
-
- Returns \c true if string \a s1 is lexically smaller than or equal to string \a s2; otherwise
- returns \c false.
-*/
-/*! \fn bool operator>(QLatin1String s1, QLatin1String s2)
- \relates QLatin1String
-
- Returns \c true if string \a s1 is lexically greater than string \a s2; otherwise
- returns \c false.
-*/
-/*! \fn bool operator>=(QLatin1String s1, QLatin1String s2)
- \relates QLatin1String
-
- Returns \c true if string \a s1 is lexically greater than or equal to
- string \a s2; otherwise returns \c false.
-*/
-
-
-#if !defined(QT_NO_DATASTREAM) || (defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE))
+#if !defined(QT_NO_DATASTREAM)
/*!
\fn QDataStream &operator<<(QDataStream &stream, const QString &string)
\relates QString
@@ -9572,15 +9562,16 @@ QDataStream &operator<<(QDataStream &out, const QString &str)
} else {
if (!str.isNull() || out.version() < 3) {
if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
- out.writeBytes(reinterpret_cast<const char *>(str.unicode()), uint(sizeof(QChar) * str.length()));
+ out.writeBytes(reinterpret_cast<const char *>(str.unicode()),
+ static_cast<qsizetype>(sizeof(QChar) * str.size()));
} else {
- QVarLengthArray<char16_t> buffer(str.length());
- qbswap<sizeof(char16_t)>(str.constData(), str.length(), buffer.data());
- out.writeBytes(reinterpret_cast<const char *>(buffer.data()), uint(sizeof(char16_t) * buffer.size()));
+ 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<qsizetype>(sizeof(char16_t) * buffer.size()));
}
} else {
- // write null marker
- out << (quint32)0xffffffff;
+ QDataStream::writeQSizeType(out, -1); // write null marker
}
}
return out;
@@ -9602,20 +9593,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);
@@ -9635,607 +9631,13 @@ QDataStream &operator>>(QDataStream &in, QString &str)
qbswap<sizeof(*data)>(data, len, data);
}
} else {
- str = QString(QLatin1String(""));
+ str = QString(QLatin1StringView(""));
}
}
return in;
}
#endif // QT_NO_DATASTREAM
-
-
-
-/*!
- \class QStringRef
- \inmodule QtCore
- \since 4.3
- \brief The QStringRef class provides a thin wrapper around QString substrings.
- \reentrant
- \ingroup tools
- \ingroup string-processing
-
- QStringRef provides a read-only subset of the QString API.
-
- A string reference explicitly references a portion of a string()
- with a given size(), starting at a specific position(). Calling
- toString() returns a copy of the data as a real QString instance.
-
- This class is designed to improve the performance of substring
- handling when manipulating substrings obtained from existing QString
- instances. QStringRef avoids the memory allocation and reference
- counting overhead of a standard QString by simply referencing a
- part of the original string. This can prove to be advantageous in
- low level code, such as that used in a parser, at the expense of
- potentially more complex code.
-
- For most users, there are no semantic benefits to using QStringRef
- instead of QString since QStringRef requires attention to be paid
- to memory management issues, potentially making code more complex
- to write and maintain.
-
- \warning A QStringRef is only valid as long as the referenced
- string exists. If the original string is deleted, the string
- reference points to an invalid memory location.
-
- We suggest that you only use this class in stable code where profiling
- has clearly identified that performance improvements can be made by
- replacing standard string operations with the optimized substring
- handling provided by this class.
-
- \sa {Implicitly Shared Classes}
-*/
-
-/*!
- \typedef QStringRef::size_type
- \internal
-*/
-
-/*!
- \typedef QStringRef::value_type
- \internal
-*/
-
-/*!
- \typedef QStringRef::const_pointer
- \internal
-*/
-
-/*!
- \typedef QStringRef::const_reference
- \internal
-*/
-
-/*!
- \typedef QStringRef::const_iterator
- \since 5.4
-
- \sa QStringRef::const_reverse_iterator
-*/
-
-/*!
- \typedef QStringRef::const_reverse_iterator
- \since 5.7
-
- \sa QStringRef::const_iterator
-*/
-
-/*!
- \fn QStringRef::QStringRef()
-
- Constructs an empty string reference.
-*/
-
-/*! \fn QStringRef::QStringRef(const QString *string, int position, int length)
-
-Constructs a string reference to the range of characters in the given
-\a string specified by the starting \a position and \a length in characters.
-
-\warning This function exists to improve performance as much as possible,
-and performs no bounds checking. For program correctness, \a position and
-\a length must describe a valid substring of \a string.
-
-This means that the starting \a position must be positive or 0 and smaller
-than \a string's length, and \a length must be positive or 0 but smaller than
-the string's length minus the starting \a position;
-i.e, 0 <= position < string->length() and
-0 <= length <= string->length() - position must both be satisfied.
-*/
-
-/*! \fn QStringRef::QStringRef(const QString *string)
-
-Constructs a string reference to the given \a string.
-*/
-
-/*! \fn QStringRef::QStringRef(const QStringRef &other)
-
-Constructs a copy of the \a other string reference.
- */
-/*!
-\fn QStringRef::~QStringRef()
-
-Destroys the string reference.
-
-Since this class is only used to refer to string data, and does not take
-ownership of it, no memory is freed when instances are destroyed.
-*/
-
-/*!
- \fn int QStringRef::position() const
-
- Returns the starting position in the referenced string that is referred to
- by the string reference.
-
- \sa size(), string()
-*/
-
-/*!
- \fn int QStringRef::size() const
-
- Returns the number of characters referred to by the string reference.
- Equivalent to length() and count().
-
- \sa position(), string()
-*/
-/*!
- \fn int QStringRef::count() const
- Returns the number of characters referred to by the string reference.
- Equivalent to size() and length().
-
- \sa position(), string()
-*/
-/*!
- \fn int QStringRef::length() const
- Returns the number of characters referred to by the string reference.
- Equivalent to size() and count().
-
- \sa position(), string()
-*/
-
-
-/*!
- \fn bool QStringRef::isEmpty() const
-
- Returns \c true if the string reference has no characters; otherwise returns
- \c false.
-
- A string reference is empty if its size is zero.
-
- \sa size()
-*/
-
-/*!
- \fn bool QStringRef::isNull() const
-
- Returns \c true if this string reference does not reference a string or if
- the string it references is null (i.e. QString::isNull() is true).
-
- \sa size()
-*/
-
-/*!
- \fn const QString *QStringRef::string() const
-
- Returns a pointer to the string referred to by the string reference, or
- 0 if it does not reference a string.
-
- \sa unicode()
-*/
-
-
-/*!
- \fn const QChar *QStringRef::unicode() const
-
- Returns a Unicode representation of the string reference. Since
- the data stems directly from the referenced string, it is not
- \\0'-terminated unless the string reference includes the string's
- null terminator.
-
- \sa string()
-*/
-
-/*!
- \fn const QChar *QStringRef::data() const
-
- Same as unicode().
-*/
-
-/*!
- \fn const QChar *QStringRef::constData() const
-
- Same as unicode().
-*/
-
-/*!
- \fn QStringRef::const_iterator QStringRef::begin() const
- \since 5.4
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in
- the string.
-
- \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
-*/
-
-/*!
- \fn QStringRef::const_iterator QStringRef::cbegin() const
- \since 5.4
-
- Same as begin().
-
- \sa begin(), constBegin(), cend(), constEnd(), rbegin(), rend()
-*/
-
-/*!
- \fn QStringRef::const_iterator QStringRef::constBegin() const
- \since 5.9
-
- Same as begin().
-
- \sa begin(), cend(), constEnd(), rbegin(), rend()
-*/
-
-/*!
- \fn QStringRef::const_iterator QStringRef::end() const
- \since 5.4
-
- Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
- character after the last character in the list.
-
- \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
-*/
-
-/*! \fn QStringRef::const_iterator QStringRef::cend() const
- \since 5.4
-
- Same as end().
-
- \sa end(), constEnd(), cbegin(), constBegin(), rbegin(), rend()
-*/
-
-/*! \fn QStringRef::const_iterator QStringRef::constEnd() const
- \since 5.9
-
- Same as end().
-
- \sa end(), cend(), cbegin(), constBegin(), rbegin(), rend()
-*/
-
-/*!
- \fn QStringRef::const_reverse_iterator QStringRef::rbegin() const
- \since 5.7
-
- Returns a const \l{STL-style iterators}{STL-style} reverse iterator pointing to the first
- character in the string, in reverse order.
-
- \sa begin(), crbegin(), rend()
-*/
-
-/*!
- \fn QStringRef::const_reverse_iterator QStringRef::crbegin() const
- \since 5.7
-
- Same as rbegin().
-
- \sa begin(), rbegin(), rend()
-*/
-
-/*!
- \fn QStringRef::const_reverse_iterator QStringRef::rend() const
- \since 5.7
-
- Returns a \l{STL-style iterators}{STL-style} reverse iterator pointing to one past
- the last character in the string, in reverse order.
-
- \sa end(), crend(), rbegin()
-*/
-
-
-/*!
- \fn QStringRef::const_reverse_iterator QStringRef::crend() const
- \since 5.7
-
- Same as rend().
-
- \sa end(), rend(), rbegin()
-*/
-
-/*!
- Returns a copy of the string reference as a QString object.
-
- If the string reference is not a complete reference of the string
- (meaning that position() is 0 and size() equals string()->size()),
- this function will allocate a new string to return.
-
- \sa string()
-*/
-
-QString QStringRef::toString() const {
- if (isNull())
- return QString();
- if (m_size && m_position == 0 && m_size == m_string->size())
- return *m_string;
- return QString(m_string->unicode() + m_position, m_size);
-}
-
-
-/*! \relates QStringRef
-
- Returns \c true if string reference \a s1 is lexically equal to string reference \a s2; otherwise
- returns \c false.
-*/
-bool operator==(const QStringRef &s1,const QStringRef &s2) noexcept
-{
- return s1.size() == s2.size() && qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
-}
-
-/*! \relates QStringRef
-
- Returns \c true if string \a s1 is lexically equal to string reference \a s2; otherwise
- returns \c false.
-*/
-bool operator==(const QString &s1,const QStringRef &s2) noexcept
-{
- return s1.size() == s2.size() && qt_compare_strings(s1, s2, Qt::CaseSensitive) == 0;
-}
-
-/*! \relates QStringRef
-
- Returns \c true if string \a s1 is lexically equal to string reference \a s2; otherwise
- returns \c false.
-*/
-bool operator==(QLatin1String s1, const QStringRef &s2) noexcept
-{
- if (s1.size() != s2.size())
- return false;
-
- return qt_compare_strings(s2, s1, Qt::CaseSensitive) == 0;
-}
-
-/*!
- \relates QStringRef
-
- Returns \c true if string reference \a s1 is lexically less than
- string reference \a s2; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
-*/
-bool operator<(const QStringRef &s1,const QStringRef &s2) noexcept
-{
- return qt_compare_strings(s1, s2, Qt::CaseSensitive) < 0;
-}
-
-/*!\fn bool operator<=(const QStringRef &s1,const QStringRef &s2)
-
- \relates QStringRef
-
- Returns \c true if string reference \a s1 is lexically less than
- or equal to string reference \a s2; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
-*/
-
-/*!\fn bool operator>=(const QStringRef &s1,const QStringRef &s2)
-
- \relates QStringRef
-
- Returns \c true if string reference \a s1 is lexically greater than
- or equal to string reference \a s2; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
-*/
-
-/*!\fn bool operator>(const QStringRef &s1,const QStringRef &s2)
-
- \relates QStringRef
-
- Returns \c true if string reference \a s1 is lexically greater than
- string reference \a s2; otherwise returns \c false.
-
- The comparison is based exclusively on the numeric Unicode values
- of the characters and is very fast, but is not what a human would
- expect. Consider sorting user-interface strings using the
- QString::localeAwareCompare() function.
-*/
-
-
-/*!
- \fn const QChar QStringRef::at(int position) const
-
- Returns the character at the given index \a position in the
- string reference.
-
- The \a position must be a valid index position in the string
- (i.e., 0 <= \a position < size()).
-*/
-
-/*!
- \fn QChar QStringRef::operator[](int position) const
- \since 5.7
-
- Returns the character at the given index \a position in the
- string reference.
-
- The \a position must be a valid index position in the string
- reference (i.e., 0 <= \a position < size()).
-
- \sa at()
-*/
-
-/*!
- \fn QChar QStringRef::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 QChar QStringRef::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 void QStringRef::clear()
-
- Clears the contents of the string reference by making it null and empty.
-
- \sa isEmpty(), isNull()
-*/
-
-/*!
- \fn QStringRef &QStringRef::operator=(const QStringRef &other)
-
- Assigns the \a other string reference to this string reference, and
- returns the result.
-*/
-
-/*!
- \fn QStringRef &QStringRef::operator=(const QString *string)
-
- Constructs a string reference to the given \a string and assigns it to
- this string reference, returning the result.
-*/
-
-/*!
- \fn bool QStringRef::operator==(const char * s) const
-
- \overload operator==()
-
- The \a s byte array is converted to a QStringRef using the
- fromUtf8() function. This function stops conversion at the
- first NUL character found, or the end of the byte array.
-
- You can disable this operator by defining \c
- 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 s. Otherwise returns \c false.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QStringRef::operator!=(const char * s) const
-
- \overload operator!=()
-
- The \a s const char pointer is converted to a QStringRef using
- the fromUtf8() function.
-
- You can disable this operator by defining \c
- 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 not lexically equal to the parameter
- string \a s. Otherwise returns \c false.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QStringRef::operator<(const char * s) const
-
- \overload operator<()
-
- The \a s const char pointer is converted to a QStringRef using
- the fromUtf8() function.
-
- You can disable this operator by defining \c
- 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 smaller than the parameter
- string \a s. Otherwise returns \c false.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QStringRef::operator<=(const char * s) const
-
- \overload operator<=()
-
- The \a s const char pointer is converted to a QStringRef using
- the fromUtf8() function.
-
- You can disable this operator by defining \c
- 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 smaller than or equal to the parameter
- string \a s. Otherwise returns \c false.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QStringRef::operator>(const char * s) const
-
-
- \overload operator>()
-
- The \a s const char pointer is converted to a QStringRef using
- the fromUtf8() function.
-
- You can disable this operator by defining \c
- 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 greater than the parameter
- string \a s. Otherwise returns \c false.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
-
-/*!
- \fn bool QStringRef::operator>= (const char * s) const
-
- \overload operator>=()
-
- The \a s const char pointer is converted to a QStringRef using
- the fromUtf8() function.
-
- You can disable this operator by defining \c
- 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 greater than or equal to the
- parameter string \a s. Otherwise returns \c false.
-
- \sa QT_NO_CAST_FROM_ASCII
-*/
/*!
\typedef QString::Data
\internal
@@ -10251,631 +9653,6 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) noexcept
\internal
*/
-
-
-/*! Appends the string reference to \a string, and returns a new
-reference to the combined string data.
- */
-QStringRef QStringRef::appendTo(QString *string) const
-{
- if (!string)
- return QStringRef();
- int pos = string->size();
- string->insert(pos, unicode(), size());
- return QStringRef(string, pos, size());
-}
-
-/*!
- \fn int QStringRef::compare(const QStringRef &s1, const QString &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
- \since 4.5
-
- Compares the string \a s1 with the string \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.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-*/
-
-/*!
- \fn int QStringRef::compare(const QStringRef &s1, const QStringRef &s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
- \since 4.5
- \overload
-
- Compares the string \a s1 with the string \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.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-*/
-
-/*!
- \fn int QStringRef::compare(const QStringRef &s1, QLatin1String s2, Qt::CaseSensitivity cs = Qt::CaseSensitive)
- \since 4.5
- \overload
-
- Compares the string \a s1 with the string \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.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-*/
-
-/*!
- \overload
- \fn int QStringRef::compare(const QString &other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 4.5
-
- 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 \a other string.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-
- Equivalent to \c {compare(*this, other, cs)}.
-*/
-
-/*!
- \overload
- \fn int QStringRef::compare(const QStringRef &other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 4.5
-
- 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 \a other string.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-
- Equivalent to \c {compare(*this, other, cs)}.
-*/
-
-/*!
- \overload
- \fn int QStringRef::compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 5.14
-
- Compares this string with \a ch and returns an
- integer less than, equal to, or greater than zero if this string
- is less than, equal to, or greater than \a ch, interpreted as a string of length one.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-*/
-
-/*!
- \overload
- \fn int QStringRef::compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 4.5
-
- 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 \a other string.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-
- Equivalent to \c {compare(*this, other, cs)}.
-*/
-
-/*!
- \overload
- \fn int QStringRef::compare(const QByteArray &other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 5.8
-
- Compares this string with \a other and returns an
- integer less than, equal to, or greater than zero if this string
- is less than, equal to, or greater than the \a other byte array,
- interpreted as a UTF-8 sequence.
-
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
-
- Equivalent to \c {compare(*this, other, cs)}.
-*/
-
-/*!
- \fn int QStringRef::localeAwareCompare(const QStringRef &s1, const QString & s2)
- \since 4.5
-
- 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.
-
- The comparison is performed in a locale- and also
- platform-dependent manner. Use this function to present sorted
- lists of strings to the user.
-
- On \macos and iOS, this function compares according the
- "Order for sorted lists" setting in the International prefereces panel.
-
- \sa compare(), QLocale
-*/
-
-/*!
- \fn int QStringRef::localeAwareCompare(const QStringRef &s1, const QStringRef & s2)
- \since 4.5
- \overload
-
- 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.
-
- The comparison is performed in a locale- and also
- platform-dependent manner. Use this function to present sorted
- lists of strings to the user.
-
-*/
-
-/*!
- \fn int QStringRef::localeAwareCompare(const QString &other) const
- \since 4.5
- \overload
-
- 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 \a other string.
-
- The comparison is performed in a locale- and also
- platform-dependent manner. Use this function to present sorted
- lists of strings to the user.
-*/
-
-/*!
- \fn int QStringRef::localeAwareCompare(const QStringRef &other) const
- \since 4.5
- \overload
-
- 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 \a other string.
-
- The comparison is performed in a locale- and also
- platform-dependent manner. Use this function to present sorted
- lists of strings to the user.
-*/
-
-/*!
- \fn QString &QString::append(QStringView str)
- \since 6.0
-
- Appends the given string view \a str to this string and returns the result.
-*/
-
-/*!
- \fn QStringRef::left(int n) const
- \since 5.2
-
- Returns a substring reference to the \a n leftmost characters
- of the string.
-
- If \a n is greater than or equal to size(), or less than zero,
- a reference to the entire string is returned.
-
- \sa right(), mid(), startsWith(), chopped(), chop(), truncate()
-*/
-QStringRef QStringRef::left(int n) const
-{
- if (uint(n) >= uint(m_size))
- return *this;
- return QStringRef(m_string, m_position, n);
-}
-
-/*!
- \since 4.4
-
- Returns a substring reference to the \a n leftmost characters
- of the string.
-
- If \a n is greater than or equal to size(), or less than zero,
- a reference to the entire string is returned.
-
- \snippet qstring/main.cpp leftRef
-
- \sa left(), rightRef(), midRef(), startsWith()
-*/
-QStringRef QString::leftRef(int n) const
-{
- return QStringRef(this).left(n);
-}
-
-/*!
- \fn QStringRef::right(int n) const
- \since 5.2
-
- Returns a substring reference to the \a n rightmost characters
- of the string.
-
- If \a n is greater than or equal to size(), or less than zero,
- a reference to the entire string is returned.
-
- \sa left(), mid(), endsWith(), chopped(), chop(), truncate()
-*/
-QStringRef QStringRef::right(int n) const
-{
- if (uint(n) >= uint(m_size))
- return *this;
- return QStringRef(m_string, m_size - n + m_position, n);
-}
-
-/*!
- \since 4.4
-
- Returns a substring reference to the \a n rightmost characters
- of the string.
-
- If \a n is greater than or equal to size(), or less than zero,
- a reference to the entire string is returned.
-
- \snippet qstring/main.cpp rightRef
-
- \sa right(), leftRef(), midRef(), endsWith()
-*/
-QStringRef QString::rightRef(int n) const
-{
- return QStringRef(this).right(n);
-}
-
-/*!
- \fn QStringRef QStringRef::mid(int position, int n = -1) const
- \since 5.2
-
- Returns a substring reference to \a n characters of this string,
- starting at the specified \a position.
-
- If the \a position exceeds the length of the string, a null
- reference is returned.
-
- If there are less than \a n characters available in the string,
- starting at the given \a position, or if \a n is -1 (default), the
- function returns all characters from the specified \a position
- onwards.
-
- \sa left(), right(), chopped(), chop(), truncate()
-*/
-QStringRef QStringRef::mid(int pos, int n) const
-{
- qsizetype p = pos;
- qsizetype l = n;
- using namespace QtPrivate;
- switch (QContainerImplHelper::mid(m_size, &p, &l)) {
- case QContainerImplHelper::Null:
- return QStringRef();
- case QContainerImplHelper::Empty:
- return QStringRef(m_string, 0, 0);
- case QContainerImplHelper::Full:
- return *this;
- case QContainerImplHelper::Subset:
- return QStringRef(m_string, p + m_position, l);
- }
- Q_UNREACHABLE();
- return QStringRef();
-}
-
-/*!
- \fn QStringRef QStringRef::chopped(int len) const
- \since 5.10
-
- Returns a substring reference to the size() - \a len leftmost characters
- of this string.
-
- \note The behavior is undefined if \a len is negative or greater than size().
-
- \sa endsWith(), left(), right(), mid(), chop(), truncate()
-*/
-
-/*!
- \since 4.4
-
- Returns a substring reference to \a n characters of this string,
- starting at the specified \a position.
-
- If the \a position exceeds the length of the string, a null
- reference is returned.
-
- If there are less than \a n characters available in the string,
- starting at the given \a position, or if \a n is -1 (default), the
- function returns all characters from the specified \a position
- onwards.
-
- Example:
-
- \snippet qstring/main.cpp midRef
-
- \sa mid(), leftRef(), rightRef()
-*/
-QStringRef QString::midRef(int position, int n) const
-{
- return QStringRef(this).mid(position, n);
-}
-
-/*!
- \fn void QStringRef::truncate(int position)
- \since 5.6
-
- Truncates the string at the given \a position index.
-
- If the specified \a position index is beyond the end of the
- string, nothing happens.
-
- If \a position is negative, it is equivalent to passing zero.
-
- \sa QString::truncate()
-*/
-
-/*!
- \fn void QStringRef::chop(int n)
- \since 5.8
-
- Removes \a n characters from the end of the string.
-
- If \a n is greater than or equal to size(), the result is an
- empty string; if \a n is negative, it is equivalent to passing zero.
-
- \sa QString::chop(), truncate()
-*/
-
-#if QT_STRINGVIEW_LEVEL < 2
-/*!
- \since 4.8
-
- Returns the index position of the first occurrence of the string \a
- str in this string reference, searching forward from index position
- \a from. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- If \a from is -1, the search starts at the last character; if it is
- -2, at the next to last character and so on.
-
- \sa QString::indexOf(), lastIndexOf(), contains(), count()
-*/
-int QStringRef::indexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::findString(QStringView(unicode(), length()), from, QStringView(str.unicode(), str.length()), cs));
-}
-#endif // QT_STRINGVIEW_LEVEL < 2
-
-/*!
- \fn int QStringRef::indexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
- \since 5.14
- \overload indexOf()
-
- Returns the index position of the first occurrence of the string view \a str
- in this string reference, searching forward from index position \a from.
- Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- If \a from is -1, the search starts at the last character; if it is
- -2, at the next to last character and so on.
-
- \sa QString::indexOf(), QStringView::indexOf(), lastIndexOf(), contains(), count()
-*/
-
-/*!
- \since 4.8
- \overload indexOf()
-
- Returns the index position of the first occurrence of the
- character \a ch in the string reference, searching forward from
- index position \a from. Returns -1 if \a ch could not be found.
-
- \sa QString::indexOf(), lastIndexOf(), contains(), count()
-*/
-int QStringRef::indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(qFindChar(QStringView(unicode(), length()), ch, from, cs));
-}
-
-/*!
- \since 4.8
-
- Returns the index position of the first occurrence of the string \a
- str in this string reference, searching forward from index position
- \a from. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- If \a from is -1, the search starts at the last character; if it is
- -2, at the next to last character and so on.
-
- \sa QString::indexOf(), lastIndexOf(), contains(), count()
-*/
-int QStringRef::indexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::findString(QStringView(unicode(), size()), from, str, cs));
-}
-
-#if QT_STRINGVIEW_LEVEL < 2
-/*!
- \since 4.8
-
- \overload indexOf()
-
- Returns the index position of the first occurrence of the string
- reference \a str in this string reference, searching forward from
- index position \a from. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::indexOf(), lastIndexOf(), contains(), count()
-*/
-int QStringRef::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::findString(QStringView(unicode(), size()), from, QStringView(str.unicode(), str.size()), cs));
-}
-#endif // QT_STRINGVIEW_LEVEL < 2
-
-/*!
- \since 4.8
-
- Returns the index position of the last occurrence of the string \a
- str in this string reference, searching backward from index position
- \a from. If \a from is -1 (default), the search starts at the last
- character; if \a from is -2, at the next to last character and so
- on. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::lastIndexOf(), indexOf(), contains(), count()
-*/
-int QStringRef::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::lastIndexOf(*this, from, str, cs));
-}
-
-/*!
- \since 4.8
- \overload lastIndexOf()
-
- Returns the index position of the last occurrence of the character
- \a ch, searching backward from position \a from.
-
- \sa QString::lastIndexOf(), indexOf(), contains(), count()
-*/
-int QStringRef::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(qLastIndexOf(*this, ch, from, cs));
-}
-
-/*!
- \since 4.8
- \overload lastIndexOf()
-
- Returns the index position of the last occurrence of the string \a
- str in this string reference, searching backward from index position
- \a from. If \a from is -1 (default), the search starts at the last
- character; if \a from is -2, at the next to last character and so
- on. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::lastIndexOf(), indexOf(), contains(), count()
-*/
-int QStringRef::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::lastIndexOf(*this, from, str, cs));
-}
-
-/*!
- \since 4.8
- \overload lastIndexOf()
-
- Returns the index position of the last occurrence of the string
- reference \a str in this string reference, searching backward from
- index position \a from. If \a from is -1 (default), the search
- starts at the last character; if \a from is -2, at the next to last
- character and so on. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::lastIndexOf(), indexOf(), contains(), count()
-*/
-int QStringRef::lastIndexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::lastIndexOf(*this, from, str, cs));
-}
-
-/*!
- \fn int QStringRef::lastIndexOf(QStringView str, int from, Qt::CaseSensitivity cs) const
- \since 5.14
- \overload lastIndexOf()
-
- Returns the index position of the last occurrence of the string view \a
- str in this string, searching backward from index position \a
- from. If \a from is -1 (default), the search starts at the last
- character; if \a from is -2, at the next to last character and so
- on. Returns -1 if \a str is not found.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa indexOf(), contains(), count()
-*/
-
-/*!
- \since 4.8
- Returns the number of (potentially overlapping) occurrences of
- the string \a str in this string reference.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa QString::count(), contains(), indexOf()
-*/
-int QStringRef::count(const QString &str, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs));
-}
-
-/*!
- \since 4.8
- \overload count()
-
- Returns the number of occurrences of the character \a ch in the
- string reference.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa QString::count(), contains(), indexOf()
-*/
-int QStringRef::count(QChar ch, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::count(QStringView(unicode(), size()), ch, cs));
-}
-
-/*!
- \since 4.8
- \overload count()
-
- Returns the number of (potentially overlapping) occurrences of the
- string reference \a str in this string reference.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa QString::count(), contains(), indexOf()
-*/
-int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const
-{
- // ### Qt6: qsizetype
- return int(QtPrivate::count(QStringView(unicode(), size()), QStringView(str.unicode(), str.size()), cs));
-}
-
-/*!
- \since 5.9
-
- Returns \c true if the string is read right to left.
-
- \sa QString::isRightToLeft()
-*/
-bool QStringRef::isRightToLeft() const
-{
- return QtPrivate::isRightToLeft(QStringView(unicode(), size()));
-}
-
/*!
\since 5.11
\internal
@@ -10887,20 +9664,12 @@ bool QStringRef::isRightToLeft() const
*/
bool QtPrivate::isRightToLeft(QStringView string) noexcept
{
- const char16_t *p = string.utf16();
- const char16_t * const end = p + string.size();
int isolateLevel = 0;
- while (p < end) {
- uint ucs4 = *p;
- if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
- char16_t low = p[1];
- if (QChar::isLowSurrogate(low)) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++p;
- }
- }
- switch (QChar::direction(ucs4))
- {
+
+ for (QStringIterator i(string); i.hasNext();) {
+ const char32_t c = i.next();
+
+ switch (QChar::direction(c)) {
case QChar::DirRLI:
case QChar::DirLRI:
case QChar::DirFSI:
@@ -10919,201 +9688,28 @@ bool QtPrivate::isRightToLeft(QStringView string) noexcept
if (isolateLevel)
break;
return true;
- default:
+ case QChar::DirEN:
+ case QChar::DirES:
+ case QChar::DirET:
+ case QChar::DirAN:
+ case QChar::DirCS:
+ case QChar::DirB:
+ case QChar::DirS:
+ case QChar::DirWS:
+ case QChar::DirON:
+ case QChar::DirLRE:
+ case QChar::DirLRO:
+ case QChar::DirRLE:
+ case QChar::DirRLO:
+ case QChar::DirPDF:
+ case QChar::DirNSM:
+ case QChar::DirBN:
break;
}
- ++p;
}
return false;
}
-/*!
- \since 4.8
-
- Returns \c true if the string reference starts with \a str; otherwise
- returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa QString::startsWith(), endsWith()
-*/
-bool QStringRef::startsWith(const QString &str, Qt::CaseSensitivity cs) const
-{
- return qt_starts_with(*this, str, cs);
-}
-
-/*!
- \since 4.8
- \overload startsWith()
- \sa QString::startsWith(), endsWith()
-*/
-bool QStringRef::startsWith(QLatin1String str, Qt::CaseSensitivity cs) const
-{
- return qt_starts_with(*this, str, cs);
-}
-
-/*!
- \fn bool QStringRef::startsWith(QStringView str, Qt::CaseSensitivity cs) const
- \since 5.10
- \overload startsWith()
- \sa QString::startsWith(), endsWith()
-*/
-
-/*!
- \since 4.8
- \overload startsWith()
- \sa QString::startsWith(), endsWith()
-*/
-bool QStringRef::startsWith(const QStringRef &str, Qt::CaseSensitivity cs) const
-{
- return qt_starts_with(*this, str, cs);
-}
-
-/*!
- \since 4.8
- \overload startsWith()
-
- Returns \c true if the string reference starts with \a ch; otherwise
- returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::startsWith(), endsWith()
-*/
-bool QStringRef::startsWith(QChar ch, Qt::CaseSensitivity cs) const
-{
- return qt_starts_with(*this, ch, cs);
-}
-
-/*!
- \since 4.8
- Returns \c true if the string reference ends with \a str; otherwise
- returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::endsWith(), startsWith()
-*/
-bool QStringRef::endsWith(const QString &str, Qt::CaseSensitivity cs) const
-{
- return qt_ends_with(*this, str, cs);
-}
-
-/*!
- \since 4.8
- \overload endsWith()
-
- Returns \c true if the string reference ends with \a ch; otherwise
- returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is case
- sensitive; otherwise the search is case insensitive.
-
- \sa QString::endsWith(), endsWith()
-*/
-bool QStringRef::endsWith(QChar ch, Qt::CaseSensitivity cs) const
-{
- return qt_ends_with(*this, ch, cs);
-}
-
-/*!
- \since 4.8
- \overload endsWith()
- \sa QString::endsWith(), endsWith()
-*/
-bool QStringRef::endsWith(QLatin1String str, Qt::CaseSensitivity cs) const
-{
- return qt_ends_with(*this, str, cs);
-}
-
-/*!
- \fn bool QStringRef::endsWith(QStringView str, Qt::CaseSensitivity cs) const
- \since 5.10
- \overload endsWith()
- \sa QString::endsWith(), startsWith()
-*/
-
-/*!
- \since 4.8
- \overload endsWith()
- \sa QString::endsWith(), endsWith()
-*/
-bool QStringRef::endsWith(const QStringRef &str, Qt::CaseSensitivity cs) const
-{
- return qt_ends_with(*this, str, cs);
-}
-
-#if QT_STRINGVIEW_LEVEL < 2
-/*! \fn bool QStringRef::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
-
- \since 4.8
- Returns \c true if this string reference 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.
-
- \sa indexOf(), count()
-*/
-#endif // QT_STRINGVIEW_LEVEL < 2
-
-/*! \fn bool QStringRef::contains(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
-
- \overload contains()
- \since 4.8
-
- Returns \c true if this string contains an occurrence of the
- character \a ch; otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
-*/
-
-#if QT_STRINGVIEW_LEVEL < 2
-/*! \fn bool QStringRef::contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \overload contains()
- \since 4.8
-
- Returns \c true if this string reference contains an occurrence of
- the string reference \a str; otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa indexOf(), count()
-*/
-#endif // QT_STRINGVIEW_LEVEL < 2
-
-/*! \fn bool QStringRef::contains(QLatin1String str, Qt::CaseSensitivity cs) const
- \since 4.8
- \overload contains()
-
- Returns \c true if this string reference 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.
-
- \sa indexOf(), count()
-*/
-
-/*! \fn bool QStringRef::contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- \since 5.14
- \overload contains()
-
- Returns \c true if this string reference contains an occurrence of
- the string view \a str; otherwise returns \c false.
-
- If \a cs is Qt::CaseSensitive (default), the search is
- case sensitive; otherwise the search is case insensitive.
-
- \sa indexOf(), count()
-*/
-
qsizetype QtPrivate::count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
qsizetype num = 0;
@@ -11129,64 +9725,81 @@ 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); });
}
-template <typename Haystack, typename Needle>
-bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::count(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
{
- if (haystack.isNull())
- return needle.isNull(); // historical behavior, consider changing in ### Qt 6.
- const auto haystackLen = haystack.size();
- const auto needleLen = needle.size();
- if (haystackLen == 0)
- return needleLen == 0;
- if (needleLen > haystackLen)
- return false;
+ qsizetype num = 0;
+ qsizetype i = -1;
+
+ QLatin1StringMatcher matcher(needle, cs);
+ while ((i = matcher.indexIn(haystack, i + 1)) != -1)
+ ++num;
- return qt_compare_strings(haystack.left(needleLen), needle, cs) == 0;
+ return num;
}
-static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
+qsizetype QtPrivate::count(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs)
{
- return qt_starts_with_impl(haystack, needle, cs);
+ if (haystack.size() < needle.size())
+ return 0;
+
+ if (!QtPrivate::isLatin1(needle)) // won't find non-L1 UTF-16 needles in a L1 haystack!
+ return 0;
+
+ qsizetype num = 0;
+ qsizetype i = -1;
+
+ 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;
+
+ return num;
}
-static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+qsizetype QtPrivate::count(QStringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
{
- return qt_starts_with_impl(haystack, needle, cs);
+ if (haystack.size() < needle.size())
+ return -1;
+
+ QVarLengthArray<char16_t> s = qt_from_latin1_to_qvla(needle);
+ return QtPrivate::count(haystack, QStringView(s.data(), s.size()), cs);
}
-static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs)
+qsizetype QtPrivate::count(QLatin1StringView haystack, QChar needle, Qt::CaseSensitivity cs) noexcept
{
- return haystack.size()
- && (cs == Qt::CaseSensitive ? haystack.front() == needle
- : foldCase(haystack.front()) == foldCase(needle));
+ // non-L1 needles cannot possibly match in L1-only haystacks
+ if (needle.unicode() > 0xff)
+ return 0;
+
+ if (cs == Qt::CaseSensitive) {
+ return std::count(haystack.cbegin(), haystack.cend(), needle.toLatin1());
+ } else {
+ return std::count_if(haystack.cbegin(), haystack.cend(),
+ CaseInsensitiveL1::matcher(needle.toLatin1()));
+ }
}
/*!
\fn bool QtPrivate::startsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
\since 5.10
- \fn bool QtPrivate::startsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \fn bool QtPrivate::startsWith(QStringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
\since 5.10
- \fn bool QtPrivate::startsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs)
+ \fn bool QtPrivate::startsWith(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs)
\since 5.10
- \fn bool QtPrivate::startsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \fn bool QtPrivate::startsWith(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
\since 5.10
\internal
\relates QStringView
@@ -11194,10 +9807,9 @@ static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSe
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(), QLatin1String::endsWith()
+ \sa QtPrivate::endsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1StringView::endsWith()
*/
bool QtPrivate::startsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
@@ -11205,61 +9817,29 @@ bool QtPrivate::startsWith(QStringView haystack, QStringView needle, Qt::CaseSen
return qt_starts_with_impl(haystack, needle, cs);
}
-bool QtPrivate::startsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::startsWith(QStringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
return qt_starts_with_impl(haystack, needle, cs);
}
-bool QtPrivate::startsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::startsWith(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
return qt_starts_with_impl(haystack, needle, cs);
}
-bool QtPrivate::startsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::startsWith(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
return qt_starts_with_impl(haystack, needle, cs);
}
-template <typename Haystack, typename Needle>
-bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
-{
- if (haystack.isNull())
- return needle.isNull(); // historical behavior, consider changing in ### Qt 6.
- const auto haystackLen = haystack.size();
- const auto needleLen = needle.size();
- if (haystackLen == 0)
- return needleLen == 0;
- if (haystackLen < needleLen)
- return false;
-
- return qt_compare_strings(haystack.right(needleLen), needle, cs) == 0;
-}
-
-static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
-{
- return qt_ends_with_impl(haystack, needle, cs);
-}
-
-static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
-{
- return qt_ends_with_impl(haystack, needle, cs);
-}
-
-static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs)
-{
- return haystack.size()
- && (cs == Qt::CaseSensitive ? haystack.back() == needle
- : foldCase(haystack.back()) == foldCase(needle));
-}
-
/*!
\fn bool QtPrivate::endsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
\since 5.10
- \fn bool QtPrivate::endsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \fn bool QtPrivate::endsWith(QStringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
\since 5.10
- \fn bool QtPrivate::endsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs)
+ \fn bool QtPrivate::endsWith(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs)
\since 5.10
- \fn bool QtPrivate::endsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs)
+ \fn bool QtPrivate::endsWith(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs)
\since 5.10
\internal
\relates QStringView
@@ -11267,10 +9847,9 @@ static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSens
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(), QLatin1String::endsWith()
+ \sa QtPrivate::startsWith(), QString::endsWith(), QStringView::endsWith(), QLatin1StringView::endsWith()
*/
bool QtPrivate::endsWith(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
@@ -11278,91 +9857,27 @@ bool QtPrivate::endsWith(QStringView haystack, QStringView needle, Qt::CaseSensi
return qt_ends_with_impl(haystack, needle, cs);
}
-bool QtPrivate::endsWith(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::endsWith(QStringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
return qt_ends_with_impl(haystack, needle, cs);
}
-bool QtPrivate::endsWith(QLatin1String haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::endsWith(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
return qt_ends_with_impl(haystack, needle, cs);
}
-bool QtPrivate::endsWith(QLatin1String haystack, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+bool QtPrivate::endsWith(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
return qt_ends_with_impl(haystack, needle, cs);
}
-namespace {
-template <typename Pointer>
-char32_t foldCaseHelper(Pointer ch, Pointer start) = delete;
-
-template <>
-char32_t foldCaseHelper<const QChar*>(const QChar* ch, const QChar* start)
-{
- return foldCase(reinterpret_cast<const char16_t*>(ch),
- reinterpret_cast<const char16_t*>(start));
-}
-
-template <>
-char32_t foldCaseHelper<const char*>(const char* ch, const char*)
-{
- return foldCase(char16_t(uchar(*ch)));
-}
-
-template <typename T>
-char16_t valueTypeToUtf16(T t) = delete;
-
-template <>
-char16_t valueTypeToUtf16<QChar>(QChar t)
-{
- return t.unicode();
-}
-
-template <>
-char16_t valueTypeToUtf16<char>(char t)
-{
- return char16_t{uchar(t)};
-}
-}
-
-/*!
- \internal
-
- Returns the index position of the first occurrence of the
- character \a ch in the string given by \a str and \a len,
- searching forward from index
- position \a from. Returns -1 if \a ch could not be found.
-*/
-
-static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept
-{
- if (from < 0)
- from = qMax(from + str.size(), qsizetype(0));
- if (from < str.size()) {
- const 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;
-}
-
qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringView needle0, Qt::CaseSensitivity cs) noexcept
{
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))
@@ -11372,9 +9887,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
@@ -11407,7 +9919,7 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
while (haystack <= end) {
hashHaystack += haystack[sl_minus_1];
if (hashHaystack == hashNeedle
- && qt_compare_strings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
+ && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
return haystack - haystack0.utf16();
REHASH(*haystack);
@@ -11424,7 +9936,7 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
while (haystack <= end) {
hashHaystack += foldCase(haystack + sl_minus_1, haystack_start);
if (hashHaystack == hashNeedle
- && qt_compare_strings(needle0, sv(haystack), Qt::CaseInsensitive) == 0)
+ && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseInsensitive) == 0)
return haystack - haystack0.utf16();
REHASH(foldCase(haystack, haystack_start));
@@ -11434,128 +9946,93 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
return -1;
}
-template <typename Haystack>
-static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
- qsizetype from, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::findString(QStringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
- if (from < 0)
- from += haystack.size();
- if (std::size_t(from) >= std::size_t(haystack.size()))
+ if (haystack.size() < needle.size())
return -1;
- if (from >= 0) {
- char16_t c = needle.unicode();
- const auto b = haystack.data();
- auto n = b + from;
- if (cs == Qt::CaseSensitive) {
- for (; n >= b; --n)
- if (valueTypeToUtf16(*n) == c)
- return n - b;
- } else {
- c = foldCase(c);
- for (; n >= b; --n)
- if (foldCase(valueTypeToUtf16(*n)) == c)
- return n - b;
- }
- }
- return -1;
+
+ 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);
}
-template<typename Haystack, typename Needle>
-static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from,
- Needle needle0, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
- const qsizetype sl = needle0.size();
- if (sl == 1)
- return qLastIndexOf(haystack0, needle0.front(), from, cs);
-
- const qsizetype l = haystack0.size();
- if (from < 0)
- from += l;
- if (from == l && sl == 0)
- return from;
- const qsizetype delta = l - sl;
- if (std::size_t(from) >= std::size_t(l) || delta < 0)
+ if (haystack.size() < needle.size())
return -1;
- if (from > delta)
- from = delta;
-
- auto sv = [sl](const typename Haystack::value_type *v) { return Haystack(v, sl); };
- auto haystack = haystack0.data();
- const auto needle = needle0.data();
- const auto *end = haystack;
- haystack += from;
- const std::size_t sl_minus_1 = sl - 1;
- const auto *n = needle + sl_minus_1;
- const auto *h = haystack + sl_minus_1;
- std::size_t hashNeedle = 0, hashHaystack = 0;
- qsizetype idx;
-
- if (cs == Qt::CaseSensitive) {
- for (idx = 0; idx < sl; ++idx) {
- hashNeedle = (hashNeedle << 1) + valueTypeToUtf16(*(n - idx));
- hashHaystack = (hashHaystack << 1) + valueTypeToUtf16(*(h - idx));
- }
- hashHaystack -= valueTypeToUtf16(*haystack);
-
- while (haystack >= end) {
- hashHaystack += valueTypeToUtf16(*haystack);
- if (hashHaystack == hashNeedle
- && qt_compare_strings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
- return haystack - end;
- --haystack;
- REHASH(valueTypeToUtf16(haystack[sl]));
- }
- } else {
- for (idx = 0; idx < sl; ++idx) {
- hashNeedle = (hashNeedle << 1) + foldCaseHelper(n - idx, needle);
- hashHaystack = (hashHaystack << 1) + foldCaseHelper(h - idx, end);
- }
- hashHaystack -= foldCaseHelper(haystack, end);
+ if (!QtPrivate::isLatin1(needle)) // won't find non-L1 UTF-16 needles in a L1 haystack!
+ return -1;
- while (haystack >= end) {
- hashHaystack += foldCaseHelper(haystack, end);
- if (hashHaystack == hashNeedle
- && qt_compare_strings(sv(haystack), needle0, Qt::CaseInsensitive) == 0)
- return haystack - end;
- --haystack;
- REHASH(foldCaseHelper(haystack + sl, end));
- }
+ if (needle.size() == 1) {
+ const char n = needle.front().toLatin1();
+ return QtPrivate::findString(haystack, from, QLatin1StringView(&n, 1), cs);
}
- return -1;
+
+ QVarLengthArray<char> s(needle.size());
+ qt_to_latin1_unchecked(reinterpret_cast<uchar *>(s.data()), needle.utf16(), needle.size());
+ return QtPrivate::findString(haystack, from, QLatin1StringView(s.data(), s.size()), cs);
}
-qsizetype QtPrivate::findString(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
- if (haystack.size() < needle.size())
+ if (from < 0)
+ from += haystack.size();
+ if (from < 0)
+ return -1;
+ qsizetype adjustedSize = haystack.size() - from;
+ if (adjustedSize < needle.size())
return -1;
+ if (needle.size() == 0)
+ return from;
- QVarLengthArray<char16_t> s(needle.size());
- qt_from_latin1(s.data(), needle.latin1(), needle.size());
- return QtPrivate::findString(haystack, from, QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), cs);
-}
+ if (cs == Qt::CaseSensitive) {
-qsizetype QtPrivate::findString(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
-{
- if (haystack.size() < needle.size())
+ if (needle.size() == 1) {
+ 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 QLatin1StringMatcher matcher(needle, Qt::CaseSensitivity::CaseSensitive);
+ return matcher.indexIn(haystack, from);
+ }
+
+ // If the needle is sufficiently small we simply iteratively search through
+ // the haystack. When the needle is too long we use a boyer-moore searcher
+ // from the standard library, if available. If it is not available then the
+ // QLatin1Strings are converted to QString and compared as such. Though
+ // initialization is slower the boyer-moore search it employs still makes up
+ // for it when haystack and needle are sufficiently long.
+ // The needle size was chosen by testing various lengths using the
+ // qstringtokenizer benchmark with the
+ // "tokenize_qlatin1string_qlatin1string" test.
+#ifdef Q_CC_MSVC
+ const qsizetype threshold = 1;
+#else
+ const qsizetype threshold = 13;
+#endif
+ if (needle.size() <= threshold) {
+ const auto begin = haystack.begin();
+ const auto end = haystack.end() - needle.size() + 1;
+ 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;
+ 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)
+ return std::distance(begin, it);
+ }
return -1;
+ }
- QVarLengthArray<char16_t> s(haystack.size());
- qt_from_latin1(s.data(), haystack.latin1(), haystack.size());
- return QtPrivate::findString(QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), from, needle, cs);
+ QLatin1StringMatcher matcher(needle, Qt::CaseSensitivity::CaseInsensitive);
+ return matcher.indexIn(haystack, from);
}
-qsizetype QtPrivate::findString(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, char16_t needle, Qt::CaseSensitivity cs) noexcept
{
- if (haystack.size() < needle.size())
- return -1;
-
- QVarLengthArray<char16_t> h(haystack.size());
- qt_from_latin1(h.data(), haystack.latin1(), haystack.size());
- QVarLengthArray<char16_t> n(needle.size());
- qt_from_latin1(n.data(), needle.latin1(), needle.size());
- return QtPrivate::findString(QStringView(reinterpret_cast<const QChar*>(h.constData()), h.size()), from,
- QStringView(reinterpret_cast<const QChar*>(n.constData()), n.size()), cs);
+ return qLastIndexOf(haystack, QChar(needle), from, cs);
}
qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
@@ -11563,470 +10040,349 @@ qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QStringVi
return qLastIndexOf(haystack, from, needle, cs);
}
-qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
-qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::lastIndexOf(QLatin1StringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
-qsizetype QtPrivate::lastIndexOf(QLatin1String haystack, qsizetype from, QLatin1String needle, Qt::CaseSensitivity cs) noexcept
+qsizetype QtPrivate::lastIndexOf(QLatin1StringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
}
-/*!
- \since 4.8
-
- Returns a Latin-1 representation of the string as a QByteArray.
-
- The returned byte array is undefined if the string contains non-Latin1
- characters. Those characters may be suppressed or replaced with a
- question mark.
-
- \sa toUtf8(), toLocal8Bit(), QStringEncoder
-*/
-QByteArray QStringRef::toLatin1() const
+#if QT_CONFIG(regularexpression)
+qsizetype QtPrivate::indexOf(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
{
- return qt_convert_to_latin1(*this);
-}
-
-/*!
- \since 4.8
-
- 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.
-
- On Unix systems this is equivalen to toUtf8(), on Windows the systems
- current code page is being used.
+ if (!re.isValid()) {
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::indexOf");
+ return -1;
+ }
- 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.
+ QRegularExpressionMatch match = stringHaystack
+ ? re.match(*stringHaystack, from)
+ : re.matchView(viewHaystack, from);
+ if (match.hasMatch()) {
+ const qsizetype ret = match.capturedStart();
+ if (rmatch)
+ *rmatch = std::move(match);
+ return ret;
+ }
- \sa toLatin1(), toUtf8(), QStringEncoder
-*/
-QByteArray QStringRef::toLocal8Bit() const
-{
- return qt_convert_to_local_8bit(*this);
+ return -1;
}
-/*!
- \since 4.8
-
- Returns a UTF-8 representation of the string as a QByteArray.
-
- UTF-8 is a Unicode codec and can represent all characters in a Unicode
- string like QString.
-
- \sa toLatin1(), toLocal8Bit(), QStringEncoder
-*/
-QByteArray QStringRef::toUtf8() const
+qsizetype QtPrivate::indexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
{
- return qt_convert_to_utf8(*this);
+ return indexOf(haystack, nullptr, re, from, rmatch);
}
-/*!
- \since 4.8
-
- Returns a UCS-4/UTF-32 representation of the string as a QList<uint>.
-
- UCS-4 is a Unicode codec and therefore it is lossless. All characters from
- this string will be encoded in UCS-4. Any invalid sequence of code units in
- this string is replaced by the Unicode's replacement character
- (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}).
-
- The returned list is not \\0'-terminated.
-
- \sa toUtf8(), toLatin1(), toLocal8Bit(), QStringEncoder
-*/
-QList<uint> QStringRef::toUcs4() const
+qsizetype QtPrivate::lastIndexOf(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
{
- return qt_convert_to_ucs4(*this);
-}
-
-/*!
- Returns a string that has whitespace removed from the start and
- the end.
-
- Whitespace means any character for which QChar::isSpace() returns
- \c true. This includes the ASCII characters '\\t', '\\n', '\\v',
- '\\f', '\\r', and ' '.
-
- Unlike QString::simplified(), trimmed() leaves internal whitespace alone.
+ if (!re.isValid()) {
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::lastIndexOf");
+ return -1;
+ }
- \since 5.1
+ 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();
+ qsizetype start = match.capturedStart();
+ if (start < endpos) {
+ lastIndex = start;
+ if (rmatch)
+ *rmatch = std::move(match);
+ } else {
+ break;
+ }
+ }
- \sa QString::trimmed()
-*/
-QStringRef QStringRef::trimmed() const
-{
- const QChar *begin = cbegin();
- const QChar *end = cend();
- QStringAlgorithms<const QStringRef>::trimmed_helper_positions(begin, end);
- if (begin == cbegin() && end == cend())
- return *this;
- int position = m_position + (begin - cbegin());
- return QStringRef(m_string, position, end - begin);
+ return lastIndex;
}
-/*!
- 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.
-
- If \a ok is not \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
-
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
-
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toLongLong()
-
- \sa QString::toLongLong()
-
- \since 5.1
-*/
-
-qint64 QStringRef::toLongLong(bool *ok, int base) const
+qsizetype QtPrivate::lastIndexOf(QStringView haystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
{
- return QString::toIntegral_helper<qint64>(*this, ok, base);
+ return lastIndexOf(haystack, nullptr, re, from, rmatch);
}
-/*!
- 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.
-
- If \a ok is not \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
-
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
-
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toULongLong()
-
- \sa QString::toULongLong()
-
- \since 5.1
-*/
-
-quint64 QStringRef::toULongLong(bool *ok, int base) const
+bool QtPrivate::contains(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
{
- return QString::toIntegral_helper<quint64>(*this, ok, base);
+ if (!re.isValid()) {
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::contains");
+ return false;
+ }
+ QRegularExpressionMatch m = stringHaystack
+ ? re.match(*stringHaystack)
+ : re.matchView(viewHaystack);
+ bool hasMatch = m.hasMatch();
+ if (hasMatch && rmatch)
+ *rmatch = std::move(m);
+ return hasMatch;
}
-/*!
- \fn long QStringRef::toLong(bool *ok, int base) const
-
- Returns the string converted to a \c 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.
-
- If \a ok is not \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
-
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
-
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toLong()
-
- \sa QString::toLong()
-
- \since 5.1
-*/
-
-long QStringRef::toLong(bool *ok, int base) const
+bool QtPrivate::contains(QStringView haystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
{
- return QString::toIntegral_helper<long>(*this, ok, base);
+ return contains(haystack, nullptr, re, rmatch);
}
-/*!
- \fn ulong QStringRef::toULong(bool *ok, int base) const
-
- Returns the string converted to an \c{unsigned 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.
-
- If \a ok is not \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
-
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
-
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toULongLong()
-
- \sa QString::toULong()
-
- \since 5.1
-*/
-
-ulong QStringRef::toULong(bool *ok, int base) const
+qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re)
{
- return QString::toIntegral_helper<ulong>(*this, ok, base);
+ if (!re.isValid()) {
+ qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::count");
+ return 0;
+ }
+ qsizetype count = 0;
+ qsizetype index = -1;
+ qsizetype len = haystack.size();
+ while (index <= len - 1) {
+ QRegularExpressionMatch match = re.matchView(haystack, index + 1);
+ if (!match.hasMatch())
+ break;
+ 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;
}
+#endif // QT_CONFIG(regularexpression)
/*!
- Returns the string converted to an \c int using base \a
- base, which is 10 by default and must be between 2 and 36, or 0.
- Returns 0 if the conversion fails.
-
- If \a ok is not \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
-
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ \since 5.0
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toInt()
+ Converts a plain text string to an HTML string with
+ HTML metacharacters \c{<}, \c{>}, \c{&}, and \c{"} replaced by HTML
+ entities.
- \sa QString::toInt()
+ Example:
- \since 5.1
+ \snippet code/src_corelib_text_qstring.cpp 7
*/
-
-int QStringRef::toInt(bool *ok, int base) const
+QString QString::toHtmlEscaped() const
{
- return QString::toIntegral_helper<int>(*this, ok, base);
+ const auto pos = std::u16string_view(*this).find_first_of(u"<>&\"");
+ if (pos == std::u16string_view::npos)
+ return *this;
+ QString rich;
+ const qsizetype len = size();
+ rich.reserve(qsizetype(len * 1.1));
+ rich += qToStringViewIgnoringNull(*this).first(pos);
+ for (auto ch : qToStringViewIgnoringNull(*this).sliced(pos)) {
+ if (ch == u'<')
+ rich += "&lt;"_L1;
+ else if (ch == u'>')
+ rich += "&gt;"_L1;
+ else if (ch == u'&')
+ rich += "&amp;"_L1;
+ else if (ch == u'"')
+ rich += "&quot;"_L1;
+ else
+ rich += ch;
+ }
+ rich.squeeze();
+ return rich;
}
/*!
- Returns the string converted to an \c{unsigned int} using base \a
- base, which is 10 by default and must be between 2 and 36, or 0.
- Returns 0 if the conversion fails.
+ \macro QStringLiteral(str)
+ \relates QString
- If \a ok is not \nullptr, failure is reported by setting *\a{ok}
- to \c false, and success by setting *\a{ok} to \c true.
+ The macro generates the data for a QString out of the string literal \a str
+ at compile time. Creating a QString from it is free in this case, and the
+ generated string data is stored in the read-only segment of the compiled
+ object file.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ If you have code that looks like this:
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toUInt()
+ \snippet code/src_corelib_text_qstring.cpp 9
- \sa QString::toUInt()
+ then a temporary QString will be created to be passed as the \c{hasAttribute}
+ function parameter. This can be quite expensive, as it involves a memory
+ allocation and the copy/conversion of the data into QString's internal
+ encoding.
- \since 5.1
-*/
+ This cost can be avoided by using QStringLiteral instead:
-uint QStringRef::toUInt(bool *ok, int base) const
-{
- return QString::toIntegral_helper<uint>(*this, ok, base);
-}
+ \snippet code/src_corelib_text_qstring.cpp 10
-/*!
- Returns the string converted to a \c short using base \a
- base, which is 10 by default and must be between 2 and 36, or 0.
- Returns 0 if the conversion fails.
+ In this case, QString's internal data will be generated at compile time; no
+ conversion or allocation will occur at runtime.
- 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.
+ Using QStringLiteral instead of a double quoted plain C++ string literal can
+ significantly speed up creation of QString instances from data known at
+ compile time.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ \note QLatin1StringView can still be more efficient than QStringLiteral
+ when the string is passed to a function that has an overload taking
+ QLatin1StringView and this overload avoids conversion to QString. For
+ instance, QString::operator==() can compare to a QLatin1StringView
+ directly:
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toShort()
+ \snippet code/src_corelib_text_qstring.cpp 11
- \sa QString::toShort()
+ \note Some compilers have bugs encoding strings containing characters outside
+ the US-ASCII character set. Make sure you prefix your string with \c{u} in
+ those cases. It is optional otherwise.
- \since 5.1
+ \sa QByteArrayLiteral
*/
-short QStringRef::toShort(bool *ok, int base) const
-{
- return QString::toIntegral_helper<short>(*this, ok, base);
-}
-
+#if QT_DEPRECATED_SINCE(6, 8)
/*!
- Returns the string converted to an \c{unsigned short} using base \a
- base, which is 10 by default and must be between 2 and 36, or 0.
- Returns 0 if the conversion fails.
+ \fn QtLiterals::operator""_qs(const char16_t *str, size_t size)
- 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.
+ \relates QString
+ \since 6.2
+ \deprecated [6.8] Use \c _s from Qt::StringLiterals namespace instead.
- If \a base is 0, the C language convention is used: If the string
- begins with "0x", base 16 is used; if the string begins with "0",
- base 8 is used; otherwise, base 10 is used.
+ Literal operator that creates a QString out of the first \a size characters in
+ the char16_t string literal \a str.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toUShort()
+ The QString is created at compile time, and the generated string data is stored
+ in the read-only segment of the compiled object file. Duplicate literals may
+ share the same read-only memory. This functionality is interchangeable with
+ QStringLiteral, but saves typing when many string literals are present in the
+ code.
- \sa QString::toUShort()
+ The following code creates a QString:
+ \code
+ auto str = u"hello"_qs;
+ \endcode
- \since 5.1
+ \sa QStringLiteral, QtLiterals::operator""_qba(const char *str, size_t size)
*/
-
-ushort QStringRef::toUShort(bool *ok, int base) const
-{
- return QString::toIntegral_helper<ushort>(*this, ok, base);
-}
-
+#endif // QT_DEPRECATED_SINCE(6, 8)
/*!
- Returns the string converted to a \c double value.
+ \fn Qt::Literals::StringLiterals::operator""_s(const char16_t *str, size_t size)
- Returns an infinity if the conversion overflows or 0.0 if the
- conversion fails for other reasons (e.g. underflow).
+ \relates QString
+ \since 6.4
- 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.
+ Literal operator that creates a QString out of the first \a size characters in
+ the char16_t string literal \a str.
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toDouble()
+ The QString is created at compile time, and the generated string data is stored
+ in the read-only segment of the compiled object file. Duplicate literals may
+ share the same read-only memory. This functionality is interchangeable with
+ QStringLiteral, but saves typing when many string literals are present in the
+ code.
- For historic reasons, this function does not handle
- thousands group separators. If you need to convert such numbers,
- use QLocale::toDouble().
+ The following code creates a QString:
+ \code
+ using namespace Qt::Literals::StringLiterals;
- \sa QString::toDouble()
+ auto str = u"hello"_s;
+ \endcode
- \since 5.1
+ \sa Qt::Literals::StringLiterals
*/
-double QStringRef::toDouble(bool *ok) const
+/*!
+ \internal
+ */
+void QAbstractConcatenable::appendLatin1To(QLatin1StringView in, QChar *out) noexcept
{
- return QLocaleData::c()->stringToDouble(*this, ok, QLocale::RejectGroupSeparator);
+ qt_from_latin1(reinterpret_cast<char16_t *>(out), in.data(), size_t(in.size()));
}
/*!
- Returns the string converted to a \c float 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.
-
- The string conversion will always happen in the 'C' locale. For locale
- dependent conversion use QLocale::toFloat()
+ \fn template <typename T> qsizetype erase(QString &s, const T &t)
+ \relates QString
+ \since 6.1
- \sa QString::toFloat()
+ Removes all elements that compare equal to \a t from the
+ string \a s. Returns the number of elements removed, if any.
- \since 5.1
+ \sa erase_if
*/
-float QStringRef::toFloat(bool *ok) const
-{
- return QLocaleData::convertDoubleToFloat(toDouble(ok), ok);
-}
-
/*!
- \obsolete
- \fn QString Qt::escape(const QString &plain)
+ \fn template <typename Predicate> qsizetype erase_if(QString &s, Predicate pred)
+ \relates QString
+ \since 6.1
+
+ Removes all elements for which the predicate \a pred returns true
+ from the string \a s. Returns the number of elements removed, if
+ any.
- Use QString::toHtmlEscaped() instead.
+ \sa erase
*/
/*!
- \since 5.0
+ \macro const char *qPrintable(const QString &str)
+ \relates QString
- Converts a plain text string to an HTML string with
- HTML metacharacters \c{<}, \c{>}, \c{&}, and \c{"} replaced by HTML
- entities.
+ Returns \a str as a \c{const char *}. This is equivalent to
+ \a{str}.toLocal8Bit().constData().
- Example:
+ 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.
- \snippet code/src_corelib_text_qstring.cpp 7
+ \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()
*/
-QString QString::toHtmlEscaped() const
-{
- QString rich;
- const int len = length();
- rich.reserve(int(len * 1.1));
- for (int i = 0; i < len; ++i) {
- if (at(i) == QLatin1Char('<'))
- rich += QLatin1String("&lt;");
- else if (at(i) == QLatin1Char('>'))
- rich += QLatin1String("&gt;");
- else if (at(i) == QLatin1Char('&'))
- rich += QLatin1String("&amp;");
- else if (at(i) == QLatin1Char('"'))
- rich += QLatin1String("&quot;");
- else
- rich += at(i);
- }
- rich.squeeze();
- return rich;
-}
/*!
- \macro QStringLiteral(str)
- \relates QString
+ \macro const char *qUtf8Printable(const QString &str)
+ \relates QString
+ \since 5.4
- The macro generates the data for a QString out of the string literal \a str
- at compile time. Creating a QString from it is free in this case, and the
- generated string data is stored in the read-only segment of the compiled
- object file.
+ Returns \a str as a \c{const char *}. This is equivalent to
+ \a{str}.toUtf8().constData().
- If you have code that looks like this:
+ 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.
- \snippet code/src_corelib_text_qstring.cpp 9
+ Example:
- then a temporary QString will be created to be passed as the \c{hasAttribute}
- function parameter. This can be quite expensive, as it involves a memory
- allocation and the copy/conversion of the data into QString's internal
- encoding.
+ \snippet code/src_corelib_text_qstring.cpp qUtf8Printable
- This cost can be avoided by using QStringLiteral instead:
+ \sa qPrintable(), qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
+*/
- \snippet code/src_corelib_text_qstring.cpp 10
+/*!
+ \macro const wchar_t *qUtf16Printable(const QString &str)
+ \relates QString
+ \since 5.7
- In this case, QString's internal data will be generated at compile time; no
- conversion or allocation will occur at runtime.
+ 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.
- Using QStringLiteral instead of a double quoted plain C++ string literal can
- significantly speed up creation of QString instances from data known at
- compile time.
+ 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*}!
- \note QLatin1String can still be more efficient than QStringLiteral
- when the string is passed to a function that has an overload taking
- QLatin1String and this overload avoids conversion to QString. For
- instance, QString::operator==() can compare to a QLatin1String
- directly:
+ 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.
- \snippet code/src_corelib_text_qstring.cpp 11
+ Example:
- \note Some compilers have bugs encoding strings containing characters outside
- the US-ASCII character set. Make sure you prefix your string with \c{u} in
- those cases. It is optional otherwise.
+ \snippet code/src_corelib_text_qstring.cpp qUtf16Printable
- \sa QByteArrayLiteral
+ \sa qPrintable(), qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
*/
-/*!
- \internal
- */
-void QAbstractConcatenable::appendLatin1To(const char *a, int len, QChar *out) noexcept
-{
- qt_from_latin1(reinterpret_cast<char16_t *>(out), a, uint(len));
-}
-
-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);
-}
-
QT_END_NAMESPACE
+
+#undef REHASH