Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qstring.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// Copyright (C) 2019 Mail.ru Group.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qstringlist.h"
7#if QT_CONFIG(regularexpression)
9#endif
10#include "qunicodetables_p.h"
11#include <private/qstringconverter_p.h>
12#include <private/qtools_p.h>
13#include "qlocale_tools_p.h"
14#include "private/qsimd_p.h"
15#include <qnumeric.h>
16#include <qdatastream.h>
17#include <qlist.h>
18#include "qlocale.h"
19#include "qlocale_p.h"
20#include "qstringbuilder.h"
21#include "qstringmatcher.h"
22#include "qvarlengtharray.h"
23#include "qdebug.h"
24#include "qendian.h"
25#include "qcollator.h"
26#include "qttypetraits.h"
27
28#ifdef Q_OS_DARWIN
29#include <private/qcore_mac_p.h>
30#endif
31
32#include <private/qfunctions_p.h>
33
34#include <limits.h>
35#include <string.h>
36#include <stdlib.h>
37#include <stdio.h>
38#include <stdarg.h>
39#include <wchar.h>
40
41#include "qchar.cpp"
43#include "qstringmatcher.cpp"
44#include "qstringiterator_p.h"
45#include "qstringalgorithms_p.h"
46#include "qthreadstorage.h"
47
48#include <algorithm>
49#include <functional>
50
51#ifdef Q_OS_WIN
52# include <qt_windows.h>
53#endif
54
55#ifdef truncate
56# undef truncate
57#endif
58
59#ifndef LLONG_MAX
60#define LLONG_MAX qint64_C(9223372036854775807)
61#endif
62#ifndef LLONG_MIN
63#define LLONG_MIN (-LLONG_MAX - qint64_C(1))
64#endif
65#ifndef ULLONG_MAX
66#define ULLONG_MAX quint64_C(18446744073709551615)
67#endif
68
69#define REHASH(a) \
70 if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
71 hashHaystack -= std::size_t(a) << sl_minus_1; \
72 hashHaystack <<= 1
73
75
76using namespace Qt::StringLiterals;
77using namespace QtMiscUtils;
78
79const char16_t QString::_empty = 0;
80
81// in qstringmatcher.cpp
83
84namespace {
85enum StringComparisonMode {
86 CompareStringsForEquality,
87 CompareStringsForOrdering
88};
89
90template <typename Pointer>
91char32_t foldCaseHelper(Pointer ch, Pointer start) = delete;
92
93template <>
94char32_t foldCaseHelper<const QChar*>(const QChar* ch, const QChar* start)
95{
96 return foldCase(reinterpret_cast<const char16_t*>(ch),
97 reinterpret_cast<const char16_t*>(start));
98}
99
100template <>
101char32_t foldCaseHelper<const char*>(const char* ch, const char*)
102{
103 return foldCase(char16_t(uchar(*ch)));
104}
105
106template <typename T>
107char16_t valueTypeToUtf16(T t) = delete;
108
109template <>
110char16_t valueTypeToUtf16<QChar>(QChar t)
111{
112 return t.unicode();
113}
114
115template <>
116char16_t valueTypeToUtf16<char>(char t)
117{
118 return char16_t{uchar(t)};
119}
120
121template <typename T>
122static inline bool foldAndCompare(const T a, const T b)
123{
124 return foldCase(a) == b;
125}
126
135static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept
136{
137 if (-from > str.size())
138 return -1;
139 if (from < 0)
140 from = qMax(from + str.size(), qsizetype(0));
141 if (from < str.size()) {
142 const char16_t *s = str.utf16();
143 char16_t c = ch.unicode();
144 const char16_t *n = s + from;
145 const char16_t *e = s + str.size();
146 if (cs == Qt::CaseSensitive) {
148 if (n != e)
149 return n - s;
150 } else {
151 c = foldCase(c);
152 auto it = std::find_if(n, e, [c](const auto &ch) { return foldAndCompare(ch, c); });
153 if (it != e)
154 return std::distance(s, it);
155 }
156 }
157 return -1;
158}
159
160template <typename Haystack>
161static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
162 qsizetype from, Qt::CaseSensitivity cs) noexcept
163{
164 if (haystack.size() == 0)
165 return -1;
166 if (from < 0)
167 from += haystack.size();
168 else if (std::size_t(from) > std::size_t(haystack.size()))
169 from = haystack.size() - 1;
170 if (from >= 0) {
171 char16_t c = needle.unicode();
172 const auto b = haystack.data();
173 auto n = b + from;
174 if (cs == Qt::CaseSensitive) {
175 for (; n >= b; --n)
176 if (valueTypeToUtf16(*n) == c)
177 return n - b;
178 } else {
179 c = foldCase(c);
180 for (; n >= b; --n)
181 if (foldCase(valueTypeToUtf16(*n)) == c)
182 return n - b;
183 }
184 }
185 return -1;
186}
187template <> qsizetype
188qLastIndexOf(QString, QChar, qsizetype, Qt::CaseSensitivity) noexcept = delete; // unwanted, would detach
189
190template<typename Haystack, typename Needle>
191static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from,
192 Needle needle0, Qt::CaseSensitivity cs) noexcept
193{
194 const qsizetype sl = needle0.size();
195 if (sl == 1)
196 return qLastIndexOf(haystack0, needle0.front(), from, cs);
197
198 const qsizetype l = haystack0.size();
199 if (from < 0)
200 from += l;
201 if (from == l && sl == 0)
202 return from;
203 const qsizetype delta = l - sl;
204 if (std::size_t(from) > std::size_t(l) || delta < 0)
205 return -1;
206 if (from > delta)
207 from = delta;
208
209 auto sv = [sl](const typename Haystack::value_type *v) { return Haystack(v, sl); };
210
211 auto haystack = haystack0.data();
212 const auto needle = needle0.data();
213 const auto *end = haystack;
214 haystack += from;
215 const std::size_t sl_minus_1 = sl ? sl - 1 : 0;
216 const auto *n = needle + sl_minus_1;
217 const auto *h = haystack + sl_minus_1;
218 std::size_t hashNeedle = 0, hashHaystack = 0;
219
220 if (cs == Qt::CaseSensitive) {
221 for (qsizetype idx = 0; idx < sl; ++idx) {
222 hashNeedle = (hashNeedle << 1) + valueTypeToUtf16(*(n - idx));
223 hashHaystack = (hashHaystack << 1) + valueTypeToUtf16(*(h - idx));
224 }
225 hashHaystack -= valueTypeToUtf16(*haystack);
226
227 while (haystack >= end) {
228 hashHaystack += valueTypeToUtf16(*haystack);
229 if (hashHaystack == hashNeedle
230 && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
231 return haystack - end;
232 --haystack;
233 REHASH(valueTypeToUtf16(haystack[sl]));
234 }
235 } else {
236 for (qsizetype idx = 0; idx < sl; ++idx) {
237 hashNeedle = (hashNeedle << 1) + foldCaseHelper(n - idx, needle);
238 hashHaystack = (hashHaystack << 1) + foldCaseHelper(h - idx, end);
239 }
240 hashHaystack -= foldCaseHelper(haystack, end);
241
242 while (haystack >= end) {
243 hashHaystack += foldCaseHelper(haystack, end);
244 if (hashHaystack == hashNeedle
245 && QtPrivate::compareStrings(sv(haystack), needle0, Qt::CaseInsensitive) == 0)
246 return haystack - end;
247 --haystack;
248 REHASH(foldCaseHelper(haystack + sl, end));
249 }
250 }
251 return -1;
252}
253
254template <typename Haystack, typename Needle>
255bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
256{
257 if (haystack.isNull())
258 return needle.isNull();
259 const auto haystackLen = haystack.size();
260 const auto needleLen = needle.size();
261 if (haystackLen == 0)
262 return needleLen == 0;
263 if (needleLen > haystackLen)
264 return false;
265
266 return QtPrivate::compareStrings(haystack.left(needleLen), needle, cs) == 0;
267}
268
269template <typename Haystack, typename Needle>
270bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
271{
272 if (haystack.isNull())
273 return needle.isNull();
274 const auto haystackLen = haystack.size();
275 const auto needleLen = needle.size();
276 if (haystackLen == 0)
277 return needleLen == 0;
278 if (haystackLen < needleLen)
279 return false;
280
281 return QtPrivate::compareStrings(haystack.right(needleLen), needle, cs) == 0;
282}
283
284template <typename T>
285static void append_helper(QString &self, T view)
286{
287 const auto strData = view.data();
288 const qsizetype strSize = view.size();
289 auto &d = self.data_ptr();
290 if (strData && strSize > 0) {
291 // the number of UTF-8 code units is always at a minimum equal to the number
292 // of equivalent UTF-16 code units
293 d.detachAndGrow(QArrayData::GrowsAtEnd, strSize, nullptr, nullptr);
294 Q_CHECK_PTR(d.data());
295 Q_ASSERT(strSize <= d.freeSpaceAtEnd());
296
297 auto dst = std::next(d.data(), d.size);
298 if constexpr (std::is_same_v<T, QUtf8StringView>) {
300 } else if constexpr (std::is_same_v<T, QLatin1StringView>) {
302 dst += strSize;
303 } else {
305 "Can only operate on UTF-8 and Latin-1");
306 }
307 self.resize(std::distance(d.begin(), dst));
308 } else if (d.isNull() && !view.isNull()) { // special case
310 }
311}
312
313template <uint MaxCount> struct UnrollTailLoop
314{
315 template <typename RetType, typename Functor1, typename Functor2, typename Number>
316 static inline RetType exec(Number count, RetType returnIfExited, Functor1 loopCheck, Functor2 returnIfFailed, Number i = 0)
317 {
318 /* equivalent to:
319 * while (count--) {
320 * if (loopCheck(i))
321 * return returnIfFailed(i);
322 * }
323 * return returnIfExited;
324 */
325
326 if (!count)
327 return returnIfExited;
328
329 bool check = loopCheck(i);
330 if (check)
331 return returnIfFailed(i);
332
333 return UnrollTailLoop<MaxCount - 1>::exec(count - 1, returnIfExited, loopCheck, returnIfFailed, i + 1);
334 }
335
336 template <typename Functor, typename Number>
337 static inline void exec(Number count, Functor code)
338 {
339 /* equivalent to:
340 * for (Number i = 0; i < count; ++i)
341 * code(i);
342 */
343 exec(count, 0, [=](Number i) -> bool { code(i); return false; }, [](Number) { return 0; });
344 }
345};
346template <> template <typename RetType, typename Functor1, typename Functor2, typename Number>
347inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, Functor2, Number)
348{
349 return returnIfExited;
350}
351} // unnamed namespace
352
353/*
354 * Note on the use of SIMD in qstring.cpp:
355 *
356 * Several operations with strings are improved with the use of SIMD code,
357 * since they are repetitive. For MIPS, we have hand-written assembly code
358 * outside of qstring.cpp targeting MIPS DSP and MIPS DSPr2. For ARM and for
359 * x86, we can only use intrinsics and therefore everything is contained in
360 * qstring.cpp. We need to use intrinsics only for those platforms due to the
361 * different compilers and toolchains used, which have different syntax for
362 * assembly sources.
363 *
364 * ** SSE notes: **
365 *
366 * Whenever multiple alternatives are equivalent or near so, we prefer the one
367 * using instructions from SSE2, since SSE2 is guaranteed to be enabled for all
368 * 64-bit builds and we enable it for 32-bit builds by default. Use of higher
369 * SSE versions should be done when there is a clear performance benefit and
370 * requires fallback code to SSE2, if it exists.
371 *
372 * Performance measurement in the past shows that most strings are short in
373 * size and, therefore, do not benefit from alignment prologues. That is,
374 * trying to find a 16-byte-aligned boundary to operate on is often more
375 * expensive than executing the unaligned operation directly. In addition, note
376 * that the QString private data is designed so that the data is stored on
377 * 16-byte boundaries if the system malloc() returns 16-byte aligned pointers
378 * on its own (64-bit glibc on Linux does; 32-bit glibc on Linux returns them
379 * 50% of the time), so skipping the alignment prologue is actually optimizing
380 * for the common case.
381 */
382
383#if defined(__mips_dsp)
384// From qstring_mips_dsp_asm.S
385extern "C" void qt_fromlatin1_mips_asm_unroll4 (char16_t*, const char*, uint);
386extern "C" void qt_fromlatin1_mips_asm_unroll8 (char16_t*, const char*, uint);
387extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const char16_t *src, int length);
388#endif
389
390#if defined(__SSE2__) && defined(Q_CC_GNU)
391// We may overrun the buffer, but that's a false positive:
392// this won't crash nor produce incorrect results
393# define ATTRIBUTE_NO_SANITIZE __attribute__((__no_sanitize_address__))
394#else
395# define ATTRIBUTE_NO_SANITIZE
396#endif
397
398#ifdef __SSE2__
399static constexpr bool UseSse4_1 = bool(qCompilerCpuFeatures & CpuFeatureSSE4_1);
400static constexpr bool UseAvx2 = UseSse4_1 &&
401 (qCompilerCpuFeatures & CpuFeatureArchHaswell) == CpuFeatureArchHaswell;
402
403[[maybe_unused]]
404static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr)
405{
406 const __m128i *dataptr = static_cast<const __m128i *>(ptr);
407 if constexpr (UseSse4_1) {
408 // use a MOVQ followed by PMOVZXBW
409 // if AVX2 is present, these should combine into a single VPMOVZXBW instruction
410 __m128i data = _mm_loadl_epi64(dataptr);
411 return _mm_cvtepu8_epi16(data);
412 }
413
414 // use MOVQ followed by PUNPCKLBW
415 __m128i data = _mm_loadl_epi64(dataptr);
416 return _mm_unpacklo_epi8(data, _mm_setzero_si128());
417}
418
419[[maybe_unused]] ATTRIBUTE_NO_SANITIZE
420static qsizetype qustrlen_sse2(const char16_t *str) noexcept
421{
422 // find the 16-byte alignment immediately prior or equal to str
423 quintptr misalignment = quintptr(str) & 0xf;
424 Q_ASSERT((misalignment & 1) == 0);
425 const char16_t *ptr = str - (misalignment / 2);
426
427 // load 16 bytes and see if we have a null
428 // (aligned loads can never segfault)
429 const __m128i zeroes = _mm_setzero_si128();
430 __m128i data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr));
431 __m128i comparison = _mm_cmpeq_epi16(data, zeroes);
432 uint mask = _mm_movemask_epi8(comparison);
433
434 // ignore the result prior to the beginning of str
435 mask >>= misalignment;
436
437 // Have we found something in the first block? Need to handle it now
438 // because of the left shift above.
439 if (mask)
440 return qCountTrailingZeroBits(mask) / sizeof(char16_t);
441
442 constexpr qsizetype Step = sizeof(__m128i) / sizeof(char16_t);
443 qsizetype size = Step - misalignment / sizeof(char16_t);
444
445 size -= Step;
446 do {
447 size += Step;
448 data = _mm_load_si128(reinterpret_cast<const __m128i *>(str + size));
449
450 comparison = _mm_cmpeq_epi16(data, zeroes);
451 mask = _mm_movemask_epi8(comparison);
452 } while (mask == 0);
453
454 // found a null
455 return size + qCountTrailingZeroBits(mask) / sizeof(char16_t);
456}
457
458// Scans from \a ptr to \a end until \a maskval is non-zero. Returns true if
459// the no non-zero was found. Returns false and updates \a ptr to point to the
460// first 16-bit word that has any bit set (note: if the input is 8-bit, \a ptr
461// may be updated to one byte short).
462static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
463{
464 auto updatePtr = [&](uint result) {
465 // found a character matching the mask
467 ptr += idx;
468 return false;
469 };
470
471 if constexpr (UseSse4_1) {
472# ifndef Q_OS_QNX // compiler fails in the code below
473 __m128i mask;
474 auto updatePtrSimd = [&](__m128i data) {
475 __m128i masked = _mm_and_si128(mask, data);
476 __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
477 uint result = _mm_movemask_epi8(comparison);
478 return updatePtr(result);
479 };
480
481 if constexpr (UseAvx2) {
482 // AVX2 implementation: test 32 bytes at a time
483 const __m256i mask256 = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(maskval));
484 while (ptr + 32 <= end) {
485 __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
486 if (!_mm256_testz_si256(mask256, data)) {
487 // found a character matching the mask
488 __m256i masked256 = _mm256_and_si256(mask256, data);
489 __m256i comparison256 = _mm256_cmpeq_epi16(masked256, _mm256_setzero_si256());
490 return updatePtr(_mm256_movemask_epi8(comparison256));
491 }
492 ptr += 32;
493 }
494
495 mask = _mm256_castsi256_si128(mask256);
496 } else {
497 // SSE 4.1 implementation: test 32 bytes at a time (two 16-byte
498 // comparisons, unrolled)
499 mask = _mm_set1_epi32(maskval);
500 while (ptr + 32 <= end) {
501 __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
502 __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16));
503 if (!_mm_testz_si128(mask, data1))
504 return updatePtrSimd(data1);
505
506 ptr += 16;
507 if (!_mm_testz_si128(mask, data2))
508 return updatePtrSimd(data2);
509 ptr += 16;
510 }
511 }
512
513 // AVX2 and SSE4.1: final 16-byte comparison
514 if (ptr + 16 <= end) {
515 __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
516 if (!_mm_testz_si128(mask, data1))
517 return updatePtrSimd(data1);
518 ptr += 16;
519 }
520
521 // and final 8-byte comparison
522 if (ptr + 8 <= end) {
523 __m128i data1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
524 if (!_mm_testz_si128(mask, data1))
525 return updatePtrSimd(data1);
526 ptr += 8;
527 }
528
529 return true;
530# endif // QNX
531 }
532
533 // SSE2 implementation: test 16 bytes at a time.
534 const __m128i mask = _mm_set1_epi32(maskval);
535 while (ptr + 16 <= end) {
536 __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
537 __m128i masked = _mm_and_si128(mask, data);
538 __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
539 quint16 result = _mm_movemask_epi8(comparison);
540 if (result != 0xffff)
541 return updatePtr(result);
542 ptr += 16;
543 }
544
545 // and one 8-byte comparison
546 if (ptr + 8 <= end) {
547 __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
548 __m128i masked = _mm_and_si128(mask, data);
549 __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
550 quint8 result = _mm_movemask_epi8(comparison);
551 if (result != 0xff)
552 return updatePtr(result);
553 ptr += 8;
554 }
555
556 return true;
557}
558
559template <StringComparisonMode Mode, typename Char> [[maybe_unused]]
560static int ucstrncmp_sse2(const char16_t *a, const Char *b, size_t l)
561{
562 static_assert(std::is_unsigned_v<Char>);
563
564 // Using the PMOVMSKB instruction, we get two bits for each UTF-16 character
565 // we compare. This lambda helps extract the code unit.
566 static const auto codeUnitAt = [](const auto *n, qptrdiff idx) -> int {
567 constexpr int Stride = 2;
568 // this is the same as:
569 // return n[idx / Stride];
570 // but using pointer arithmetic to avoid the compiler dividing by two
571 // and multiplying by two in the case of char16_t (we know idx is even,
572 // but the compiler does not). This is not UB.
573
574 auto ptr = reinterpret_cast<const uchar *>(n);
575 ptr += idx / (Stride / sizeof(*n));
576 return *reinterpret_cast<decltype(n)>(ptr);
577 };
578 auto difference = [a, b](uint mask, qptrdiff offset) {
579 if (Mode == CompareStringsForEquality)
580 return 1;
582 return codeUnitAt(a + offset, idx) - codeUnitAt(b + offset, idx);
583 };
584
585 static const auto load8Chars = [](const auto *ptr) {
586 if (sizeof(*ptr) == 2)
587 return _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
588 __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
589 return _mm_unpacklo_epi8(chunk, _mm_setzero_si128());
590 };
591 static const auto load4Chars = [](const auto *ptr) {
592 if (sizeof(*ptr) == 2)
593 return _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
594 __m128i chunk = _mm_cvtsi32_si128(qFromUnaligned<quint32>(ptr));
595 return _mm_unpacklo_epi8(chunk, _mm_setzero_si128());
596 };
597
598 // we're going to read a[0..15] and b[0..15] (32 bytes)
599 auto processChunk16Chars = [a, b](qptrdiff offset) -> uint {
600 if constexpr (UseAvx2) {
601 __m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset));
602 __m256i b_data;
603 if (sizeof(Char) == 1) {
604 // expand to UTF-16 via zero-extension
605 __m128i chunk = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
606 b_data = _mm256_cvtepu8_epi16(chunk);
607 } else {
608 b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset));
609 }
610 __m256i result = _mm256_cmpeq_epi16(a_data, b_data);
611 return _mm256_movemask_epi8(result);
612 }
613
614 __m128i a_data1 = load8Chars(a + offset);
615 __m128i a_data2 = load8Chars(a + offset + 8);
616 __m128i b_data1, b_data2;
617 if (sizeof(Char) == 1) {
618 // expand to UTF-16 via unpacking
619 __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
620 b_data1 = _mm_unpacklo_epi8(b_data, _mm_setzero_si128());
621 b_data2 = _mm_unpackhi_epi8(b_data, _mm_setzero_si128());
622 } else {
623 b_data1 = load8Chars(b + offset);
624 b_data2 = load8Chars(b + offset + 8);
625 }
626 __m128i result1 = _mm_cmpeq_epi16(a_data1, b_data1);
627 __m128i result2 = _mm_cmpeq_epi16(a_data2, b_data2);
628 return _mm_movemask_epi8(result1) | _mm_movemask_epi8(result2) << 16;
629 };
630
631 if (l >= sizeof(__m256i) / sizeof(char16_t)) {
632 qptrdiff offset = 0;
633 for ( ; l >= offset + sizeof(__m256i) / sizeof(char16_t); offset += sizeof(__m256i) / sizeof(char16_t)) {
634 uint mask = ~processChunk16Chars(offset);
635 if (mask)
636 return difference(mask, offset);
637 }
638
639 // maybe overlap the last 32 bytes
640 if (size_t(offset) < l) {
641 offset = l - sizeof(__m256i) / sizeof(char16_t);
642 uint mask = ~processChunk16Chars(offset);
643 return mask ? difference(mask, offset) : 0;
644 }
645 } else if (l >= 4) {
646 __m128i a_data1, b_data1;
647 __m128i a_data2, b_data2;
648 int width;
649 if (l >= 8) {
650 width = 8;
651 a_data1 = load8Chars(a);
652 b_data1 = load8Chars(b);
653 a_data2 = load8Chars(a + l - width);
654 b_data2 = load8Chars(b + l - width);
655 } else {
656 // we're going to read a[0..3] and b[0..3] (8 bytes)
657 width = 4;
658 a_data1 = load4Chars(a);
659 b_data1 = load4Chars(b);
660 a_data2 = load4Chars(a + l - width);
661 b_data2 = load4Chars(b + l - width);
662 }
663
664 __m128i result = _mm_cmpeq_epi16(a_data1, b_data1);
665 ushort mask = ~_mm_movemask_epi8(result);
666 if (mask)
667 return difference(mask, 0);
668
669 result = _mm_cmpeq_epi16(a_data2, b_data2);
670 mask = ~_mm_movemask_epi8(result);
671 if (mask)
672 return difference(mask, l - width);
673 } else {
674 // reset l
675 l &= 3;
676
677 const auto lambda = [=](size_t i) -> int {
678 return a[i] - b[i];
679 };
680 return UnrollTailLoop<3>::exec(l, 0, lambda, lambda);
681 }
682 return 0;
683}
684#endif
685
686qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
687{
688#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
689 return qustrlen_sse2(str);
690#endif
691
692 if (sizeof(wchar_t) == sizeof(char16_t))
693 return wcslen(reinterpret_cast<const wchar_t *>(str));
694
695 qsizetype result = 0;
696 while (*str++)
697 ++result;
698 return result;
699}
700
701qsizetype QtPrivate::qustrnlen(const char16_t *str, qsizetype maxlen) noexcept
702{
703 return qustrchr({ str, maxlen }, u'\0') - str;
704}
705
714const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
715{
716 const char16_t *n = str.utf16();
717 const char16_t *e = n + str.size();
718
719#ifdef __SSE2__
720 bool loops = true;
721 // Using the PMOVMSKB instruction, we get two bits for each character
722 // we compare.
723 __m128i mch;
724 if constexpr (UseAvx2) {
725 // we're going to read n[0..15] (32 bytes)
726 __m256i mch256 = _mm256_set1_epi32(c | (c << 16));
727 for (const char16_t *next = n + 16; next <= e; n = next, next += 16) {
728 __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n));
729 __m256i result = _mm256_cmpeq_epi16(data, mch256);
730 uint mask = uint(_mm256_movemask_epi8(result));
731 if (mask) {
733 return n + idx / 2;
734 }
735 }
736 loops = false;
737 mch = _mm256_castsi256_si128(mch256);
738 } else {
739 mch = _mm_set1_epi32(c | (c << 16));
740 }
741
742 auto hasMatch = [mch, &n](__m128i data, ushort validityMask) {
743 __m128i result = _mm_cmpeq_epi16(data, mch);
744 uint mask = uint(_mm_movemask_epi8(result));
745 if ((mask & validityMask) == 0)
746 return false;
748 n += idx / 2;
749 return true;
750 };
751
752 // we're going to read n[0..7] (16 bytes)
753 for (const char16_t *next = n + 8; next <= e; n = next, next += 8) {
754 __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(n));
755 if (hasMatch(data, 0xffff))
756 return n;
757
758 if (!loops) {
759 n += 8;
760 break;
761 }
762 }
763
764# if !defined(__OPTIMIZE_SIZE__)
765 // we're going to read n[0..3] (8 bytes)
766 if (e - n > 3) {
767 __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(n));
768 if (hasMatch(data, 0xff))
769 return n;
770
771 n += 4;
772 }
773
774 return UnrollTailLoop<3>::exec(e - n, e,
775 [=](qsizetype i) { return n[i] == c; },
776 [=](qsizetype i) { return n + i; });
777# endif
778#elif defined(__ARM_NEON__)
779 const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
780 const uint16x8_t ch_vec = vdupq_n_u16(c);
781 for (const char16_t *next = n + 8; next <= e; n = next, next += 8) {
782 uint16x8_t data = vld1q_u16(reinterpret_cast<const uint16_t *>(n));
783 uint mask = vaddvq_u16(vandq_u16(vceqq_u16(data, ch_vec), vmask));
784 if (ushort(mask)) {
785 // found a match
786 return n + qCountTrailingZeroBits(mask);
787 }
788 }
789#endif // aarch64
790
791 return std::find(n, e, c);
792}
793
794// Note: ptr on output may be off by one and point to a preceding US-ASCII
795// character. Usually harmless.
796bool qt_is_ascii(const char *&ptr, const char *end) noexcept
797{
798#if defined(__SSE2__)
799 // Testing for the high bit can be done efficiently with just PMOVMSKB
800 bool loops = true;
801 if constexpr (UseAvx2) {
802 while (ptr + 32 <= end) {
803 __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
804 quint32 mask = _mm256_movemask_epi8(data);
805 if (mask) {
807 ptr += idx;
808 return false;
809 }
810 ptr += 32;
811 }
812 loops = false;
813 }
814
815 while (ptr + 16 <= end) {
816 __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
817 quint32 mask = _mm_movemask_epi8(data);
818 if (mask) {
820 ptr += idx;
821 return false;
822 }
823 ptr += 16;
824
825 if (!loops)
826 break;
827 }
828 if (ptr + 8 <= end) {
829 __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
830 quint8 mask = _mm_movemask_epi8(data);
831 if (mask) {
833 ptr += idx;
834 return false;
835 }
836 ptr += 8;
837 }
838#endif
839
840 while (ptr + 4 <= end) {
841 quint32 data = qFromUnaligned<quint32>(ptr);
842 if (data &= 0x80808080U) {
846 ptr += idx / 8;
847 return false;
848 }
849 ptr += 4;
850 }
851
852 while (ptr != end) {
853 if (quint8(*ptr) & 0x80)
854 return false;
855 ++ptr;
856 }
857 return true;
858}
859
861{
862 const char *ptr = s.begin();
863 const char *end = s.end();
864
865 return qt_is_ascii(ptr, end);
866}
867
868static bool isAscii_helper(const char16_t *&ptr, const char16_t *end)
869{
870#ifdef __SSE2__
871 const char *ptr8 = reinterpret_cast<const char *>(ptr);
872 const char *end8 = reinterpret_cast<const char *>(end);
873 bool ok = simdTestMask(ptr8, end8, 0xff80ff80);
874 ptr = reinterpret_cast<const char16_t *>(ptr8);
875 if (!ok)
876 return false;
877#endif
878
879 while (ptr != end) {
880 if (*ptr & 0xff80)
881 return false;
882 ++ptr;
883 }
884 return true;
885}
886
888{
889 const char16_t *ptr = s.utf16();
890 const char16_t *end = ptr + s.size();
891
892 return isAscii_helper(ptr, end);
893}
894
896{
897 const char16_t *ptr = s.utf16();
898 const char16_t *end = ptr + s.size();
899
900#ifdef __SSE2__
901 const char *ptr8 = reinterpret_cast<const char *>(ptr);
902 const char *end8 = reinterpret_cast<const char *>(end);
903 if (!simdTestMask(ptr8, end8, 0xff00ff00))
904 return false;
905 ptr = reinterpret_cast<const char16_t *>(ptr8);
906#endif
907
908 while (ptr != end) {
909 if (*ptr++ > 0xff)
910 return false;
911 }
912 return true;
913}
914
916{
917 constexpr char32_t InvalidCodePoint = UINT_MAX;
918
920 while (i.hasNext()) {
921 const char32_t c = i.next(InvalidCodePoint);
922 if (c == InvalidCodePoint)
923 return false;
924 }
925
926 return true;
927}
928
929// conversion between Latin 1 and UTF-16
930Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept
931{
932 /* SIMD:
933 * Unpacking with SSE has been shown to improve performance on recent CPUs
934 * The same method gives no improvement with NEON. On Aarch64, clang will do the vectorization
935 * itself in exactly the same way as one would do it with intrinsics.
936 */
937#if defined(__SSE2__)
938 // we're going to read str[offset..offset+15] (16 bytes)
939 const __m128i nullMask = _mm_setzero_si128();
940 auto processOneChunk = [=](qptrdiff offset) {
941 const __m128i chunk = _mm_loadu_si128((const __m128i*)(str + offset)); // load
942 if constexpr (UseAvx2) {
943 // zero extend to an YMM register
944 const __m256i extended = _mm256_cvtepu8_epi16(chunk);
945
946 // store
947 _mm256_storeu_si256((__m256i*)(dst + offset), extended);
948 } else {
949 // unpack the first 8 bytes, padding with zeros
950 const __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullMask);
951 _mm_storeu_si128((__m128i*)(dst + offset), firstHalf); // store
952
953 // unpack the last 8 bytes, padding with zeros
954 const __m128i secondHalf = _mm_unpackhi_epi8 (chunk, nullMask);
955 _mm_storeu_si128((__m128i*)(dst + offset + 8), secondHalf); // store
956 }
957 };
958
959 const char *e = str + size;
960 if (size >= sizeof(__m128i)) {
961 qptrdiff offset = 0;
962 for ( ; str + offset + sizeof(__m128i) <= e; offset += sizeof(__m128i))
963 processOneChunk(offset);
964 if (str + offset < e)
965 processOneChunk(size - sizeof(__m128i));
966 return;
967 }
968
969# if !defined(__OPTIMIZE_SIZE__)
970 if (size >= 4) {
971 // two overlapped loads & stores, of either 64-bit or of 32-bit
972 if (size >= 8) {
973 const __m128i unpacked1 = mm_load8_zero_extend(str);
974 const __m128i unpacked2 = mm_load8_zero_extend(str + size - 8);
975 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), unpacked1);
976 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + size - 8), unpacked2);
977 } else {
978 const __m128i chunk1 = _mm_cvtsi32_si128(qFromUnaligned<quint32>(str));
979 const __m128i chunk2 = _mm_cvtsi32_si128(qFromUnaligned<quint32>(str + size - 4));
980 const __m128i unpacked1 = _mm_unpacklo_epi8(chunk1, nullMask);
981 const __m128i unpacked2 = _mm_unpacklo_epi8(chunk2, nullMask);
982 _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), unpacked1);
983 _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + size - 4), unpacked2);
984 }
985 return;
986 } else {
987 size = size % 4;
988 return UnrollTailLoop<3>::exec(qsizetype(size), [=](qsizetype i) { dst[i] = uchar(str[i]); });
989 }
990# endif
991#endif
992#if defined(__mips_dsp)
993 static_assert(sizeof(qsizetype) == sizeof(int),
994 "oops, the assembler implementation needs to be called in a loop");
995 if (size > 20)
996 qt_fromlatin1_mips_asm_unroll8(dst, str, size);
997 else
998 qt_fromlatin1_mips_asm_unroll4(dst, str, size);
999#else
1000 while (size--)
1001 *dst++ = (uchar)*str++;
1002#endif
1003}
1004
1006{
1007 const qsizetype len = str.size();
1009 qt_from_latin1(arr.data(), str.data(), len);
1010 return arr;
1011}
1012
1013template <bool Checked>
1014static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype length)
1015{
1016#if defined(__SSE2__)
1017 auto questionMark256 = []() {
1018 if constexpr (UseAvx2)
1019 return _mm256_broadcastw_epi16(_mm_cvtsi32_si128('?'));
1020 else
1021 return 0;
1022 }();
1023 auto outOfRange256 = []() {
1024 if constexpr (UseAvx2)
1025 return _mm256_broadcastw_epi16(_mm_cvtsi32_si128(0x100));
1026 else
1027 return 0;
1028 }();
1029 __m128i questionMark, outOfRange;
1030 if constexpr (UseAvx2) {
1031 questionMark = _mm256_castsi256_si128(questionMark256);
1032 outOfRange = _mm256_castsi256_si128(outOfRange256);
1033 } else {
1034 questionMark = _mm_set1_epi16('?');
1035 outOfRange = _mm_set1_epi16(0x100);
1036 }
1037
1038 auto mergeQuestionMarks = [=](__m128i chunk) {
1039 if (!Checked)
1040 return chunk;
1041
1042 // SSE has no compare instruction for unsigned comparison.
1043 if constexpr (UseSse4_1) {
1044 // We use an unsigned uc = qMin(uc, 0x100) and then compare for equality.
1045 chunk = _mm_min_epu16(chunk, outOfRange);
1046 const __m128i offLimitMask = _mm_cmpeq_epi16(chunk, outOfRange);
1047 chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
1048 return chunk;
1049 }
1050 // The variables must be shiffted + 0x8000 to be compared
1051 const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000));
1052 const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000));
1053
1054 const __m128i signedChunk = _mm_add_epi16(chunk, signedBitOffset);
1055 const __m128i offLimitMask = _mm_cmpgt_epi16(signedChunk, thresholdMask);
1056
1057 // offLimitQuestionMark contains '?' for each 16 bits that was off-limit
1058 // the 16 bits that were correct contains zeros
1059 const __m128i offLimitQuestionMark = _mm_and_si128(offLimitMask, questionMark);
1060
1061 // correctBytes contains the bytes that were in limit
1062 // the 16 bits that were off limits contains zeros
1063 const __m128i correctBytes = _mm_andnot_si128(offLimitMask, chunk);
1064
1065 // merge offLimitQuestionMark and correctBytes to have the result
1066 chunk = _mm_or_si128(correctBytes, offLimitQuestionMark);
1067
1068 Q_UNUSED(outOfRange);
1069 return chunk;
1070 };
1071
1072 // we're going to read to src[offset..offset+15] (16 bytes)
1073 auto loadChunkAt = [=](qptrdiff offset) {
1074 __m128i chunk1, chunk2;
1075 if constexpr (UseAvx2) {
1076 __m256i chunk = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + offset));
1077 if (Checked) {
1078 // See mergeQuestionMarks lambda above for details
1079 chunk = _mm256_min_epu16(chunk, outOfRange256);
1080 const __m256i offLimitMask = _mm256_cmpeq_epi16(chunk, outOfRange256);
1081 chunk = _mm256_blendv_epi8(chunk, questionMark256, offLimitMask);
1082 }
1083
1084 chunk2 = _mm256_extracti128_si256(chunk, 1);
1085 chunk1 = _mm256_castsi256_si128(chunk);
1086 } else {
1087 chunk1 = _mm_loadu_si128((const __m128i*)(src + offset)); // load
1088 chunk1 = mergeQuestionMarks(chunk1);
1089
1090 chunk2 = _mm_loadu_si128((const __m128i*)(src + offset + 8)); // load
1091 chunk2 = mergeQuestionMarks(chunk2);
1092 }
1093
1094 // pack the two vector to 16 x 8bits elements
1095 return _mm_packus_epi16(chunk1, chunk2);
1096 };
1097
1098 if (size_t(length) >= sizeof(__m128i)) {
1099 // because of possible overlapping, we won't process the last chunk in the loop
1100 qptrdiff offset = 0;
1101 for ( ; offset + 2 * sizeof(__m128i) < size_t(length); offset += sizeof(__m128i))
1102 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), loadChunkAt(offset));
1103
1104 // overlapped conversion of the last full chunk and the tail
1105 __m128i last1 = loadChunkAt(offset);
1106 __m128i last2 = loadChunkAt(length - sizeof(__m128i));
1107 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), last1);
1108 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + length - sizeof(__m128i)), last2);
1109 return;
1110 }
1111
1112# if !defined(__OPTIMIZE_SIZE__)
1113 if (length >= 4) {
1114 // this code is fine even for in-place conversion because we load both
1115 // before any store
1116 if (length >= 8) {
1117 __m128i chunk1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src));
1118 __m128i chunk2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + length - 8));
1119 chunk1 = mergeQuestionMarks(chunk1);
1120 chunk2 = mergeQuestionMarks(chunk2);
1121
1122 // pack, where the upper half is ignored
1123 const __m128i result1 = _mm_packus_epi16(chunk1, chunk1);
1124 const __m128i result2 = _mm_packus_epi16(chunk2, chunk2);
1125 _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), result1);
1126 _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + length - 8), result2);
1127 } else {
1128 __m128i chunk1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src));
1129 __m128i chunk2 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src + length - 4));
1130 chunk1 = mergeQuestionMarks(chunk1);
1131 chunk2 = mergeQuestionMarks(chunk2);
1132
1133 // pack, we'll zero the upper three quarters
1134 const __m128i result1 = _mm_packus_epi16(chunk1, chunk1);
1135 const __m128i result2 = _mm_packus_epi16(chunk2, chunk2);
1136 qToUnaligned(_mm_cvtsi128_si32(result1), dst);
1137 qToUnaligned(_mm_cvtsi128_si32(result2), dst + length - 4);
1138 }
1139 return;
1140 }
1141
1142 length = length % 4;
1143 return UnrollTailLoop<3>::exec(length, [=](qsizetype i) {
1144 if (Checked)
1145 dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i];
1146 else
1147 dst[i] = src[i];
1148 });
1149# else
1150 length = length % 16;
1151# endif // optimize size
1152#elif defined(__ARM_NEON__)
1153 // Refer to the documentation of the SSE2 implementation.
1154 // This uses exactly the same method as for SSE except:
1155 // 1) neon has unsigned comparison
1156 // 2) packing is done to 64 bits (8 x 8bits component).
1157 if (length >= 16) {
1158 const qsizetype chunkCount = length >> 3; // divided by 8
1159 const uint16x8_t questionMark = vdupq_n_u16('?'); // set
1160 const uint16x8_t thresholdMask = vdupq_n_u16(0xff); // set
1161 for (qsizetype i = 0; i < chunkCount; ++i) {
1162 uint16x8_t chunk = vld1q_u16((uint16_t *)src); // load
1163 src += 8;
1164
1165 if (Checked) {
1166 const uint16x8_t offLimitMask = vcgtq_u16(chunk, thresholdMask); // chunk > thresholdMask
1167 const uint16x8_t offLimitQuestionMark = vandq_u16(offLimitMask, questionMark); // offLimitMask & questionMark
1168 const uint16x8_t correctBytes = vbicq_u16(chunk, offLimitMask); // !offLimitMask & chunk
1169 chunk = vorrq_u16(correctBytes, offLimitQuestionMark); // correctBytes | offLimitQuestionMark
1170 }
1171 const uint8x8_t result = vmovn_u16(chunk); // narrowing move->packing
1172 vst1_u8(dst, result); // store
1173 dst += 8;
1174 }
1175 length = length % 8;
1176 }
1177#endif
1178#if defined(__mips_dsp)
1179 static_assert(sizeof(qsizetype) == sizeof(int),
1180 "oops, the assembler implementation needs to be called in a loop");
1181 qt_toLatin1_mips_dsp_asm(dst, src, length);
1182#else
1183 while (length--) {
1184 if (Checked)
1185 *dst++ = (*src>0xff) ? '?' : (uchar) *src;
1186 else
1187 *dst++ = *src;
1188 ++src;
1189 }
1190#endif
1191}
1192
1193void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length)
1194{
1195 qt_to_latin1_internal<true>(dst, src, length);
1196}
1197
1199{
1200 qt_to_latin1_internal<false>(dst, src, length);
1201}
1202
1203// Unicode case-insensitive comparison (argument order matches QStringView)
1204Q_NEVER_INLINE static int ucstricmp(qsizetype alen, const char16_t *a, qsizetype blen, const char16_t *b)
1205{
1206 if (a == b)
1207 return qt_lencmp(alen, blen);
1208
1209 char32_t alast = 0;
1210 char32_t blast = 0;
1211 qsizetype l = qMin(alen, blen);
1212 qsizetype i;
1213 for (i = 0; i < l; ++i) {
1214// qDebug() << Qt::hex << alast << blast;
1215// qDebug() << Qt::hex << "*a=" << *a << "alast=" << alast << "folded=" << foldCase (*a, alast);
1216// qDebug() << Qt::hex << "*b=" << *b << "blast=" << blast << "folded=" << foldCase (*b, blast);
1217 int diff = foldCase(a[i], alast) - foldCase(b[i], blast);
1218 if ((diff))
1219 return diff;
1220 }
1221 if (i == alen) {
1222 if (i == blen)
1223 return 0;
1224 return -1;
1225 }
1226 return 1;
1227}
1228
1229// Case-insensitive comparison between a QStringView and a QLatin1StringView
1230// (argument order matches those types)
1231Q_NEVER_INLINE static int ucstricmp(qsizetype alen, const char16_t *a, qsizetype blen, const char *b)
1232{
1233 qsizetype l = qMin(alen, blen);
1234 qsizetype i;
1235 for (i = 0; i < l; ++i) {
1236 int diff = foldCase(a[i]) - foldCase(char16_t{uchar(b[i])});
1237 if ((diff))
1238 return diff;
1239 }
1240 if (i == alen) {
1241 if (i == blen)
1242 return 0;
1243 return -1;
1244 }
1245 return 1;
1246}
1247
1248// Case-insensitive comparison between a Unicode string and a UTF-8 string
1249Q_NEVER_INLINE static int ucstricmp8(const char *utf8, const char *utf8end, const QChar *utf16, const QChar *utf16end)
1250{
1251 auto src1 = reinterpret_cast<const uchar *>(utf8);
1252 auto end1 = reinterpret_cast<const uchar *>(utf8end);
1253 QStringIterator src2(utf16, utf16end);
1254
1255 while (src1 < end1 && src2.hasNext()) {
1256 char32_t uc1 = 0;
1257 char32_t *output = &uc1;
1258 uchar b = *src1++;
1259 const qsizetype res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, output, src1, end1);
1260 if (res < 0) {
1261 // decoding error
1263 } else {
1264 uc1 = QChar::toCaseFolded(uc1);
1265 }
1266
1267 char32_t uc2 = QChar::toCaseFolded(src2.next());
1268 int diff = uc1 - uc2; // can't underflow
1269 if (diff)
1270 return diff;
1271 }
1272
1273 // the shorter string sorts first
1274 return (end1 > src1) - int(src2.hasNext());
1275}
1276
1277#if defined(__mips_dsp)
1278// From qstring_mips_dsp_asm.S
1279extern "C" int qt_ucstrncmp_mips_dsp_asm(const char16_t *a,
1280 const char16_t *b,
1281 unsigned len);
1282#endif
1283
1284// Unicode case-sensitive compare two same-sized strings
1285template <StringComparisonMode Mode>
1286static int ucstrncmp(const char16_t *a, const char16_t *b, size_t l)
1287{
1288 // This function isn't memcmp() because that can return the wrong sorting
1289 // result in little-endian architectures: 0x00ff must sort before 0x0100,
1290 // but the bytes in memory are FF 00 and 00 01.
1291
1292#ifndef __OPTIMIZE_SIZE__
1293# if defined(__mips_dsp)
1294 static_assert(sizeof(uint) == sizeof(size_t));
1295 if (l >= 8) {
1296 return qt_ucstrncmp_mips_dsp_asm(a, b, l);
1297 }
1298# elif defined(__SSE2__)
1299 return ucstrncmp_sse2<Mode>(a, b, l);
1300# elif defined(__ARM_NEON__)
1301 if (l >= 8) {
1302 const char16_t *end = a + l;
1303 const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
1304 while (end - a > 7) {
1305 uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
1306 uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));
1307
1308 uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
1309 if (r) {
1310 // found a different QChar
1311 if (Mode == CompareStringsForEquality)
1312 return 1;
1314 return a[idx] - b[idx];
1315 }
1316 a += 8;
1317 b += 8;
1318 }
1319 l &= 7;
1320 }
1321 const auto lambda = [=](size_t i) -> int {
1322 return a[i] - b[i];
1323 };
1324 return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
1325# endif // MIPS DSP or __SSE2__ or __ARM_NEON__
1326#endif // __OPTIMIZE_SIZE__
1327
1328 if (Mode == CompareStringsForEquality || QSysInfo::ByteOrder == QSysInfo::BigEndian)
1329 return memcmp(a, b, l * sizeof(char16_t));
1330
1331 for (size_t i = 0; i < l; ++i) {
1332 if (int diff = a[i] - b[i])
1333 return diff;
1334 }
1335 return 0;
1336}
1337
1338template <StringComparisonMode Mode>
1339static int ucstrncmp(const char16_t *a, const char *b, size_t l)
1340{
1341 const uchar *c = reinterpret_cast<const uchar *>(b);
1342 const char16_t *uc = a;
1343 const char16_t *e = uc + l;
1344
1345#if defined(__SSE2__) && !defined(__OPTIMIZE_SIZE__)
1346 return ucstrncmp_sse2<Mode>(uc, c, l);
1347#endif
1348
1349 while (uc < e) {
1350 int diff = *uc - *c;
1351 if (diff)
1352 return diff;
1353 uc++, c++;
1354 }
1355
1356 return 0;
1357}
1358
1359// Unicode case-sensitive equality
1360template <typename Char2>
1361static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
1362{
1363 if (alen != blen)
1364 return false;
1365 if constexpr (std::is_same_v<decltype(a), decltype(b)>) {
1366 if (a == b)
1367 return true;
1368 }
1369 return ucstrncmp<CompareStringsForEquality>(a, b, alen) == 0;
1370}
1371
1372// Unicode case-sensitive comparison
1373template <typename Char2>
1374static int ucstrcmp(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
1375{
1376 if constexpr (std::is_same_v<decltype(a), decltype(b)>) {
1377 if (a == b && alen == blen)
1378 return 0;
1379 }
1380 const size_t l = qMin(alen, blen);
1381 int cmp = ucstrncmp<CompareStringsForOrdering>(a, b, l);
1382 return cmp ? cmp : qt_lencmp(alen, blen);
1383}
1384
1386
1387static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar, qsizetype rSize)
1388{
1389 // We're called with QLatin1StringView's .data() and .size():
1390 Q_ASSERT(lSize >= 0 && rSize >= 0);
1391 if (!lSize)
1392 return rSize ? -1 : 0;
1393 if (!rSize)
1394 return 1;
1395 const qsizetype size = std::min(lSize, rSize);
1396
1397 Q_ASSERT(lhsChar && rhsChar); // since both lSize and rSize are positive
1398 for (qsizetype i = 0; i < size; i++) {
1399 if (int res = CaseInsensitiveL1::difference(lhsChar[i], rhsChar[i]))
1400 return res;
1401 }
1402 return qt_lencmp(lSize, rSize);
1403}
1404
1406{
1407 return ucstreq(lhs.utf16(), lhs.size(), rhs.utf16(), rhs.size());
1408}
1409
1411{
1412 return ucstreq(lhs.utf16(), lhs.size(), rhs.latin1(), rhs.size());
1413}
1414
1416{
1417 return QtPrivate::equalStrings(rhs, lhs);
1418}
1419
1421{
1422 return QByteArrayView(lhs) == QByteArrayView(rhs);
1423}
1424
1426{
1427 return QUtf8::compareUtf8(lhs, rhs) == 0;
1428}
1429
1431{
1432 return QtPrivate::equalStrings(rhs, lhs);
1433}
1434
1436{
1437 return QUtf8::compareUtf8(QByteArrayView(rhs), lhs) == 0;
1438}
1439
1441{
1442 return QtPrivate::equalStrings(rhs, lhs);
1443}
1444
1446{
1447 return lhs.size() == rhs.size() && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
1448}
1449
1451{
1452 if (lhs.size() != rhs.size() && lhs.isUtf8() == rhs.isUtf8())
1453 return false;
1454 return lhs.visit([rhs](auto lhs) {
1455 return rhs.visit([lhs](auto rhs) {
1456 return QtPrivate::equalStrings(lhs, rhs);
1457 });
1458 });
1459}
1460
1477{
1478 if (cs == Qt::CaseSensitive)
1479 return ucstrcmp(lhs.utf16(), lhs.size(), rhs.utf16(), rhs.size());
1480 return ucstricmp(lhs.size(), lhs.utf16(), rhs.size(), rhs.utf16());
1481}
1482
1500{
1501 if (cs == Qt::CaseSensitive)
1502 return ucstrcmp(lhs.utf16(), lhs.size(), rhs.latin1(), rhs.size());
1503 return ucstricmp(lhs.size(), lhs.utf16(), rhs.size(), rhs.latin1());
1504}
1505
1513{
1514 return -compareStrings(rhs, lhs, cs);
1515}
1516
1524{
1525 return -compareStrings(rhs, lhs, cs);
1526}
1527
1545{
1546 if (lhs.isEmpty())
1547 return qt_lencmp(qsizetype(0), rhs.size());
1548 if (cs == Qt::CaseInsensitive)
1549 return latin1nicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size());
1550 const auto l = std::min(lhs.size(), rhs.size());
1551 int r = memcmp(lhs.data(), rhs.data(), l);
1552 return r ? r : qt_lencmp(lhs.size(), rhs.size());
1553}
1554
1562{
1563 return -QUtf8::compareUtf8(QByteArrayView(rhs), lhs, cs);
1564}
1565
1573{
1574 if (cs == Qt::CaseSensitive)
1575 return QUtf8::compareUtf8(lhs, rhs);
1576 return ucstricmp8(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1577}
1578
1586{
1587 return -compareStrings(rhs, lhs, cs);
1588}
1589
1597{
1598 return QUtf8::compareUtf8(QByteArrayView(lhs), QByteArrayView(rhs), cs);
1599}
1600
1602{
1603 return lhs.visit([rhs, cs](auto lhs) {
1604 return rhs.visit([lhs, cs](auto rhs) {
1605 return QtPrivate::compareStrings(lhs, rhs, cs);
1606 });
1607 });
1608}
1609
1610// ### Qt 7: do not allow anything but ASCII digits
1611// in arg()'s replacements.
1612#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1613static bool supportUnicodeDigitValuesInArg()
1614{
1615 static const bool result = []() {
1616 static const char supportUnicodeDigitValuesEnvVar[]
1617 = "QT_USE_UNICODE_DIGIT_VALUES_IN_STRING_ARG";
1618
1619 if (qEnvironmentVariableIsSet(supportUnicodeDigitValuesEnvVar))
1620 return qEnvironmentVariableIntValue(supportUnicodeDigitValuesEnvVar) != 0;
1621
1622#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) // keep it in sync with the test
1623 return true;
1624#else
1625 return false;
1626#endif
1627 }();
1628
1629 return result;
1630}
1631#endif
1632
1633static int qArgDigitValue(QChar ch) noexcept
1634{
1635#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1636 if (supportUnicodeDigitValuesInArg())
1637 return ch.digitValue();
1638#endif
1639 if (ch >= u'0' && ch <= u'9')
1640 return int(ch.unicode() - u'0');
1641 return -1;
1642}
1643
1644#if QT_CONFIG(regularexpression)
1646void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *where);
1647#endif
1648
2202
2205
2372/*
2374Returns a copy of the \a str string. The given string is assumed to be
2375encoded in \1, and is converted to QString using the \2 function.
2377*/
2378
2424qsizetype QString::toUcs4_helper(const char16_t *uc, qsizetype length, char32_t *out)
2425{
2426 qsizetype count = 0;
2427
2429 while (i.hasNext())
2430 out[count++] = i.next();
2431
2432 return count;
2433}
2434
2483{
2484 if (!unicode) {
2485 d.clear();
2486 } else {
2487 if (size < 0) {
2488 size = 0;
2489 while (!unicode[size].isNull())
2490 ++size;
2491 }
2492 if (!size) {
2493 d = DataPointer::fromRawData(&_empty, 0);
2494 } else {
2496 Q_CHECK_PTR(d.data());
2497 memcpy(d.data(), unicode, size * sizeof(QChar));
2498 d.data()[size] = '\0';
2499 }
2500 }
2501}
2502
2510{
2511 if (size <= 0) {
2512 d = DataPointer::fromRawData(&_empty, 0);
2513 } else {
2515 Q_CHECK_PTR(d.data());
2516 d.data()[size] = '\0';
2517 char16_t *b = d.data();
2518 char16_t *e = d.data() + size;
2519 const char16_t value = ch.unicode();
2520 std::fill(b, e, value);
2521 }
2522}
2523
2531{
2532 if (size <= 0) {
2533 d = DataPointer::fromRawData(&_empty, 0);
2534 } else {
2536 Q_CHECK_PTR(d.data());
2537 d.data()[size] = '\0';
2538 }
2539}
2540
2552{
2553 d = DataPointer(Data::allocate(1), 1);
2554 Q_CHECK_PTR(d.data());
2555 d.data()[0] = ch.unicode();
2556 d.data()[1] = '\0';
2557}
2558
2617static bool needsReallocate(const QString &str, qsizetype newSize)
2618{
2619 const auto capacityAtEnd = str.capacity() - str.data_ptr().freeSpaceAtBegin();
2620 return newSize > capacityAtEnd;
2621}
2622
2655{
2656 if (size < 0)
2657 size = 0;
2658
2659 if (d->needsDetach() || needsReallocate(*this, size))
2660 reallocData(size, QArrayData::Grow);
2661 d.size = size;
2662 if (d->allocatedCapacity())
2663 d.data()[size] = u'\0';
2664}
2665
2676void QString::resize(qsizetype newSize, QChar fillChar)
2677{
2678 const qsizetype oldSize = size();
2679 resize(newSize);
2680 const qsizetype difference = size() - oldSize;
2681 if (difference > 0)
2682 std::fill_n(d.data() + oldSize, difference, fillChar.unicode());
2683}
2684
2753void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
2754{
2755 if (!alloc) {
2756 d = DataPointer::fromRawData(&_empty, 0);
2757 return;
2758 }
2759
2760 // don't use reallocate path when reducing capacity and there's free space
2761 // at the beginning: might shift data pointer outside of allocated space
2762 const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
2763
2764 if (d->needsDetach() || cannotUseReallocate) {
2765 DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size));
2766 Q_CHECK_PTR(dd.data());
2767 if (dd.size > 0)
2768 ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
2769 dd.data()[dd.size] = 0;
2770 d = dd;
2771 } else {
2772 d->reallocate(alloc, option);
2773 }
2774}
2775
2776void QString::reallocGrowData(qsizetype n)
2777{
2778 if (!n) // expected to always allocate
2779 n = 1;
2780
2781 if (d->needsDetach()) {
2783 Q_CHECK_PTR(dd.data());
2784 dd->copyAppend(d.data(), d.data() + d.size);
2785 dd.data()[dd.size] = 0;
2786 d = dd;
2787 } else {
2788 d->reallocate(d.constAllocatedCapacity() + n, QArrayData::Grow);
2789 }
2790}
2791
2806{
2807 d = other.d;
2808 return *this;
2809}
2810
2826{
2827 const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
2828 if (isDetached() && other.size() <= capacityAtEnd) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
2829 d.size = other.size();
2830 d.data()[other.size()] = 0;
2831 qt_from_latin1(d.data(), other.latin1(), other.size());
2832 } else {
2833 *this = fromLatin1(other.latin1(), other.size());
2834 }
2835 return *this;
2836}
2837
2870{
2871 const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
2872 if (isDetached() && capacityAtEnd >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
2873 // re-use existing capacity:
2874 d.data()[0] = ch.unicode();
2875 d.data()[1] = 0;
2876 d.size = 1;
2877 } else {
2879 }
2880 return *this;
2881}
2882
2894
2898
2946template <typename T>
2947static void insert_helper(QString &str, qsizetype i, const T &toInsert)
2948{
2949 auto &str_d = str.data_ptr();
2950 qsizetype difference = 0;
2951 if (Q_UNLIKELY(i > str_d.size))
2952 difference = i - str_d.size;
2953 const qsizetype oldSize = str_d.size;
2954 const qsizetype insert_size = toInsert.size();
2955 const qsizetype newSize = str_d.size + difference + insert_size;
2956 const auto side = i == 0 ? QArrayData::GrowsAtBeginning : QArrayData::GrowsAtEnd;
2957
2958 if (str_d.needsDetach() || needsReallocate(str, newSize)) {
2959 const auto cbegin = str.cbegin();
2960 const auto cend = str.cend();
2961 const auto insert_start = difference == 0 ? std::next(cbegin, i) : cend;
2962 QString other;
2963 // Using detachAndGrow() so that prepend optimization works and QStringBuilder
2964 // unittests pass
2965 other.data_ptr().detachAndGrow(side, newSize, nullptr, nullptr);
2966 other.append(QStringView(cbegin, insert_start));
2967 other.resize(i, u' ');
2968 other.append(toInsert);
2969 other.append(QStringView(insert_start, cend));
2970 str.swap(other);
2971 return;
2972 }
2973
2974 str_d.detachAndGrow(side, difference + insert_size, nullptr, nullptr);
2975 Q_CHECK_PTR(str_d.data());
2976 str.resize(newSize);
2977
2978 auto begin = str_d.begin();
2979 auto old_end = std::next(begin, oldSize);
2980 std::fill_n(old_end, difference, u' ');
2981 auto insert_start = std::next(begin, i);
2982 if (difference == 0)
2983 std::move_backward(insert_start, old_end, str_d.end());
2984
2985 using Char = std::remove_cv_t<typename T::value_type>;
2986 if constexpr(std::is_same_v<Char, QChar>)
2987 std::copy_n(reinterpret_cast<const char16_t *>(toInsert.data()), insert_size, insert_start);
2988 else if constexpr (std::is_same_v<Char, char16_t>)
2989 std::copy_n(toInsert.data(), insert_size, insert_start);
2990 else if constexpr (std::is_same_v<Char, char>)
2991 qt_from_latin1(insert_start, toInsert.data(), insert_size);
2992}
2993
3003{
3004 const char *s = str.latin1();
3005 if (i < 0 || !s || !(*s))
3006 return *this;
3007
3008 insert_helper(*this, i, str);
3009 return *this;
3010}
3011
3026{
3027 auto insert_size = s.size();
3028 if (i < 0 || insert_size <= 0)
3029 return *this;
3030
3031 qsizetype difference = 0;
3032 if (Q_UNLIKELY(i > d.size))
3033 difference = i - d.size;
3034
3035 const qsizetype newSize = d.size + difference + insert_size;
3036
3037 if (d.needsDetach() || needsReallocate(*this, newSize)) {
3038 const auto cbegin = this->cbegin();
3039 const auto insert_start = difference == 0 ? std::next(cbegin, i) : cend();
3040 QString other;
3041 other.reserve(newSize);
3042 other.append(QStringView(cbegin, insert_start));
3043 if (difference > 0)
3044 other.resize(i, u' ');
3045 other.append(s);
3046 other.append(QStringView(insert_start, cend()));
3047 swap(other);
3048 return *this;
3049 }
3050
3051 if (i >= d.size) {
3052 d.detachAndGrow(QArrayData::GrowsAtEnd, difference + insert_size, nullptr, nullptr);
3053 Q_CHECK_PTR(d.data());
3054
3055 if (difference > 0)
3056 resize(i, u' ');
3057 append(s);
3058 } else {
3059 // Optimal insertion of Utf8 data is at the end, anywhere else could
3060 // potentially lead to moving characters twice if Utf8 data size
3061 // (variable-width) is less than the equiavalent Utf16 data size
3062 QVarLengthArray<char16_t> buffer(insert_size); // ### optimize (QTBUG-108546)
3063 char16_t *b = QUtf8::convertToUnicode(buffer.data(), s);
3064 buffer.resize(std::distance(buffer.begin(), b));
3065 insert_helper(*this, i, buffer);
3066 }
3067
3068 return *this;
3069}
3070
3084{
3085 if (i < 0 || size <= 0)
3086 return *this;
3087
3088 // In case when data points into "this"
3089 if (!d->needsDetach() && QtPrivate::q_points_into_range(unicode, *this)) {
3091 insert(i, copy.data(), size);
3092 } else {
3094 }
3095
3096 return *this;
3097}
3098
3111{
3112 if (i < 0)
3113 i += d.size;
3114 return insert(i, &ch, 1);
3115}
3116
3136{
3137 if (!str.isNull()) {
3138 if (isNull()) {
3139 operator=(str);
3140 } else if (str.size()) {
3141 append(str.constData(), str.size());
3142 }
3143 }
3144 return *this;
3145}
3146
3162{
3163 if (str && len > 0) {
3164 static_assert(sizeof(QChar) == sizeof(char16_t), "Unexpected difference in sizes");
3165 // the following should be safe as QChar uses char16_t as underlying data
3166 const char16_t *char16String = reinterpret_cast<const char16_t *>(str);
3167 d->growAppend(char16String, char16String + len);
3168 d.data()[d.size] = u'\0';
3169 }
3170 return *this;
3171}
3172
3179{
3180 append_helper(*this, str);
3181 return *this;
3182}
3183
3191{
3192 append_helper(*this, str);
3193 return *this;
3194}
3195
3228{
3229 d.detachAndGrow(QArrayData::GrowsAtEnd, 1, nullptr, nullptr);
3230 d->copyAppend(1, ch.unicode());
3231 d.data()[d.size] = '\0';
3232 return *this;
3233}
3234
3378{
3379 if (s.size() <= capacity() && isDetached()) {
3380 const auto offset = d.freeSpaceAtBegin();
3381 if (offset)
3382 d.setBegin(d.begin() - offset);
3383 resize(0);
3384 s.visit([this](auto input) {
3385 this->append(input);
3386 });
3387 } else {
3388 *this = s.toString();
3389 }
3390 return *this;
3391}
3392
3393QString &QString::assign_helper(const char32_t *data, qsizetype len)
3394{
3395 // worst case: each char32_t requires a surrogate pair, so
3396 const auto requiredCapacity = len * 2;
3397 if (requiredCapacity <= capacity() && isDetached()) {
3398 const auto offset = d.freeSpaceAtBegin();
3399 if (offset)
3400 d.setBegin(d.begin() - offset);
3401 auto begin = reinterpret_cast<QChar *>(d.begin());
3402 auto ba = QByteArrayView(reinterpret_cast<const std::byte*>(data), len * sizeof(char32_t));
3405 d.size = end - begin;
3406 d.data()[d.size] = u'\0';
3407 } else {
3408 *this = QString::fromUcs4(data, len);
3409 }
3410 return *this;
3411}
3412
3428
3432
3436{
3437 if (pos < 0) // count from end of string
3438 pos += size();
3439
3440 if (size_t(pos) >= size_t(size()) || len <= 0)
3441 return *this;
3442
3443 len = std::min(len, size() - pos);
3444
3445 if (!d->isShared()) {
3446 d->erase(d.begin() + pos, len);
3447 d.data()[d.size] = u'\0';
3448 } else {
3449 // TODO: either reserve "size()", which is bigger than needed, or
3450 // modify the shrinking-erase docs of this method (since the size
3451 // of "copy" won't have any extra capacity any more)
3452 const qsizetype sz = size() - len;
3454 auto begin = d.begin();
3455 auto toRemove_start = d.begin() + pos;
3456 copy.d->copyRanges({{begin, toRemove_start},
3457 {toRemove_start + len, d.end()}});
3458 swap(copy);
3459 }
3460 return *this;
3461}
3462
3463template<typename T>
3464static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs)
3465{
3466 const auto needleSize = needle.size();
3467 if (!needleSize)
3468 return;
3469
3470 // avoid detach if nothing to do:
3471 qsizetype i = s.indexOf(needle, 0, cs);
3472 if (i < 0)
3473 return;
3474
3475 QString::DataPointer &dptr = s.data_ptr();
3476 auto begin = dptr.begin();
3477 auto end = dptr.end();
3478
3479 auto copyFunc = [&](auto &dst) {
3480 auto src = begin + i + needleSize;
3481 while (src < end) {
3482 i = s.indexOf(needle, std::distance(begin, src), cs);
3483 auto hit = i == -1 ? end : begin + i;
3484 dst = std::copy(src, hit, dst);
3485 src = hit + needleSize;
3486 }
3487 return dst;
3488 };
3489
3490 if (!dptr->needsDetach()) {
3491 auto dst = begin + i;
3492 dst = copyFunc(dst);
3493 s.truncate(std::distance(begin, dst));
3494 } else {
3496 auto copy_begin = copy.begin();
3497 auto dst = std::copy(begin, begin + i, copy_begin); // Chunk before the first hit
3498 dst = copyFunc(dst);
3499 copy.resize(std::distance(copy_begin, dst));
3500 s.swap(copy);
3501 }
3502}
3503
3517{
3518 const auto s = str.d.data();
3521 else
3523 return *this;
3524}
3525
3542{
3543 removeStringImpl(*this, str, cs);
3544 return *this;
3545}
3546
3597{
3598 const qsizetype idx = indexOf(ch, 0, cs);
3599 if (idx == -1)
3600 return *this;
3601
3602 const bool isCase = cs == Qt::CaseSensitive;
3603 ch = isCase ? ch : ch.toCaseFolded();
3604 auto match = [ch, isCase](QChar x) {
3605 return ch == (isCase ? x : x.toCaseFolded());
3606 };
3607
3608
3609 auto begin = d.begin();
3610 auto first_match = begin + idx;
3611 auto end = d.end();
3612 if (!d->isShared()) {
3613 auto it = std::remove_if(first_match, end, match);
3614 d->erase(it, std::distance(it, end));
3615 d.data()[d.size] = u'\0';
3616 } else {
3617 // Instead of detaching, create a new string and copy all characters except for
3618 // the ones we're removing
3619 // TODO: size() is more than the needed since "copy" would be shorter
3621 auto dst = copy.d.begin();
3622 auto it = std::copy(begin, first_match, dst); // Chunk before idx
3623 it = std::remove_copy_if(first_match + 1, end, it, match);
3624 copy.d.size = std::distance(dst, it);
3625 copy.d.data()[copy.d.size] = u'\0';
3626 *this = copy;
3627 }
3628 return *this;
3629}
3630
3661static void replace_with_copy(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen,
3662 QStringView after)
3663{
3664 const qsizetype alen = after.size();
3665 const char16_t *after_b = after.utf16();
3666
3667 const QString::DataPointer &str_d = str.data_ptr();
3668 auto src_start = str_d.begin();
3669 const qsizetype newSize = str_d.size + nIndices * (alen - blen);
3670 QString copy{ newSize, Qt::Uninitialized };
3671 QString::DataPointer &copy_d = copy.data_ptr();
3672 auto dst = copy_d.begin();
3673 for (int i = 0; i < nIndices; ++i) {
3674 auto hit = str_d.begin() + indices[i];
3675 dst = std::copy(src_start, hit, dst);
3676 dst = std::copy_n(after_b, alen, dst);
3677 src_start = hit + blen;
3678 }
3679 dst = std::copy(src_start, str_d.end(), dst);
3680 str.swap(copy);
3681}
3682
3683// No detaching or reallocation is needed
3684static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices,
3685 qsizetype blen, QStringView after)
3686{
3687 const qsizetype alen = after.size();
3688 const char16_t *after_b = after.utf16();
3689 const char16_t *after_e = after.utf16() + after.size();
3690
3691 if (blen == alen) { // Replace in place
3692 for (qsizetype i = 0; i < nIndices; ++i)
3693 std::copy_n(after_b, alen, str.data_ptr().begin() + indices[i]);
3694 } else if (blen > alen) { // Replace from front
3695 char16_t *begin = str.data_ptr().begin();
3696 char16_t *hit = begin + indices[0];
3697 char16_t *to = hit;
3698 to = std::copy_n(after_b, alen, to);
3699 char16_t *movestart = hit + blen;
3700 for (qsizetype i = 1; i < nIndices; ++i) {
3701 hit = begin + indices[i];
3702 to = std::move(movestart, hit, to);
3703 to = std::copy_n(after_b, alen, to);
3704 movestart = hit + blen;
3705 }
3706 to = std::move(movestart, str.data_ptr().end(), to);
3707 str.resize(std::distance(begin, to));
3708 } else { // blen < alen, Replace from back
3709 const qsizetype oldSize = str.data_ptr().size;
3710 const qsizetype adjust = nIndices * (alen - blen);
3711 const qsizetype newSize = oldSize + adjust;
3712
3713 str.resize(newSize);
3714 char16_t *begin = str.data_ptr().begin();
3715 char16_t *moveend = begin + oldSize;
3716 char16_t *to = str.data_ptr().end();
3717
3718 while (nIndices) {
3719 --nIndices;
3720 char16_t *hit = begin + indices[nIndices];
3721 char16_t *movestart = hit + blen;
3722 to = std::move_backward(movestart, moveend, to);
3723 to = std::copy_backward(after_b, after_e, to);
3724 moveend = hit;
3725 }
3726 }
3727}
3728
3729static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, QStringView after)
3730{
3731 const qsizetype oldSize = str.data_ptr().size;
3732 const qsizetype adjust = nIndices * (after.size() - blen);
3733 const qsizetype newSize = oldSize + adjust;
3734 if (str.data_ptr().needsDetach() || needsReallocate(str, newSize)) {
3735 replace_with_copy(str, indices, nIndices, blen, after);
3736 return;
3737 }
3738
3740 // Copy after if it lies inside our own d.b area (which we could
3741 // possibly invalidate via a realloc or modify by replacement)
3742 replace_in_place(str, indices, nIndices, blen, QVarLengthArray(after.begin(), after.end()));
3743 else
3744 replace_in_place(str, indices, nIndices, blen, after);
3745}
3746
3764{
3765 return replace(pos, len, after.constData(), after.size());
3766}
3767
3776{
3777 if (size_t(pos) > size_t(this->size()))
3778 return *this;
3779 if (len > this->size() - pos)
3780 len = this->size() - pos;
3781
3782 size_t index = pos;
3783 replace_helper(*this, &index, 1, len, QStringView{after, alen});
3784 return *this;
3785}
3786
3795{
3796 return replace(pos, len, &after, 1);
3797}
3798
3817{
3818 return replace(before.constData(), before.size(), after.constData(), after.size(), cs);
3819}
3820
3832 const QChar *after, qsizetype alen,
3834{
3835 if (d.size == 0) {
3836 if (blen)
3837 return *this;
3838 } else {
3839 if (cs == Qt::CaseSensitive && before == after && blen == alen)
3840 return *this;
3841 }
3842 if (alen == 0 && blen == 0)
3843 return *this;
3844 if (alen == 1 && blen == 1)
3845 return replace(*before, *after, cs);
3846
3847 QStringMatcher matcher(before, blen, cs);
3848
3849 qsizetype index = 0;
3850
3852 while ((index = matcher.indexIn(*this, index)) != -1) {
3853 indices.push_back(index);
3854 if (blen) // Step over before:
3855 index += blen;
3856 else // Only count one instance of empty between any two characters:
3857 index++;
3858 }
3859 if (indices.isEmpty())
3860 return *this;
3861
3862 replace_helper(*this, indices.data(), indices.size(), blen, QStringView{after, alen});
3863 return *this;
3864}
3865
3874{
3875 if (after.size() == 0)
3876 return remove(ch, cs);
3877
3878 if (after.size() == 1)
3879 return replace(ch, after.front(), cs);
3880
3881 if (size() == 0)
3882 return *this;
3883
3884 const char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
3885
3887 if (cs == Qt::CaseSensitive) {
3888 const char16_t *begin = d.begin();
3889 const char16_t *end = d.end();
3891 const char16_t *hit = nullptr;
3892 while ((hit = QtPrivate::qustrchr(view, cc)) != end) {
3893 indices.push_back(std::distance(begin, hit));
3894 view = QStringView(std::next(hit), end);
3895 }
3896 } else {
3897 for (qsizetype i = 0; i < d.size; ++i)
3898 if (QChar::toCaseFolded(d.data()[i]) == cc)
3899 indices.push_back(i);
3900 }
3901 if (indices.isEmpty())
3902 return *this;
3903
3904 replace_helper(*this, indices.data(), indices.size(), 1, after);
3905 return *this;
3906}
3907
3916{
3917 const qsizetype idx = indexOf(before, 0, cs);
3918 if (idx == -1)
3919 return *this;
3920
3921 const char16_t achar = after.unicode();
3922 char16_t bchar = before.unicode();
3923
3924 auto matchesCIS = [](char16_t beforeChar) {
3925 return [beforeChar](char16_t ch) { return foldAndCompare(ch, beforeChar); };
3926 };
3927
3928 auto hit = d.begin() + idx;
3929 if (!d.needsDetach()) {
3930 *hit++ = achar;
3931 if (cs == Qt::CaseSensitive) {
3932 std::replace(hit, d.end(), bchar, achar);
3933 } else {
3934 bchar = foldCase(bchar);
3935 std::replace_if(hit, d.end(), matchesCIS(bchar), achar);
3936 }
3937 } else {
3939 auto dest = std::copy(d.begin(), hit, other.d.begin());
3940 *dest++ = achar;
3941 ++hit;
3942 if (cs == Qt::CaseSensitive) {
3943 std::replace_copy(hit, d.end(), dest, bchar, achar);
3944 } else {
3945 bchar = foldCase(bchar);
3946 std::replace_copy_if(hit, d.end(), dest, matchesCIS(bchar), achar);
3947 }
3948
3949 swap(other);
3950 }
3951 return *this;
3952}
3953
3967{
3968 const qsizetype alen = after.size();
3969 const qsizetype blen = before.size();
3970 if (blen == 1 && alen == 1)
3971 return replace(before.front(), after.front(), cs);
3972
3975 return replace((const QChar *)b.data(), blen, (const QChar *)a.data(), alen, cs);
3976}
3977
3991{
3992 const qsizetype blen = before.size();
3993 if (blen == 1 && after.size() == 1)
3994 return replace(before.front(), after.front(), cs);
3995
3997 return replace((const QChar *)b.data(), blen, after.constData(), after.d.size, cs);
3998}
3999
4012{
4013 const qsizetype alen = after.size();
4014 if (before.size() == 1 && alen == 1)
4015 return replace(before.front(), after.front(), cs);
4016
4018 return replace(before.constData(), before.d.size, (const QChar *)a.data(), alen, cs);
4019}
4020
4033{
4034 const qsizetype alen = after.size();
4035 if (alen == 1)
4036 return replace(c, after.front(), cs);
4037
4039 return replace(&c, 1, (const QChar *)a.data(), alen, cs);
4040}
4041
4376{
4378}
4379
4411{
4412 return QtPrivate::findString(QStringView(unicode(), size()), from, str, cs);
4413}
4414
4421{
4422 return qFindChar(QStringView(unicode(), size()), ch, from, cs);
4423}
4424
4448{
4449 return QtPrivate::lastIndexOf(QStringView(*this), from, str, cs);
4450}
4451
4496{
4497 return QtPrivate::lastIndexOf(*this, from, str, cs);
4498}
4499
4523{
4524 return qLastIndexOf(QStringView(*this), ch, from, cs);
4525}
4526
4569#if QT_CONFIG(regularexpression)
4570struct QStringCapture
4571{
4572 qsizetype pos;
4573 qsizetype len;
4574 int no;
4575};
4576Q_DECLARE_TYPEINFO(QStringCapture, Q_PRIMITIVE_TYPE);
4577
4596QString &QString::replace(const QRegularExpression &re, const QString &after)
4597{
4598 if (!re.isValid()) {
4599 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString::replace");
4600 return *this;
4601 }
4602
4603 const QString copy(*this);
4605 if (!iterator.hasNext()) // no matches at all
4606 return *this;
4607
4608 reallocData(d.size, QArrayData::KeepSize);
4609
4610 qsizetype numCaptures = re.captureCount();
4611
4612 // 1. build the backreferences list, holding where the backreferences
4613 // are in the replacement string
4614 QList<QStringCapture> backReferences;
4615 const qsizetype al = after.size();
4616 const QChar *ac = after.unicode();
4617
4618 for (qsizetype i = 0; i < al - 1; i++) {
4619 if (ac[i] == u'\\') {
4620 int no = ac[i + 1].digitValue();
4621 if (no > 0 && no <= numCaptures) {
4622 QStringCapture backReference;
4623 backReference.pos = i;
4624 backReference.len = 2;
4625
4626 if (i < al - 2) {
4627 int secondDigit = ac[i + 2].digitValue();
4628 if (secondDigit != -1 && ((no * 10) + secondDigit) <= numCaptures) {
4629 no = (no * 10) + secondDigit;
4630 ++backReference.len;
4631 }
4632 }
4633
4634 backReference.no = no;
4635 backReferences.append(backReference);
4636 }
4637 }
4638 }
4639
4640 // 2. iterate on the matches. For every match, copy in chunks
4641 // - the part before the match
4642 // - the after string, with the proper replacements for the backreferences
4643
4644 qsizetype newLength = 0; // length of the new string, with all the replacements
4645 qsizetype lastEnd = 0;
4646 QList<QStringView> chunks;
4647 const QStringView copyView{ copy }, afterView{ after };
4648 while (iterator.hasNext()) {
4650 qsizetype len;
4651 // add the part before the match
4652 len = match.capturedStart() - lastEnd;
4653 if (len > 0) {
4654 chunks << copyView.mid(lastEnd, len);
4655 newLength += len;
4656 }
4657
4658 lastEnd = 0;
4659 // add the after string, with replacements for the backreferences
4660 for (const QStringCapture &backReference : std::as_const(backReferences)) {
4661 // part of "after" before the backreference
4662 len = backReference.pos - lastEnd;
4663 if (len > 0) {
4664 chunks << afterView.mid(lastEnd, len);
4665 newLength += len;
4666 }
4667
4668 // backreference itself
4669 len = match.capturedLength(backReference.no);
4670 if (len > 0) {
4671 chunks << copyView.mid(match.capturedStart(backReference.no), len);
4672 newLength += len;
4673 }
4674
4675 lastEnd = backReference.pos + backReference.len;
4676 }
4677
4678 // add the last part of the after string
4679 len = afterView.size() - lastEnd;
4680 if (len > 0) {
4681 chunks << afterView.mid(lastEnd, len);
4682 newLength += len;
4683 }
4684
4685 lastEnd = match.capturedEnd();
4686 }
4687
4688 // 3. trailing string after the last match
4689 if (copyView.size() > lastEnd) {
4690 chunks << copyView.mid(lastEnd);
4691 newLength += copyView.size() - lastEnd;
4692 }
4693
4694 // 4. assemble the chunks together
4695 resize(newLength);
4696 qsizetype i = 0;
4697 QChar *uc = data();
4698 for (const QStringView &chunk : std::as_const(chunks)) {
4699 qsizetype len = chunk.size();
4700 memcpy(uc + i, chunk.constData(), len * sizeof(QChar));
4701 i += len;
4702 }
4703
4704 return *this;
4705}
4706#endif // QT_CONFIG(regularexpression)
4707
4718{
4720}
4721
4733{
4734 return QtPrivate::count(QStringView(unicode(), size()), ch, cs);
4735}
4736
4748{
4749 return QtPrivate::count(*this, str, cs);
4750}
4751
4794#if QT_CONFIG(regularexpression)
4811{
4812 return QtPrivate::indexOf(QStringView(*this), this, re, from, rmatch);
4813}
4814
4847{
4848 return QtPrivate::lastIndexOf(QStringView(*this), this, re, from, rmatch);
4849}
4850
4886{
4887 return QtPrivate::contains(QStringView(*this), this, re, rmatch);
4888}
4889
4909{
4910 return QtPrivate::count(QStringView(*this), re);
4911}
4912#endif // QT_CONFIG(regularexpression)
4913
4914#if QT_DEPRECATED_SINCE(6, 4)
4921#endif
4922
4988{
4989 const QList<QStringView> sections = QStringView{ *this }.split(
4991 const qsizetype sectionsSize = sections.size();
4992 if (!(flags & SectionSkipEmpty)) {
4993 if (start < 0)
4994 start += sectionsSize;
4995 if (end < 0)
4996 end += sectionsSize;
4997 } else {
4998 qsizetype skip = 0;
4999 for (qsizetype k = 0; k < sectionsSize; ++k) {
5000 if (sections.at(k).isEmpty())
5001 skip++;
5002 }
5003 if (start < 0)
5004 start += sectionsSize - skip;
5005 if (end < 0)
5006 end += sectionsSize - skip;
5007 }
5008 if (start >= sectionsSize || end < 0 || start > end)
5009 return QString();
5010
5011 QString ret;
5012 qsizetype first_i = start, last_i = end;
5013 for (qsizetype x = 0, i = 0; x <= end && i < sectionsSize; ++i) {
5014 const QStringView &section = sections.at(i);
5015 const bool empty = section.isEmpty();
5016 if (x >= start) {
5017 if (x == start)
5018 first_i = i;
5019 if (x == end)
5020 last_i = i;
5021 if (x > start && i > 0)
5022 ret += sep;
5023 ret += section;
5024 }
5025 if (!empty || !(flags & SectionSkipEmpty))
5026 x++;
5027 }
5028 if ((flags & SectionIncludeLeadingSep) && first_i > 0)
5029 ret.prepend(sep);
5030 if ((flags & SectionIncludeTrailingSep) && last_i < sectionsSize - 1)
5031 ret += sep;
5032 return ret;
5033}
5034
5035#if QT_CONFIG(regularexpression)
5036class qt_section_chunk {
5037public:
5038 qt_section_chunk() {}
5039 qt_section_chunk(qsizetype l, QStringView s) : length(l), string(std::move(s)) {}
5042};
5043Q_DECLARE_TYPEINFO(qt_section_chunk, Q_RELOCATABLE_TYPE);
5044
5045static QString extractSections(const QList<qt_section_chunk> &sections, qsizetype start, qsizetype end,
5046 QString::SectionFlags flags)
5047{
5048 const qsizetype sectionsSize = sections.size();
5049
5051 if (start < 0)
5052 start += sectionsSize;
5053 if (end < 0)
5054 end += sectionsSize;
5055 } else {
5056 qsizetype skip = 0;
5057 for (qsizetype k = 0; k < sectionsSize; ++k) {
5058 const qt_section_chunk &section = sections.at(k);
5059 if (section.length == section.string.size())
5060 skip++;
5061 }
5062 if (start < 0)
5063 start += sectionsSize - skip;
5064 if (end < 0)
5065 end += sectionsSize - skip;
5066 }
5067 if (start >= sectionsSize || end < 0 || start > end)
5068 return QString();
5069
5070 QString ret;
5071 qsizetype x = 0;
5072 qsizetype first_i = start, last_i = end;
5073 for (qsizetype i = 0; x <= end && i < sectionsSize; ++i) {
5074 const qt_section_chunk &section = sections.at(i);
5075 const bool empty = (section.length == section.string.size());
5076 if (x >= start) {
5077 if (x == start)
5078 first_i = i;
5079 if (x == end)
5080 last_i = i;
5081 if (x != start)
5082 ret += section.string;
5083 else
5084 ret += section.string.mid(section.length);
5085 }
5086 if (!empty || !(flags & QString::SectionSkipEmpty))
5087 x++;
5088 }
5089
5090 if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) {
5091 const qt_section_chunk &section = sections.at(first_i);
5092 ret.prepend(section.string.left(section.length));
5093 }
5094
5096 && last_i < sectionsSize - 1) {
5097 const qt_section_chunk &section = sections.at(last_i+1);
5098 ret += section.string.left(section.length);
5099 }
5100
5101 return ret;
5102}
5103
5119{
5120 if (!re.isValid()) {
5121 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString::section");
5122 return QString();
5123 }
5124
5125 const QChar *uc = unicode();
5126 if (!uc)
5127 return QString();
5128
5131 sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption);
5132
5133 QList<qt_section_chunk> sections;
5134 qsizetype n = size(), m = 0, last_m = 0, last_len = 0;
5135 QRegularExpressionMatchIterator iterator = sep.globalMatch(*this);
5136 while (iterator.hasNext()) {
5138 m = match.capturedStart();
5139 sections.append(qt_section_chunk(last_len, QStringView{ *this }.sliced(last_m, m - last_m)));
5140 last_m = m;
5141 last_len = match.capturedLength();
5142 }
5143 sections.append(qt_section_chunk(last_len, QStringView{ *this }.sliced(last_m, n - last_m)));
5144
5145 return extractSections(sections, start, end, flags);
5146}
5147#endif // QT_CONFIG(regularexpression)
5148
5162{
5163 if (size_t(n) >= size_t(size()))
5164 return *this;
5165 return QString((const QChar*) d.data(), n);
5166}
5167
5181{
5182 if (size_t(n) >= size_t(size()))
5183 return *this;
5184 return QString(constData() + size() - n, n);
5185}
5186
5205{
5207 qsizetype l = n;
5208 using namespace QtPrivate;
5209 switch (QContainerImplHelper::mid(size(), &p, &l)) {
5210 case QContainerImplHelper::Null:
5211 return QString();
5212 case QContainerImplHelper::Empty:
5213 return QString(DataPointer::fromRawData(&_empty, 0));
5214 case QContainerImplHelper::Full:
5215 return *this;
5216 case QContainerImplHelper::Subset:
5217 return QString(constData() + p, l);
5218 }
5219 Q_UNREACHABLE_RETURN(QString());
5220}
5221
5300{
5301 return qt_starts_with_impl(QStringView(*this), QStringView(s), cs);
5302}
5303
5308{
5309 return qt_starts_with_impl(QStringView(*this), s, cs);
5310}
5311
5319{
5320 if (!size())
5321 return false;
5322 if (cs == Qt::CaseSensitive)
5323 return at(0) == c;
5324 return foldCase(at(0)) == foldCase(c);
5325}
5326
5351{
5352 return qt_ends_with_impl(QStringView(*this), QStringView(s), cs);
5353}
5354
5371{
5372 return qt_ends_with_impl(QStringView(*this), s, cs);
5373}
5374
5382{
5383 if (!size())
5384 return false;
5385 if (cs == Qt::CaseSensitive)
5386 return at(size() - 1) == c;
5387 return foldCase(at(size() - 1)) == foldCase(c);
5388}
5389
5404{
5405 QStringIterator it(*this);
5406
5407 while (it.hasNext()) {
5408 const char32_t uc = it.next();
5409 if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff)
5410 return false;
5411 }
5412
5413 return true;
5414}
5415
5430{
5431 QStringIterator it(*this);
5432
5433 while (it.hasNext()) {
5434 const char32_t uc = it.next();
5435 if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff)
5436 return false;
5437 }
5438
5439 return true;
5440}
5441
5443
5444QByteArray QString::toLatin1_helper(const QString &string)
5445{
5446 return qt_convert_to_latin1(string);
5447}
5448
5460{
5461 return string.visit([] (auto string) { return string.toString(); });
5462}
5463
5477{
5478 return qt_convert_to_latin1(string);
5479}
5480
5483{
5484 if (Q_UNLIKELY(string.isNull()))
5485 return QByteArray();
5486
5488
5489 // since we own the only copy, we're going to const_cast the constData;
5490 // that avoids an unnecessary call to detach() and expansion code that will never get used
5491 qt_to_latin1(reinterpret_cast<uchar *>(const_cast<char *>(ba.constData())),
5492 string.utf16(), string.size());
5493 return ba;
5494}
5495
5496QByteArray QString::toLatin1_helper_inplace(QString &s)
5497{
5498 if (!s.isDetached())
5499 return qt_convert_to_latin1(s);
5500
5501 // We can return our own buffer to the caller.
5502 // Conversion to Latin-1 always shrinks the buffer by half.
5503 // This relies on the fact that we use QArrayData for everything behind the scenes
5504
5505 // First, do the in-place conversion. Since isDetached() == true, the data
5506 // was allocated by QArrayData, so the null terminator must be there.
5507 qsizetype length = s.size();
5508 char16_t *sdata = s.d->data();
5509 Q_ASSERT(sdata[length] == u'\0');
5510 qt_to_latin1(reinterpret_cast<uchar *>(sdata), sdata, length + 1);
5511
5512 // Move the internals over to the byte array.
5513 // Kids, avert your eyes. Don't try this at home.
5514 auto ba_d = std::move(s.d).reinterpreted<char>();
5515
5516 // Some sanity checks
5517 Q_ASSERT(ba_d.d->allocatedCapacity() >= ba_d.size);
5518 Q_ASSERT(s.isNull());
5519 Q_ASSERT(s.isEmpty());
5520 Q_ASSERT(s.constData() == QString().constData());
5521
5522 return QByteArray(std::move(ba_d));
5523}
5524
5525// QLatin1 methods that use helpers from qstring.cpp
5527{
5528 const qsizetype len = in.size();
5529 qt_from_latin1(out, in.data(), len);
5530 return std::next(out, len);
5531}
5532
5534{
5535 const qsizetype len = in.size();
5536 qt_to_latin1(reinterpret_cast<uchar *>(out), in.utf16(), len);
5537 return out + len;
5538}
5539
5553
5569QByteArray QString::toLocal8Bit_helper(const QChar *data, qsizetype size)
5570{
5572}
5573
5575{
5576 if (string.isNull())
5577 return QByteArray();
5579 return fromUtf16(string);
5580}
5581
5598{
5599 return qt_convert_to_local_8bit(string);
5600}
5601
5603
5615QByteArray QString::toUtf8_helper(const QString &str)
5616{
5617 return qt_convert_to_utf8(str);
5618}
5619
5621{
5622 if (str.isNull())
5623 return QByteArray();
5624
5626}
5627
5641{
5642 return qt_convert_to_utf8(string);
5643}
5644
5646
5663{
5664 return qt_convert_to_ucs4(*this);
5665}
5666
5668{
5669 QList<uint> v(string.size());
5670 uint *a = const_cast<uint*>(v.constData());
5671 QStringIterator it(string);
5672 while (it.hasNext())
5673 *a++ = it.next();
5674 v.resize(a - v.constData());
5675 return v;
5676}
5677
5696{
5697 return qt_convert_to_ucs4(string);
5698}
5699
5711{
5712 DataPointer d;
5713 if (!ba.data()) {
5714 // nothing to do
5715 } else if (ba.size() == 0) {
5716 d = DataPointer::fromRawData(&_empty, 0);
5717 } else {
5719 Q_CHECK_PTR(d.data());
5720 d.data()[ba.size()] = '\0';
5721 char16_t *dst = d.data();
5722
5723 qt_from_latin1(dst, ba.data(), size_t(ba.size()));
5724 }
5725 return QString(std::move(d));
5726}
5727
5789{
5790 if (ba.isNull())
5791 return QString();
5792 if (ba.isEmpty())
5793 return QString(DataPointer::fromRawData(&_empty, 0));
5795 return toUtf16(ba);
5796}
5797
5858{
5859 if (ba.isNull())
5860 return QString();
5861 if (ba.isEmpty())
5862 return QString(DataPointer::fromRawData(&_empty, 0));
5864}
5865
5883QString QString::fromUtf16(const char16_t *unicode, qsizetype size)
5884{
5885 if (!unicode)
5886 return QString();
5887 if (size < 0)
5890 return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 2));
5891}
5892
5915QString QString::fromUcs4(const char32_t *unicode, qsizetype size)
5916{
5917 if (!unicode)
5918 return QString();
5919 if (size < 0) {
5920 size = 0;
5921 while (unicode[size] != 0)
5922 ++size;
5923 }
5925 return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 4));
5926}
5927
5928
5939{
5940 resize(size);
5941 if (unicode && size)
5942 memcpy(d.data(), unicode, size * sizeof(QChar));
5943 return *this;
5944}
5945
5978QString QString::simplified_helper(const QString &str)
5979{
5981}
5982
5983QString QString::simplified_helper(QString &str)
5984{
5986}
5987
5988namespace {
5989 template <typename StringView>
5990 StringView qt_trimmed(StringView s) noexcept
5991 {
5992 auto begin = s.begin();
5993 auto end = s.end();
5995 return StringView{begin, end};
5996 }
5997}
5998
6015{
6016 return qt_trimmed(s);
6017}
6018
6020{
6021 return qt_trimmed(s);
6022}
6023
6042QString QString::trimmed_helper(const QString &str)
6043{
6045}
6046
6047QString QString::trimmed_helper(QString &str)
6048{
6050}
6051
6160{
6161 if (pos < size())
6162 resize(pos);
6163}
6164
6165
6181{
6182 if (n > 0)
6183 resize(d.size - n);
6184}
6185
6199{
6200 resize(size < 0 ? d.size : size);
6201 if (d.size) {
6202 QChar *i = (QChar*)d.data() + d.size;
6203 QChar *b = (QChar*)d.data();
6204 std::fill(b, i, ch);
6205 }
6206 return *this;
6207}
6208
6441
6444
6499{
6500 return QtPrivate::compareStrings(*this, other, cs);
6501}
6502
6507int QString::compare_helper(const QChar *data1, qsizetype length1, const QChar *data2, qsizetype length2,
6508 Qt::CaseSensitivity cs) noexcept
6509{
6510 Q_ASSERT(length1 >= 0);
6511 Q_ASSERT(length2 >= 0);
6512 Q_ASSERT(data1 || length1 == 0);
6513 Q_ASSERT(data2 || length2 == 0);
6514 return QtPrivate::compareStrings(QStringView(data1, length1), QStringView(data2, length2), cs);
6515}
6516
6524{
6525 return QtPrivate::compareStrings(*this, other, cs);
6526}
6527
6532int QString::compare_helper(const QChar *data1, qsizetype length1, const char *data2, qsizetype length2,
6533 Qt::CaseSensitivity cs) noexcept
6534{
6535 Q_ASSERT(length1 >= 0);
6536 Q_ASSERT(data1 || length1 == 0);
6537 if (!data2)
6538 return qt_lencmp(length1, 0);
6539 if (Q_UNLIKELY(length2 < 0))
6540 length2 = qsizetype(strlen(data2));
6541 return QtPrivate::compareStrings(QStringView(data1, length1),
6542 QUtf8StringView(data2, length2), cs);
6543}
6544
6559int QLatin1StringView::compare_helper(const QLatin1StringView &s1, const char *s2, qsizetype len) noexcept
6560{
6561 // because qlatin1stringview.h can't include qutf8stringview.h
6562 Q_ASSERT(len >= 0);
6563 Q_ASSERT(s2 || len == 0);
6565}
6566
6571int QLatin1StringView::compare_helper(const QChar *data1, qsizetype length1, QLatin1StringView s2,
6572 Qt::CaseSensitivity cs) noexcept
6573{
6574 Q_ASSERT(length1 >= 0);
6575 Q_ASSERT(data1 || length1 == 0);
6576 return QtPrivate::compareStrings(QStringView(data1, length1), s2, cs);
6577}
6578
6628#if !defined(CSTR_LESS_THAN)
6629#define CSTR_LESS_THAN 1
6630#define CSTR_EQUAL 2
6631#define CSTR_GREATER_THAN 3
6632#endif
6633
6650{
6651 return localeAwareCompare_helper(constData(), size(), other.constData(), other.size());
6652}
6653
6658int QString::localeAwareCompare_helper(const QChar *data1, qsizetype length1,
6659 const QChar *data2, qsizetype length2)
6660{
6661 Q_ASSERT(length1 >= 0);
6662 Q_ASSERT(data1 || length1 == 0);
6663 Q_ASSERT(length2 >= 0);
6664 Q_ASSERT(data2 || length2 == 0);
6665
6666 // do the right thing for null and empty
6667 if (length1 == 0 || length2 == 0)
6668 return QtPrivate::compareStrings(QStringView(data1, length1), QStringView(data2, length2),
6670
6671#if QT_CONFIG(icu)
6672 return QCollator::defaultCompare(QStringView(data1, length1), QStringView(data2, length2));
6673#else
6676# if defined(Q_OS_WIN)
6677 int res = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, (LPWSTR)lhs.constData(), lhs.length(), (LPWSTR)rhs.constData(), rhs.length(), NULL, NULL, 0);
6678
6679 switch (res) {
6680 case CSTR_LESS_THAN:
6681 return -1;
6682 case CSTR_GREATER_THAN:
6683 return 1;
6684 default:
6685 return 0;
6686 }
6687# elif defined (Q_OS_DARWIN)
6688 // Use CFStringCompare for comparing strings on Mac. This makes Qt order
6689 // strings the same way as native applications do, and also respects
6690 // the "Order for sorted lists" setting in the International preferences
6691 // panel.
6692 const CFStringRef thisString =
6693 CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
6694 reinterpret_cast<const UniChar *>(lhs.constData()), lhs.length(), kCFAllocatorNull);
6695 const CFStringRef otherString =
6696 CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
6697 reinterpret_cast<const UniChar *>(rhs.constData()), rhs.length(), kCFAllocatorNull);
6698
6699 const int result = CFStringCompare(thisString, otherString, kCFCompareLocalized);
6700 CFRelease(thisString);
6701 CFRelease(otherString);
6702 return result;
6703# elif defined(Q_OS_UNIX)
6704 // declared in <string.h> (no better than QtPrivate::compareStrings() on Android, sadly)
6705 return strcoll(lhs.toLocal8Bit().constData(), rhs.toLocal8Bit().constData());
6706# else
6707# error "This case shouldn't happen"
6709# endif
6710#endif // !QT_CONFIG(icu)
6711}
6712
6713
6738{
6739 if (!d->isMutable()) {
6740 // ensure '\0'-termination for ::fromRawData strings
6741 const_cast<QString*>(this)->reallocData(d.size, QArrayData::KeepSize);
6742 }
6743 return reinterpret_cast<const ushort *>(d.data());
6744}
6745
6765{
6767 qsizetype len = size();
6768 qsizetype padlen = width - len;
6769 if (padlen > 0) {
6770 result.resize(len+padlen);
6771 if (len)
6772 memcpy(result.d.data(), d.data(), sizeof(QChar)*len);
6773 QChar *uc = (QChar*)result.d.data() + len;
6774 while (padlen--)
6775 * uc++ = fill;
6776 } else {
6777 if (truncate)
6778 result = left(width);
6779 else
6780 result = *this;
6781 }
6782 return result;
6783}
6784
6804{
6806 qsizetype len = size();
6807 qsizetype padlen = width - len;
6808 if (padlen > 0) {
6809 result.resize(len+padlen);
6810 QChar *uc = (QChar*)result.d.data();
6811 while (padlen--)
6812 * uc++ = fill;
6813 if (len)
6814 memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data()), sizeof(QChar)*len);
6815 } else {
6816 if (truncate)
6817 result = left(width);
6818 else
6819 result = *this;
6820 }
6821 return result;
6822}
6823
6838/*
6839 \internal
6840 Converts the \a str string starting from the position pointed to by the \a
6841 it iterator, using the Unicode case traits \c Traits, and returns the
6842 result. The input string must not be empty (the convertCase function below
6843 guarantees that).
6844
6845 The string type \c{T} is also a template and is either \c{const QString} or
6846 \c{QString}. This function can do both copy-conversion and in-place
6847 conversion depending on the state of the \a str parameter:
6848 \list
6849 \li \c{T} is \c{const QString}: copy-convert
6850 \li \c{T} is \c{QString} and its refcount != 1: copy-convert
6851 \li \c{T} is \c{QString} and its refcount == 1: in-place convert
6852 \endlist
6853
6854 In copy-convert mode, the local variable \c{s} is detached from the input
6855 \a str. In the in-place convert mode, \a str is in moved-from state and
6856 \c{s} contains the only copy of the string, without reallocation (thus,
6857 \a it is still valid).
6858
6859 There is one pathological case left: when the in-place conversion needs to
6860 reallocate memory to grow the buffer. In that case, we need to adjust the \a
6861 it pointer.
6862 */
6863template <typename T>
6866{
6867 Q_ASSERT(!str.isEmpty());
6868 QString s = std::move(str); // will copy if T is const QString
6869 QChar *pp = s.begin() + it.index(); // will detach if necessary
6870
6871 do {
6872 const auto folded = fullConvertCase(it.next(), which);
6873 if (Q_UNLIKELY(folded.size() > 1)) {
6874 if (folded.chars[0] == *pp && folded.size() == 2) {
6875 // special case: only second actually changed (e.g. surrogate pairs),
6876 // avoid slow case
6877 ++pp;
6878 *pp++ = folded.chars[1];
6879 } else {
6880 // slow path: the string is growing
6881 qsizetype inpos = it.index() - 1;
6882 qsizetype outpos = pp - s.constBegin();
6883
6884 s.replace(outpos, 1, reinterpret_cast<const QChar *>(folded.data()), folded.size());
6885 pp = const_cast<QChar *>(s.constBegin()) + outpos + folded.size();
6886
6887 // Adjust the input iterator if we are performing an in-place conversion
6888 if constexpr (!std::is_const<T>::value)
6889 it = QStringIterator(s.constBegin(), inpos + folded.size(), s.constEnd());
6890 }
6891 } else {
6892 *pp++ = folded.chars[0];
6893 }
6894 } while (it.hasNext());
6895
6896 return s;
6897}
6898
6899template <typename T>
6901{
6902 const QChar *p = str.constBegin();
6903 const QChar *e = p + str.size();
6904
6905 // this avoids out of bounds check in the loop
6906 while (e != p && e[-1].isHighSurrogate())
6907 --e;
6908
6910 while (it.hasNext()) {
6911 const char32_t uc = it.next();
6912 if (qGetProp(uc)->cases[which].diff) {
6913 it.recede();
6914 return detachAndConvertCase(str, it, which);
6915 }
6916 }
6917 return std::move(str);
6918}
6919} // namespace QUnicodeTables
6920
6921QString QString::toLower_helper(const QString &str)
6922{
6924}
6925
6926QString QString::toLower_helper(QString &str)
6927{
6929}
6930
6938QString QString::toCaseFolded_helper(const QString &str)
6939{
6941}
6942
6943QString QString::toCaseFolded_helper(QString &str)
6944{
6946}
6947
6961QString QString::toUpper_helper(const QString &str)
6962{
6964}
6965
6966QString QString::toUpper_helper(QString &str)
6967{
6969}
6970
7005QString QString::asprintf(const char *cformat, ...)
7006{
7007 va_list ap;
7008 va_start(ap, cformat);
7009 const QString s = vasprintf(cformat, ap);
7010 va_end(ap);
7011 return s;
7012}
7013
7014static void append_utf8(QString &qs, const char *cs, qsizetype len)
7015{
7016 const qsizetype oldSize = qs.size();
7017 qs.resize(oldSize + len);
7018 const QChar *newEnd = QUtf8::convertToUnicode(qs.data() + oldSize, QByteArrayView(cs, len));
7019 qs.resize(newEnd - qs.constData());
7020}
7021
7022static uint parse_flag_characters(const char * &c) noexcept
7023{
7025 while (true) {
7026 switch (*c) {
7027 case '#':
7030 break;
7031 case '0': flags |= QLocaleData::ZeroPadded; break;
7032 case '-': flags |= QLocaleData::LeftAdjusted; break;
7033 case ' ': flags |= QLocaleData::BlankBeforePositive; break;
7034 case '+': flags |= QLocaleData::AlwaysShowSign; break;
7035 case '\'': flags |= QLocaleData::GroupDigits; break;
7036 default: return flags;
7037 }
7038 ++c;
7039 }
7040}
7041
7042static int parse_field_width(const char *&c, qsizetype size)
7043{
7045 const char *const stop = c + size;
7046
7047 // can't be negative - started with a digit
7048 // contains at least one digit
7049 auto [result, used] = qstrntoull(c, size, 10);
7050 c += used;
7051 if (used <= 0)
7052 return false;
7053 // preserve Qt 5.5 behavior of consuming all digits, no matter how many
7054 while (c < stop && isAsciiDigit(*c))
7055 ++c;
7056 return result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0;
7057}
7058
7060
7061static inline bool can_consume(const char * &c, char ch) noexcept
7062{
7063 if (*c == ch) {
7064 ++c;
7065 return true;
7066 }
7067 return false;
7068}
7069
7070static LengthMod parse_length_modifier(const char * &c) noexcept
7071{
7072 switch (*c++) {
7073 case 'h': return can_consume(c, 'h') ? lm_hh : lm_h;
7074 case 'l': return can_consume(c, 'l') ? lm_ll : lm_l;
7075 case 'L': return lm_L;
7076 case 'j': return lm_j;
7077 case 'z':
7078 case 'Z': return lm_z;
7079 case 't': return lm_t;
7080 }
7081 --c; // don't consume *c - it wasn't a flag
7082 return lm_none;
7083}
7084
7099QString QString::vasprintf(const char *cformat, va_list ap)
7100{
7101 if (!cformat || !*cformat) {
7102 // Qt 1.x compat
7103 return fromLatin1("");
7104 }
7105
7106 // Parse cformat
7107
7109 const char *c = cformat;
7110 const char *formatEnd = cformat + qstrlen(cformat);
7111 for (;;) {
7112 // Copy non-escape chars to result
7113 const char *cb = c;
7114 while (*c != '\0' && *c != '%')
7115 c++;
7117
7118 if (*c == '\0')
7119 break;
7120
7121 // Found '%'
7122 const char *escape_start = c;
7123 ++c;
7124
7125 if (*c == '\0') {
7126 result.append(u'%'); // a % at the end of the string - treat as non-escape text
7127 break;
7128 }
7129 if (*c == '%') {
7130 result.append(u'%'); // %%
7131 ++c;
7132 continue;
7133 }
7134
7136
7137 if (*c == '\0') {
7138 result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
7139 break;
7140 }
7141
7142 // Parse field width
7143 int width = -1; // -1 means unspecified
7144 if (isAsciiDigit(*c)) {
7145 width = parse_field_width(c, formatEnd - c);
7146 } else if (*c == '*') { // can't parse this in another function, not portably, at least
7147 width = va_arg(ap, int);
7148 if (width < 0)
7149 width = -1; // treat all negative numbers as unspecified
7150 ++c;
7151 }
7152
7153 if (*c == '\0') {
7154 result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
7155 break;
7156 }
7157
7158 // Parse precision
7159 int precision = -1; // -1 means unspecified
7160 if (*c == '.') {
7161 ++c;
7162 precision = 0;
7163 if (isAsciiDigit(*c)) {
7164 precision = parse_field_width(c, formatEnd - c);
7165 } else if (*c == '*') { // can't parse this in another function, not portably, at least
7166 precision = va_arg(ap, int);
7167 if (precision < 0)
7168 precision = -1; // treat all negative numbers as unspecified
7169 ++c;
7170 }
7171 }
7172
7173 if (*c == '\0') {
7174 result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
7175 break;
7176 }
7177
7178 const LengthMod length_mod = parse_length_modifier(c);
7179
7180 if (*c == '\0') {
7181 result.append(QLatin1StringView(escape_start)); // incomplete escape, treat as non-escape text
7182 break;
7183 }
7184
7185 // Parse the conversion specifier and do the conversion
7186 QString subst;
7187 switch (*c) {
7188 case 'd':
7189 case 'i': {
7190 qint64 i;
7191 switch (length_mod) {
7192 case lm_none: i = va_arg(ap, int); break;
7193 case lm_hh: i = va_arg(ap, int); break;
7194 case lm_h: i = va_arg(ap, int); break;
7195 case lm_l: i = va_arg(ap, long int); break;
7196 case lm_ll: i = va_arg(ap, qint64); break;
7197 case lm_j: i = va_arg(ap, long int); break;
7198
7199 /* ptrdiff_t actually, but it should be the same for us */
7200 case lm_z: i = va_arg(ap, qsizetype); break;
7201 case lm_t: i = va_arg(ap, qsizetype); break;
7202 default: i = 0; break;
7203 }
7205 ++c;
7206 break;
7207 }
7208 case 'o':
7209 case 'u':
7210 case 'x':
7211 case 'X': {
7212 quint64 u;
7213 switch (length_mod) {
7214 case lm_none: u = va_arg(ap, uint); break;
7215 case lm_hh: u = va_arg(ap, uint); break;
7216 case lm_h: u = va_arg(ap, uint); break;
7217 case lm_l: u = va_arg(ap, ulong); break;
7218 case lm_ll: u = va_arg(ap, quint64); break;
7219 case lm_t: u = va_arg(ap, size_t); break;
7220 case lm_z: u = va_arg(ap, size_t); break;
7221 default: u = 0; break;
7222 }
7223
7224 if (isAsciiUpper(*c))
7226
7227 int base = 10;
7228 switch (QtMiscUtils::toAsciiLower(*c)) {
7229 case 'o':
7230 base = 8; break;
7231 case 'u':
7232 base = 10; break;
7233 case 'x':
7234 base = 16; break;
7235 default: break;
7236 }
7238 ++c;
7239 break;
7240 }
7241 case 'E':
7242 case 'e':
7243 case 'F':
7244 case 'f':
7245 case 'G':
7246 case 'g':
7247 case 'A':
7248 case 'a': {
7249 double d;
7250 if (length_mod == lm_L)
7251 d = va_arg(ap, long double); // not supported - converted to a double
7252 else
7253 d = va_arg(ap, double);
7254
7255 if (isAsciiUpper(*c))
7257
7259 switch (QtMiscUtils::toAsciiLower(*c)) {
7260 case 'e': form = QLocaleData::DFExponent; break;
7261 case 'a': // not supported - decimal form used instead
7262 case 'f': form = QLocaleData::DFDecimal; break;
7263 case 'g': form = QLocaleData::DFSignificantDigits; break;
7264 default: break;
7265 }
7267 ++c;
7268 break;
7269 }
7270 case 'c': {
7271 if (length_mod == lm_l)
7272 subst = QChar::fromUcs2(va_arg(ap, int));
7273 else
7274 subst = QLatin1Char((uchar) va_arg(ap, int));
7275 ++c;
7276 break;
7277 }
7278 case 's': {
7279 if (length_mod == lm_l) {
7280 const ushort *buff = va_arg(ap, const ushort*);
7281 const ushort *ch = buff;
7282 while (precision != 0 && *ch != 0) {
7283 ++ch;
7284 --precision;
7285 }
7286 subst.setUtf16(buff, ch - buff);
7287 } else if (precision == -1) {
7288 subst = QString::fromUtf8(va_arg(ap, const char*));
7289 } else {
7290 const char *buff = va_arg(ap, const char*);
7291 subst = QString::fromUtf8(buff, qstrnlen(buff, precision));
7292 }
7293 ++c;
7294 break;
7295 }
7296 case 'p': {
7297 void *arg = va_arg(ap, void*);
7298 const quint64 i = reinterpret_cast<quintptr>(arg);
7301 ++c;
7302 break;
7303 }
7304 case 'n':
7305 switch (length_mod) {
7306 case lm_hh: {
7307 signed char *n = va_arg(ap, signed char*);
7308 *n = result.size();
7309 break;
7310 }
7311 case lm_h: {
7312 short int *n = va_arg(ap, short int*);
7313 *n = result.size();
7314 break;
7315 }
7316 case lm_l: {
7317 long int *n = va_arg(ap, long int*);
7318 *n = result.size();
7319 break;
7320 }
7321 case lm_ll: {
7322 qint64 *n = va_arg(ap, qint64*);
7323 *n = result.size();
7324 break;
7325 }
7326 default: {
7327 int *n = va_arg(ap, int*);
7328 *n = int(result.size());
7329 break;
7330 }
7331 }
7332 ++c;
7333 break;
7334
7335 default: // bad escape, treat as non-escape text
7336 for (const char *cc = escape_start; cc != c; ++cc)
7337 result.append(QLatin1Char(*cc));
7338 continue;
7339 }
7340
7342 result.append(subst.leftJustified(width));
7343 else
7344 result.append(subst.rightJustified(width));
7345 }
7346
7347 return result;
7348}
7349
7379template <typename Int>
7380static Int toIntegral(QStringView string, bool *ok, int base)
7381{
7382#if defined(QT_CHECK_RANGE)
7383 if (base != 0 && (base < 2 || base > 36)) {
7384 qWarning("QString::toIntegral: Invalid base (%d)", base);
7385 base = 10;
7386 }
7387#endif
7388
7389 QVarLengthArray<uchar> latin1(string.size());
7390 qt_to_latin1(latin1.data(), string.utf16(), string.size());
7391 if constexpr (std::is_signed_v<Int>)
7392 return QLocaleData::bytearrayToLongLong(latin1, base, ok);
7393 else
7395}
7396
7397qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
7398{
7399 return toIntegral<qlonglong>(string, ok, base);
7400}
7401
7431qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
7432{
7433 return toIntegral<qulonglong>(string, ok, base);
7434}
7435
7642double QString::toDouble(bool *ok) const
7643{
7644 return QStringView(*this).toDouble(ok);
7645}
7646
7647double QStringView::toDouble(bool *ok) const
7648{
7649 QStringView string = qt_trimmed(*this);
7650 QVarLengthArray<uchar> latin1(string.size());
7651 qt_to_latin1(latin1.data(), string.utf16(), string.size());
7652 auto r = qt_asciiToDouble(reinterpret_cast<const char *>(latin1.data()), string.size());
7653 if (ok != nullptr)
7654 *ok = r.ok();
7655 return r.result;
7656}
7657
7688float QString::toFloat(bool *ok) const
7689{
7691}
7692
7693float QStringView::toFloat(bool *ok) const
7694{
7696}
7697
7733{
7734 return *this = number(n, base);
7735}
7736
7741{
7742 return *this = number(n, base);
7743}
7744
7765{
7766 return *this = number(n, format, precision);
7767}
7768
7805{
7806 return number(qlonglong(n), base);
7807}
7808
7815{
7816 return number(qulonglong(n), base);
7817}
7818
7823{
7824 return number(qlonglong(n), base);
7825}
7826
7831{
7832 return number(qulonglong(n), base);
7833}
7834
7839{
7840#if defined(QT_CHECK_RANGE)
7841 if (base < 2 || base > 36) {
7842 qWarning("QString::setNum: Invalid base (%d)", base);
7843 base = 10;
7844 }
7845#endif
7846 bool negative = n < 0;
7847 /*
7848 Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
7849 taking an absolute value has to take a slight detour.
7850 */
7851 return qulltoBasicLatin(negative ? 1u + qulonglong(-(n + 1)) : qulonglong(n), base, negative);
7852}
7853
7858{
7859#if defined(QT_CHECK_RANGE)
7860 if (base < 2 || base > 36) {
7861 qWarning("QString::setNum: Invalid base (%d)", base);
7862 base = 10;
7863 }
7864#endif
7865 return qulltoBasicLatin(n, base, false);
7866}
7867
7868
7881{
7883
7885 case 'f':
7887 break;
7888 case 'e':
7890 break;
7891 case 'g':
7893 break;
7894 default:
7895#if defined(QT_CHECK_RANGE)
7896 qWarning("QString::setNum: Invalid format char '%c'", format);
7897#endif
7898 break;
7899 }
7900
7902}
7903
7904namespace {
7905template<class ResultList, class StringSource>
7906static ResultList splitString(const StringSource &source, QStringView sep,
7907 Qt::SplitBehavior behavior, Qt::CaseSensitivity cs)
7908{
7909 ResultList list;
7910 typename StringSource::size_type start = 0;
7911 typename StringSource::size_type end;
7912 typename StringSource::size_type extra = 0;
7913 while ((end = QtPrivate::findString(QStringView(source.constData(), source.size()), start + extra, sep, cs)) != -1) {
7914 if (start != end || behavior == Qt::KeepEmptyParts)
7915 list.append(source.sliced(start, end - start));
7916 start = end + sep.size();
7917 extra = (sep.size() == 0 ? 1 : 0);
7918 }
7919 if (start != source.size() || behavior == Qt::KeepEmptyParts)
7920 list.append(source.sliced(start));
7921 return list;
7922}
7923
7924} // namespace
7925
7956QStringList QString::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
7957{
7958 return splitString<QStringList>(*this, sep, behavior, cs);
7959}
7960
7965QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
7966{
7967 return splitString<QStringList>(*this, QStringView(&sep, 1), behavior, cs);
7968}
7969
7988{
7989 return splitString<QList<QStringView>>(QStringView(*this), sep, behavior, cs);
7990}
7991
7993{
7994 return split(QStringView(&sep, 1), behavior, cs);
7995}
7996
7997#if QT_CONFIG(regularexpression)
7998namespace {
7999template<class ResultList, typename String, typename MatchingFunction>
8000static ResultList splitString(const String &source, const QRegularExpression &re,
8001 MatchingFunction matchingFunction,
8002 Qt::SplitBehavior behavior)
8003{
8004 ResultList list;
8005 if (!re.isValid()) {
8006 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString::split");
8007 return list;
8008 }
8009
8010 qsizetype start = 0;
8011 qsizetype end = 0;
8013 while (iterator.hasNext()) {
8015 end = match.capturedStart();
8016 if (start != end || behavior == Qt::KeepEmptyParts)
8017 list.append(source.sliced(start, end - start));
8018 start = match.capturedEnd();
8019 }
8020
8021 if (start != source.size() || behavior == Qt::KeepEmptyParts)
8022 list.append(source.sliced(start));
8023
8024 return list;
8025}
8026} // namespace
8027
8055QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
8056{
8057#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
8058 const auto matchingFunction = qOverload<const QString &, qsizetype, QRegularExpression::MatchType, QRegularExpression::MatchOptions>(&QRegularExpression::globalMatch);
8059#else
8060 const auto matchingFunction = &QRegularExpression::globalMatch;
8061#endif
8062 return splitString<QStringList>(*this,
8063 re,
8064 matchingFunction,
8065 behavior);
8066}
8067
8080QList<QStringView> QStringView::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
8081{
8082 return splitString<QList<QStringView>>(*this, re, &QRegularExpression::globalMatchView, behavior);
8083}
8084
8085#endif // QT_CONFIG(regularexpression)
8086
8113{
8114 if (d.size == 0)
8115 return *this;
8116
8117 if (times <= 1) {
8118 if (times == 1)
8119 return *this;
8120 return QString();
8121 }
8122
8123 const qsizetype resultSize = times * d.size;
8124
8126 result.reserve(resultSize);
8127 if (result.capacity() != resultSize)
8128 return QString(); // not enough memory
8129
8130 memcpy(result.d.data(), d.data(), d.size * sizeof(QChar));
8131
8132 qsizetype sizeSoFar = d.size;
8133 char16_t *end = result.d.data() + sizeSoFar;
8134
8135 const qsizetype halfResultSize = resultSize >> 1;
8136 while (sizeSoFar <= halfResultSize) {
8137 memcpy(end, result.d.data(), sizeSoFar * sizeof(QChar));
8138 end += sizeSoFar;
8139 sizeSoFar <<= 1;
8140 }
8141 memcpy(end, result.d.data(), (resultSize - sizeSoFar) * sizeof(QChar));
8142 result.d.data()[resultSize] = '\0';
8143 result.d.size = resultSize;
8144 return result;
8145}
8146
8148{
8149 {
8150 // check if it's fully ASCII first, because then we have no work
8151 auto start = reinterpret_cast<const char16_t *>(data->constData());
8152 const char16_t *p = start + from;
8153 if (isAscii_helper(p, p + data->size() - from))
8154 return;
8155 if (p > start + from)
8156 from = p - start - 1; // need one before the non-ASCII to perform NFC
8157 }
8158
8159 if (version == QChar::Unicode_Unassigned) {
8160 version = QChar::currentUnicodeVersion();
8161 } else if (int(version) <= NormalizationCorrectionsVersionMax) {
8162 const QString &s = *data;
8163 QChar *d = nullptr;
8165 if (n.version > version) {
8166 qsizetype pos = from;
8167 if (QChar::requiresSurrogates(n.ucs4)) {
8168 char16_t ucs4High = QChar::highSurrogate(n.ucs4);
8169 char16_t ucs4Low = QChar::lowSurrogate(n.ucs4);
8170 char16_t oldHigh = QChar::highSurrogate(n.old_mapping);
8171 char16_t oldLow = QChar::lowSurrogate(n.old_mapping);
8172 while (pos < s.size() - 1) {
8173 if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) {
8174 if (!d)
8175 d = data->data();
8176 d[pos] = QChar(oldHigh);
8177 d[++pos] = QChar(oldLow);
8178 }
8179 ++pos;
8180 }
8181 } else {
8182 while (pos < s.size()) {
8183 if (s.at(pos).unicode() == n.ucs4) {
8184 if (!d)
8185 d = data->data();
8186 d[pos] = QChar(n.old_mapping);
8187 }
8188 ++pos;
8189 }
8190 }
8191 }
8192 }
8193 }
8194
8195 if (normalizationQuickCheckHelper(data, mode, from, &from))
8196 return;
8197
8199
8200 canonicalOrderHelper(data, version, from);
8201
8203 return;
8204
8205 composeHelper(data, version, from);
8206}
8207
8213{
8214 QString copy = *this;
8215 qt_string_normalize(&copy, mode, version, 0);
8216 return copy;
8217}
8218
8219#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
8220static void checkArgEscape(QStringView s)
8221{
8222 // If we're in here, it means that qArgDigitValue has accepted the
8223 // digit. We can skip the check in case we already know it will
8224 // succeed.
8225 if (!supportUnicodeDigitValuesInArg())
8226 return;
8227
8228 const auto isNonAsciiDigit = [](QChar c) {
8229 return c.unicode() < u'0' || c.unicode() > u'9';
8230 };
8231
8232 if (std::any_of(s.begin(), s.end(), isNonAsciiDigit)) {
8233 const auto accumulateDigit = [](int partial, QChar digit) {
8234 return partial * 10 + digit.digitValue();
8235 };
8236 const int parsedNumber = std::accumulate(s.begin(), s.end(), 0, accumulateDigit);
8237
8238 qWarning("QString::arg(): the replacement \"%%%ls\" contains non-ASCII digits;\n"
8239 " it is currently being interpreted as the %d-th substitution.\n"
8240 " This is deprecated; support for non-ASCII digits will be dropped\n"
8241 " in a future version of Qt.",
8242 qUtf16Printable(s.toString()),
8243 parsedNumber);
8244 }
8245}
8246#endif
8247
8249{
8250 int min_escape; // lowest escape sequence number
8251 qsizetype occurrences; // number of occurrences of the lowest escape sequence number
8252 qsizetype locale_occurrences; // number of occurrences of the lowest escape sequence number that
8253 // contain 'L'
8254 qsizetype escape_len; // total length of escape sequences which will be replaced
8255};
8256
8258{
8259 const QChar *uc_begin = s.begin();
8260 const QChar *uc_end = s.end();
8261
8263
8264 d.min_escape = INT_MAX;
8265 d.occurrences = 0;
8266 d.escape_len = 0;
8267 d.locale_occurrences = 0;
8268
8269 const QChar *c = uc_begin;
8270 while (c != uc_end) {
8271 while (c != uc_end && c->unicode() != '%')
8272 ++c;
8273
8274 if (c == uc_end)
8275 break;
8276 const QChar *escape_start = c;
8277 if (++c == uc_end)
8278 break;
8279
8280 bool locale_arg = false;
8281 if (c->unicode() == 'L') {
8282 locale_arg = true;
8283 if (++c == uc_end)
8284 break;
8285 }
8286
8287 int escape = qArgDigitValue(*c);
8288 if (escape == -1)
8289 continue;
8290
8291 // ### Qt 7: do not allow anything but ASCII digits
8292 // in arg()'s replacements.
8293#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
8294 const QChar *escapeBegin = c;
8295 const QChar *escapeEnd = escapeBegin + 1;
8296#endif
8297
8298 ++c;
8299
8300 if (c != uc_end) {
8301 const int next_escape = qArgDigitValue(*c);
8302 if (next_escape != -1) {
8303 escape = (10 * escape) + next_escape;
8304 ++c;
8305#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
8306 ++escapeEnd;
8307#endif
8308 }
8309 }
8310
8311#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
8312 checkArgEscape(QStringView(escapeBegin, escapeEnd));
8313#endif
8314
8315 if (escape > d.min_escape)
8316 continue;
8317
8318 if (escape < d.min_escape) {
8319 d.min_escape = escape;
8320 d.occurrences = 0;
8321 d.escape_len = 0;
8322 d.locale_occurrences = 0;
8323 }
8324
8325 ++d.occurrences;
8326 if (locale_arg)
8327 ++d.locale_occurrences;
8328 d.escape_len += c - escape_start;
8329 }
8330 return d;
8331}
8332
8334 QStringView arg, QStringView larg, QChar fillChar)
8335{
8336 // Negative field-width for right-padding, positive for left-padding:
8337 const qsizetype abs_field_width = qAbs(field_width);
8338 const qsizetype result_len =
8339 s.size() - d.escape_len
8340 + (d.occurrences - d.locale_occurrences) * qMax(abs_field_width, arg.size())
8341 + d.locale_occurrences * qMax(abs_field_width, larg.size());
8342
8343 QString result(result_len, Qt::Uninitialized);
8344 QChar *rc = const_cast<QChar *>(result.unicode());
8345 QChar *const result_end = rc + result_len;
8346 qsizetype repl_cnt = 0;
8347
8348 const QChar *c = s.begin();
8349 const QChar *const uc_end = s.end();
8350 while (c != uc_end) {
8351 Q_ASSERT(d.occurrences > repl_cnt);
8352 /* We don't have to check increments of c against uc_end because, as
8353 long as d.occurrences > repl_cnt, we KNOW there are valid escape
8354 sequences remaining. */
8355
8356 const QChar *text_start = c;
8357 while (c->unicode() != '%')
8358 ++c;
8359
8360 const QChar *escape_start = c++;
8361 const bool localize = c->unicode() == 'L';
8362 if (localize)
8363 ++c;
8364
8365 int escape = qArgDigitValue(*c);
8366 if (escape != -1 && c + 1 != uc_end) {
8367 const int digit = qArgDigitValue(c[1]);
8368 if (digit != -1) {
8369 ++c;
8370 escape = 10 * escape + digit;
8371 }
8372 }
8373
8374 if (escape != d.min_escape) {
8375 memcpy(rc, text_start, (c - text_start) * sizeof(QChar));
8376 rc += c - text_start;
8377 } else {
8378 ++c;
8379
8380 memcpy(rc, text_start, (escape_start - text_start) * sizeof(QChar));
8381 rc += escape_start - text_start;
8382
8383 const QStringView use = localize ? larg : arg;
8384 const qsizetype pad_chars = abs_field_width - use.size();
8385 // (If negative, relevant loops are no-ops: no need to check.)
8386
8387 if (field_width > 0) { // left padded
8388 rc = std::fill_n(rc, pad_chars, fillChar);
8389 }
8390
8391 memcpy(rc, use.data(), use.size() * sizeof(QChar));
8392 rc += use.size();
8393
8394 if (field_width < 0) { // right padded
8395 rc = std::fill_n(rc, pad_chars, fillChar);
8396 }
8397
8398 if (++repl_cnt == d.occurrences) {
8399 memcpy(rc, c, (uc_end - c) * sizeof(QChar));
8400 rc += uc_end - c;
8401 Q_ASSERT(rc == result_end);
8402 c = uc_end;
8403 }
8404 }
8405 }
8406 Q_ASSERT(rc == result_end);
8407
8408 return result;
8409}
8410
8440QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
8441{
8442 return arg(qToStringViewIgnoringNull(a), fieldWidth, fillChar);
8443}
8444
8477QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
8478{
8479 ArgEscapeData d = findArgEscapes(*this);
8480
8481 if (Q_UNLIKELY(d.occurrences == 0)) {
8482 qWarning("QString::arg: Argument missing: %ls, %ls", qUtf16Printable(*this),
8483 qUtf16Printable(a.toString()));
8484 return *this;
8485 }
8486 return replaceArgEscapes(*this, d, fieldWidth, a, a, fillChar);
8487}
8488
8513QString QString::arg(QLatin1StringView a, int fieldWidth, QChar fillChar) const
8514{
8516 return arg(QStringView(utf16.data(), utf16.size()), fieldWidth, fillChar);
8517}
8518
8606QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
8607{
8608 ArgEscapeData d = findArgEscapes(*this);
8609
8610 if (d.occurrences == 0) {
8611 qWarning() << "QString::arg: Argument missing:" << *this << ',' << a;
8612 return *this;
8613 }
8614
8615 unsigned flags = QLocaleData::NoFlags;
8616 // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
8617 if (fillChar == u'0')
8619
8620 QString arg;
8621 if (d.occurrences > d.locale_occurrences) {
8622 arg = QLocaleData::c()->longLongToString(a, -1, base, fieldWidth, flags);
8623 Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
8624 || fieldWidth <= arg.size());
8625 }
8626
8627 QString localeArg;
8628 if (d.locale_occurrences > 0) {
8629 QLocale locale;
8630 if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
8632 localeArg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags);
8633 Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
8634 || fieldWidth <= localeArg.size());
8635 }
8636
8637 return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
8638}
8639
8654QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) const
8655{
8656 ArgEscapeData d = findArgEscapes(*this);
8657
8658 if (d.occurrences == 0) {
8659 qWarning() << "QString::arg: Argument missing:" << *this << ',' << a;
8660 return *this;
8661 }
8662
8663 unsigned flags = QLocaleData::NoFlags;
8664 // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
8665 if (fillChar == u'0')
8667
8668 QString arg;
8669 if (d.occurrences > d.locale_occurrences) {
8670 arg = QLocaleData::c()->unsLongLongToString(a, -1, base, fieldWidth, flags);
8671 Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
8672 || fieldWidth <= arg.size());
8673 }
8674
8675 QString localeArg;
8676 if (d.locale_occurrences > 0) {
8677 QLocale locale;
8678 if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
8680 localeArg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags);
8681 Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
8682 || fieldWidth <= localeArg.size());
8683 }
8684
8685 return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
8686}
8687
8724QString QString::arg(QChar a, int fieldWidth, QChar fillChar) const
8725{
8726 return arg(QStringView{&a, 1}, fieldWidth, fillChar);
8727}
8728
8734QString QString::arg(char a, int fieldWidth, QChar fillChar) const
8735{
8736 return arg(QLatin1Char(a), fieldWidth, fillChar);
8737}
8738
8754QString QString::arg(double a, int fieldWidth, char format, int precision, QChar fillChar) const
8755{
8756 ArgEscapeData d = findArgEscapes(*this);
8757
8758 if (d.occurrences == 0) {
8759 qWarning("QString::arg: Argument missing: %s, %g", toLocal8Bit().data(), a);
8760 return *this;
8761 }
8762
8763 unsigned flags = QLocaleData::NoFlags;
8764 // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
8765 if (fillChar == u'0')
8767
8768 if (isAsciiUpper(format))
8770
8773 case 'f':
8775 break;
8776 case 'e':
8778 break;
8779 case 'g':
8781 break;
8782 default:
8783#if defined(QT_CHECK_RANGE)
8784 qWarning("QString::arg: Invalid format char '%c'", format);
8785#endif
8786 break;
8787 }
8788
8789 QString arg;
8790 if (d.occurrences > d.locale_occurrences) {
8791 arg = QLocaleData::c()->doubleToString(a, precision, form, fieldWidth,
8793 Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
8794 || fieldWidth <= arg.size());
8795 }
8796
8797 QString localeArg;
8798 if (d.locale_occurrences > 0) {
8799 QLocale locale;
8800
8801 const QLocale::NumberOptions numberOptions = locale.numberOptions();
8802 if (!(numberOptions & QLocale::OmitGroupSeparator))
8804 if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
8806 if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
8808 localeArg = locale.d->m_data->doubleToString(a, precision, form, fieldWidth, flags);
8809 Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
8810 || fieldWidth <= localeArg.size());
8811 }
8812
8813 return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
8814}
8815
8816static inline char16_t to_unicode(const QChar c) { return c.unicode(); }
8817static inline char16_t to_unicode(const char c) { return QLatin1Char{c}.unicode(); }
8818
8819template <typename Char>
8820static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999)
8821{
8822 qsizetype i = *pos;
8823 ++i;
8824 if (i < len && uc[i] == u'L')
8825 ++i;
8826 if (i < len) {
8827 int escape = to_unicode(uc[i]) - '0';
8828 if (uint(escape) >= 10U)
8829 return -1;
8830 ++i;
8831 while (i < len) {
8832 int digit = to_unicode(uc[i]) - '0';
8833 if (uint(digit) >= 10U)
8834 break;
8835 escape = (escape * 10) + digit;
8836 ++i;
8837 }
8838 if (escape <= maxNumber) {
8839 *pos = i;
8840 return escape;
8841 }
8842 }
8843 return -1;
8844}
8845
8846/*
8847 Algorithm for multiArg:
8848
8849 1. Parse the string as a sequence of verbatim text and placeholders (%L?\d{,3}).
8850 The L is parsed and accepted for compatibility with non-multi-arg, but since
8851 multiArg only accepts strings as replacements, the localization request can
8852 be safely ignored.
8853 2. The result of step (1) is a list of (string-ref,int)-tuples. The string-ref
8854 either points at text to be copied verbatim (in which case the int is -1),
8855 or, initially, at the textual representation of the placeholder. In that case,
8856 the int contains the numerical number as parsed from the placeholder.
8857 3. Next, collect all the non-negative ints found, sort them in ascending order and
8858 remove duplicates.
8859 3a. If the result has more entries than multiArg() was given replacement strings,
8860 we have found placeholders we can't satisfy with replacement strings. That is
8861 fine (there could be another .arg() call coming after this one), so just
8862 truncate the result to the number of actual multiArg() replacement strings.
8863 3b. If the result has less entries than multiArg() was given replacement strings,
8864 the string is missing placeholders. This is an error that the user should be
8865 warned about.
8866 4. The result of step (3) is a mapping from the index of any replacement string to
8867 placeholder number. This is the wrong way around, but since placeholder
8868 numbers could get as large as 999, while we typically don't have more than 9
8869 replacement strings, we trade 4K of sparsely-used memory for doing a reverse lookup
8870 each time we need to map a placeholder number to a replacement string index
8871 (that's a linear search; but still *much* faster than using an associative container).
8872 5. Next, for each of the tuples found in step (1), do the following:
8873 5a. If the int is negative, do nothing.
8874 5b. Otherwise, if the int is found in the result of step (3) at index I, replace
8875 the string-ref with a string-ref for the (complete) I'th replacement string.
8876 5c. Otherwise, do nothing.
8877 6. Concatenate all string refs into a single result string.
8878*/
8879
8880namespace {
8881struct Part
8882{
8883 Part() = default; // for QVarLengthArray; do not use
8884 constexpr Part(QStringView s, int num = -1)
8885 : tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {}
8886 constexpr Part(QLatin1StringView s, int num = -1)
8887 : tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {}
8888
8889 void reset(QStringView s) noexcept { *this = {s, number}; }
8890 void reset(QLatin1StringView s) noexcept { *this = {s, number}; }
8891
8893 int number;
8894 const void *data;
8896};
8897} // unnamed namespace
8898
8900
8901namespace {
8902
8903enum { ExpectedParts = 32 };
8904
8905typedef QVarLengthArray<Part, ExpectedParts> ParseResult;
8906typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap;
8907
8908template <typename StringView>
8909static ParseResult parseMultiArgFormatString(StringView s)
8910{
8911 ParseResult result;
8912
8913 const auto uc = s.data();
8914 const auto len = s.size();
8915 const auto end = len - 1;
8916 qsizetype i = 0;
8917 qsizetype last = 0;
8918
8919 while (i < end) {
8920 if (uc[i] == u'%') {
8921 qsizetype percent = i;
8922 int number = getEscape(uc, &i, len);
8923 if (number != -1) {
8924 if (last != percent)
8925 result.push_back(Part{s.sliced(last, percent - last)}); // literal text (incl. failed placeholders)
8926 result.push_back(Part{s.sliced(percent, i - percent), number}); // parsed placeholder
8927 last = i;
8928 continue;
8929 }
8930 }
8931 ++i;
8932 }
8933
8934 if (last < len)
8935 result.push_back(Part{s.sliced(last, len - last)}); // trailing literal text
8936
8937 return result;
8938}
8939
8940static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult &parts)
8941{
8942 ArgIndexToPlaceholderMap result;
8943
8944 for (const Part &part : parts) {
8945 if (part.number >= 0)
8946 result.push_back(part.number);
8947 }
8948
8949 std::sort(result.begin(), result.end());
8950 result.erase(std::unique(result.begin(), result.end()),
8951 result.end());
8952
8953 return result;
8954}
8955
8956static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QtPrivate::ArgBase *args[])
8957{
8958 using namespace QtPrivate;
8959 qsizetype totalSize = 0;
8960 for (Part &part : parts) {
8961 if (part.number != -1) {
8962 const auto it = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), part.number);
8963 if (it != argIndexToPlaceholderMap.end()) {
8964 const auto &arg = *args[it - argIndexToPlaceholderMap.begin()];
8965 switch (arg.tag) {
8966 case ArgBase::L1:
8967 part.reset(static_cast<const QLatin1StringArg&>(arg).string);
8968 break;
8969 case ArgBase::U8:
8970 Q_UNREACHABLE(); // waiting for QUtf8String...
8971 break;
8972 case ArgBase::U16:
8973 part.reset(static_cast<const QStringViewArg&>(arg).string);
8974 break;
8975 }
8976 }
8977 }
8978 totalSize += part.size;
8979 }
8980 return totalSize;
8981}
8982
8983} // unnamed namespace
8984
8986Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); }
8987
8988template <typename StringView>
8989static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args)
8990{
8991 // Step 1-2 above
8992 ParseResult parts = parseMultiArgFormatString(pattern);
8993
8994 // 3-4
8995 ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);
8996
8997 if (static_cast<size_t>(argIndexToPlaceholderMap.size()) > numArgs) // 3a
8998 argIndexToPlaceholderMap.resize(qsizetype(numArgs));
8999 else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b
9000 qWarning("QString::arg: %d argument(s) missing in %ls",
9001 int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern)));
9002
9003 // 5
9004 const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args);
9005
9006 // 6:
9007 QString result(totalSize, Qt::Uninitialized);
9008 auto out = const_cast<QChar*>(result.constData());
9009
9010 for (const Part &part : parts) {
9011 switch (part.tag) {
9013 if (part.size) {
9014 qt_from_latin1(reinterpret_cast<char16_t*>(out),
9015 reinterpret_cast<const char*>(part.data), part.size);
9016 }
9017 break;
9019 Q_UNREACHABLE(); // waiting for QUtf8String
9020 break;
9022 if (part.size)
9023 memcpy(out, part.data, part.size * sizeof(QChar));
9024 break;
9025 }
9026 out += part.size;
9027 }
9028
9029 return result;
9030}
9031
9033{
9034 return argToQStringImpl(pattern, n, args);
9035}
9036
9038{
9039 return argToQStringImpl(pattern, n, args);
9040}
9041
9047{
9048 const char16_t *p = d.data();
9049 const char16_t * const end = p + d.size;
9050 while (p < end) {
9051 char16_t uc = *p;
9052 // sort out regions of complex text formatting
9053 if (uc > 0x058f && (uc < 0x1100 || uc > 0xfb0f)) {
9054 return false;
9055 }
9056 p++;
9057 }
9058
9059 return true;
9060}
9061
9069{
9071}
9072
9173{
9174 const auto start = std::distance(cbegin(), first);
9175 const auto len = std::distance(first, last);
9176 remove(start, len);
9177 return begin() + start;
9178}
9179
9243{
9244 return QString(DataPointer::fromRawData(const_cast<char16_t *>(reinterpret_cast<const char16_t *>(unicode)), size));
9245}
9246
9262{
9263 if (!unicode || !size) {
9264 clear();
9265 }
9266 *this = fromRawData(unicode, size);
9267 return *this;
9268}
9269
9308#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
9319{
9320 if (out.version() == 1) {
9321 out << str.toLatin1();
9322 } else {
9323 if (!str.isNull() || out.version() < 3) {
9325 out.writeBytes(reinterpret_cast<const char *>(str.unicode()),
9326 static_cast<uint>(sizeof(QChar) * str.size()));
9327 } else {
9329 qbswap<sizeof(char16_t)>(str.constData(), str.size(), buffer.data());
9330 out.writeBytes(reinterpret_cast<const char *>(buffer.data()),
9331 static_cast<uint>(sizeof(char16_t) * buffer.size()));
9332 }
9333 } else {
9334 // write null marker
9335 out << (quint32)0xffffffff;
9336 }
9337 }
9338 return out;
9339}
9340
9351{
9352 if (in.version() == 1) {
9353 QByteArray l;
9354 in >> l;
9356 } else {
9357 quint32 bytes = 0;
9358 in >> bytes; // read size of string
9359 if (bytes == 0xffffffff) { // null string
9360 str = QString();
9361 } else if (bytes > 0) { // not empty
9362 if (bytes & 0x1) {
9363 str.clear();
9365 return in;
9366 }
9367
9368 const quint32 Step = 1024 * 1024;
9369 quint32 len = bytes / 2;
9370 quint32 allocated = 0;
9371
9372 while (allocated < len) {
9373 int blockSize = qMin(Step, len - allocated);
9374 str.resize(allocated + blockSize);
9375 if (in.readRawData(reinterpret_cast<char *>(str.data()) + allocated * 2,
9376 blockSize * 2) != blockSize * 2) {
9377 str.clear();
9378 in.setStatus(QDataStream::ReadPastEnd);
9379 return in;
9380 }
9381 allocated += blockSize;
9382 }
9383
9384 if ((in.byteOrder() == QDataStream::BigEndian)
9386 char16_t *data = reinterpret_cast<char16_t *>(str.data());
9387 qbswap<sizeof(*data)>(data, len, data);
9388 }
9389 } else {
9391 }
9392 }
9393 return in;
9394}
9395#endif // QT_NO_DATASTREAM
9396
9422{
9423 int isolateLevel = 0;
9424
9425 for (QStringIterator i(string); i.hasNext();) {
9426 const char32_t c = i.next();
9427
9428 switch (QChar::direction(c)) {
9429 case QChar::DirRLI:
9430 case QChar::DirLRI:
9431 case QChar::DirFSI:
9432 ++isolateLevel;
9433 break;
9434 case QChar::DirPDI:
9435 if (isolateLevel)
9436 --isolateLevel;
9437 break;
9438 case QChar::DirL:
9439 if (isolateLevel)
9440 break;
9441 return false;
9442 case QChar::DirR:
9443 case QChar::DirAL:
9444 if (isolateLevel)
9445 break;
9446 return true;
9447 case QChar::DirEN:
9448 case QChar::DirES:
9449 case QChar::DirET:
9450 case QChar::DirAN:
9451 case QChar::DirCS:
9452 case QChar::DirB:
9453 case QChar::DirS:
9454 case QChar::DirWS:
9455 case QChar::DirON:
9456 case QChar::DirLRE:
9457 case QChar::DirLRO:
9458 case QChar::DirRLE:
9459 case QChar::DirRLO:
9460 case QChar::DirPDF:
9461 case QChar::DirNSM:
9462 case QChar::DirBN:
9463 break;
9464 }
9465 }
9466 return false;
9467}
9468
9470{
9471 qsizetype num = 0;
9472 qsizetype i = -1;
9473 if (haystack.size() > 500 && needle.size() > 5) {
9474 QStringMatcher matcher(needle, cs);
9475 while ((i = matcher.indexIn(haystack, i + 1)) != -1)
9476 ++num;
9477 } else {
9478 while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1)
9479 ++num;
9480 }
9481 return num;
9482}
9483
9485{
9486 if (cs == Qt::CaseSensitive)
9487 return std::count(haystack.cbegin(), haystack.cend(), needle);
9488
9489 needle = foldCase(needle);
9490 return std::count_if(haystack.cbegin(), haystack.cend(),
9491 [needle](const QChar c) { return foldAndCompare(c, needle); });
9492}
9493
9495{
9496 qsizetype num = 0;
9497 qsizetype i = -1;
9498
9499 QLatin1StringMatcher matcher(needle, cs);
9500 while ((i = matcher.indexIn(haystack, i + 1)) != -1)
9501 ++num;
9502
9503 return num;
9504}
9505
9507{
9508 if (haystack.size() < needle.size())
9509 return 0;
9510
9511 if (!QtPrivate::isLatin1(needle)) // won't find non-L1 UTF-16 needles in a L1 haystack!
9512 return 0;
9513
9514 qsizetype num = 0;
9515 qsizetype i = -1;
9516
9517 QVarLengthArray<uchar> s(needle.size());
9518 qt_to_latin1_unchecked(s.data(), needle.utf16(), needle.size());
9519
9520 QLatin1StringMatcher matcher(QLatin1StringView(reinterpret_cast<char *>(s.data()), s.size()),
9521 cs);
9522 while ((i = matcher.indexIn(haystack, i + 1)) != -1)
9523 ++num;
9524
9525 return num;
9526}
9527
9529{
9530 if (haystack.size() < needle.size())
9531 return -1;
9532
9534 return QtPrivate::count(haystack, QStringView(s.data(), s.size()), cs);
9535}
9536
9538{
9539 // non-L1 needles cannot possibly match in L1-only haystacks
9540 if (needle.unicode() > 0xff)
9541 return 0;
9542
9543 if (cs == Qt::CaseSensitive) {
9544 return std::count(haystack.cbegin(), haystack.cend(), needle.toLatin1());
9545 } else {
9546 return std::count_if(haystack.cbegin(), haystack.cend(),
9547 CaseInsensitiveL1::matcher(needle.toLatin1()));
9548 }
9549}
9550
9572{
9573 return qt_starts_with_impl(haystack, needle, cs);
9574}
9575
9577{
9578 return qt_starts_with_impl(haystack, needle, cs);
9579}
9580
9582{
9583 return qt_starts_with_impl(haystack, needle, cs);
9584}
9585
9587{
9588 return qt_starts_with_impl(haystack, needle, cs);
9589}
9590
9612{
9613 return qt_ends_with_impl(haystack, needle, cs);
9614}
9615
9617{
9618 return qt_ends_with_impl(haystack, needle, cs);
9619}
9620
9622{
9623 return qt_ends_with_impl(haystack, needle, cs);
9624}
9625
9627{
9628 return qt_ends_with_impl(haystack, needle, cs);
9629}
9630
9632{
9633 const qsizetype l = haystack0.size();
9634 const qsizetype sl = needle0.size();
9635 if (from < 0)
9636 from += l;
9637 if (std::size_t(sl + from) > std::size_t(l))
9638 return -1;
9639 if (!sl)
9640 return from;
9641 if (!l)
9642 return -1;
9643
9644 if (sl == 1)
9645 return qFindChar(haystack0, needle0[0], from, cs);
9646
9647 /*
9648 We use the Boyer-Moore algorithm in cases where the overhead
9649 for the skip table should pay off, otherwise we use a simple
9650 hash function.
9651 */
9652 if (l > 500 && sl > 5)
9653 return qFindStringBoyerMoore(haystack0, from, needle0, cs);
9654
9655 auto sv = [sl](const char16_t *v) { return QStringView(v, sl); };
9656 /*
9657 We use some hashing for efficiency's sake. Instead of
9658 comparing strings, we compare the hash value of str with that
9659 of a part of this QString. Only if that matches, we call
9660 qt_string_compare().
9661 */
9662 const char16_t *needle = needle0.utf16();
9663 const char16_t *haystack = haystack0.utf16() + from;
9664 const char16_t *end = haystack0.utf16() + (l - sl);
9665 const std::size_t sl_minus_1 = sl - 1;
9666 std::size_t hashNeedle = 0, hashHaystack = 0;
9667 qsizetype idx;
9668
9669 if (cs == Qt::CaseSensitive) {
9670 for (idx = 0; idx < sl; ++idx) {
9671 hashNeedle = ((hashNeedle<<1) + needle[idx]);
9672 hashHaystack = ((hashHaystack<<1) + haystack[idx]);
9673 }
9674 hashHaystack -= haystack[sl_minus_1];
9675
9676 while (haystack <= end) {
9677 hashHaystack += haystack[sl_minus_1];
9678 if (hashHaystack == hashNeedle
9679 && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
9680 return haystack - haystack0.utf16();
9681
9682 REHASH(*haystack);
9683 ++haystack;
9684 }
9685 } else {
9686 const char16_t *haystack_start = haystack0.utf16();
9687 for (idx = 0; idx < sl; ++idx) {
9688 hashNeedle = (hashNeedle<<1) + foldCase(needle + idx, needle);
9689 hashHaystack = (hashHaystack<<1) + foldCase(haystack + idx, haystack_start);
9690 }
9691 hashHaystack -= foldCase(haystack + sl_minus_1, haystack_start);
9692
9693 while (haystack <= end) {
9694 hashHaystack += foldCase(haystack + sl_minus_1, haystack_start);
9695 if (hashHaystack == hashNeedle
9696 && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseInsensitive) == 0)
9697 return haystack - haystack0.utf16();
9698
9699 REHASH(foldCase(haystack, haystack_start));
9700 ++haystack;
9701 }
9702 }
9703 return -1;
9704}
9705
9707{
9708 if (haystack.size() < needle.size())
9709 return -1;
9710
9712 return QtPrivate::findString(haystack, from, QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), cs);
9713}
9714
9716{
9717 if (haystack.size() < needle.size())
9718 return -1;
9719
9720 if (!QtPrivate::isLatin1(needle)) // won't find non-L1 UTF-16 needles in a L1 haystack!
9721 return -1;
9722
9723 if (needle.size() == 1) {
9724 const char n = needle.front().toLatin1();
9725 return QtPrivate::findString(haystack, from, QLatin1StringView(&n, 1), cs);
9726 }
9727
9728 QVarLengthArray<char> s(needle.size());
9729 qt_to_latin1_unchecked(reinterpret_cast<uchar *>(s.data()), needle.utf16(), needle.size());
9730 return QtPrivate::findString(haystack, from, QLatin1StringView(s.data(), s.size()), cs);
9731}
9732
9734{
9735 if (from < 0)
9736 from += haystack.size();
9737 if (from < 0)
9738 return -1;
9739 qsizetype adjustedSize = haystack.size() - from;
9740 if (adjustedSize < needle.size())
9741 return -1;
9742 if (needle.size() == 0)
9743 return from;
9744
9745 if (cs == Qt::CaseSensitive) {
9746
9747 if (needle.size() == 1) {
9748 Q_ASSUME(haystack.data() != nullptr); // see size check above
9749 if (auto it = memchr(haystack.data() + from, needle.front().toLatin1(), adjustedSize))
9750 return static_cast<const char *>(it) - haystack.data();
9751 return -1;
9752 }
9753
9755 return matcher.indexIn(haystack, from);
9756 }
9757
9758 // If the needle is sufficiently small we simply iteratively search through
9759 // the haystack. When the needle is too long we use a boyer-moore searcher
9760 // from the standard library, if available. If it is not available then the
9761 // QLatin1Strings are converted to QString and compared as such. Though
9762 // initialization is slower the boyer-moore search it employs still makes up
9763 // for it when haystack and needle are sufficiently long.
9764 // The needle size was chosen by testing various lengths using the
9765 // qstringtokenizer benchmark with the
9766 // "tokenize_qlatin1string_qlatin1string" test.
9767#ifdef Q_CC_MSVC
9768 const qsizetype threshold = 1;
9769#else
9770 const qsizetype threshold = 13;
9771#endif
9772 if (needle.size() <= threshold) {
9773 const auto begin = haystack.begin();
9774 const auto end = haystack.end() - needle.size() + 1;
9775 auto ciMatch = CaseInsensitiveL1::matcher(needle[0].toLatin1());
9776 const qsizetype nlen1 = needle.size() - 1;
9777 for (auto it = std::find_if(begin + from, end, ciMatch); it < end;
9778 it = std::find_if(it + 1, end, ciMatch)) {
9779 // In this comparison we skip the first character because we know it's a match
9780 if (!nlen1 || QLatin1StringView(it + 1, nlen1).compare(needle.sliced(1), cs) == 0)
9781 return std::distance(begin, it);
9782 }
9783 return -1;
9784 }
9785
9787 return matcher.indexIn(haystack, from);
9788}
9789
9791{
9792 return qLastIndexOf(haystack, from, needle, cs);
9793}
9794
9796{
9797 return qLastIndexOf(haystack, from, needle, cs);
9798}
9799
9801{
9802 return qLastIndexOf(haystack, from, needle, cs);
9803}
9804
9806{
9807 return qLastIndexOf(haystack, from, needle, cs);
9808}
9809
9810#if QT_CONFIG(regularexpression)
9811qsizetype QtPrivate::indexOf(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
9812{
9813 if (!re.isValid()) {
9814 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::indexOf");
9815 return -1;
9816 }
9817
9818 QRegularExpressionMatch match = stringHaystack
9819 ? re.match(*stringHaystack, from)
9820 : re.matchView(viewHaystack, from);
9821 if (match.hasMatch()) {
9822 const qsizetype ret = match.capturedStart();
9823 if (rmatch)
9824 *rmatch = std::move(match);
9825 return ret;
9826 }
9827
9828 return -1;
9829}
9830
9832{
9833 return indexOf(haystack, nullptr, re, from, rmatch);
9834}
9835
9836qsizetype QtPrivate::lastIndexOf(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, qsizetype from, QRegularExpressionMatch *rmatch)
9837{
9838 if (!re.isValid()) {
9839 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::lastIndexOf");
9840 return -1;
9841 }
9842
9843 qsizetype endpos = (from < 0) ? (viewHaystack.size() + from + 1) : (from + 1);
9845 ? re.globalMatch(*stringHaystack)
9846 : re.globalMatchView(viewHaystack);
9847 qsizetype lastIndex = -1;
9848 while (iterator.hasNext()) {
9850 qsizetype start = match.capturedStart();
9851 if (start < endpos) {
9852 lastIndex = start;
9853 if (rmatch)
9854 *rmatch = std::move(match);
9855 } else {
9856 break;
9857 }
9858 }
9859
9860 return lastIndex;
9861}
9862
9864{
9865 return lastIndexOf(haystack, nullptr, re, from, rmatch);
9866}
9867
9868bool QtPrivate::contains(QStringView viewHaystack, const QString *stringHaystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
9869{
9870 if (!re.isValid()) {
9871 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::contains");
9872 return false;
9873 }
9874 QRegularExpressionMatch m = stringHaystack
9875 ? re.match(*stringHaystack)
9876 : re.matchView(viewHaystack);
9877 bool hasMatch = m.hasMatch();
9878 if (hasMatch && rmatch)
9879 *rmatch = std::move(m);
9880 return hasMatch;
9881}
9882
9883bool QtPrivate::contains(QStringView haystack, const QRegularExpression &re, QRegularExpressionMatch *rmatch)
9884{
9885 return contains(haystack, nullptr, re, rmatch);
9886}
9887
9889{
9890 if (!re.isValid()) {
9891 qtWarnAboutInvalidRegularExpression(re.pattern(), "QString(View)::count");
9892 return 0;
9893 }
9894 qsizetype count = 0;
9895 qsizetype index = -1;
9896 qsizetype len = haystack.size();
9897 while (index <= len - 1) {
9898 QRegularExpressionMatch match = re.matchView(haystack, index + 1);
9899 if (!match.hasMatch())
9900 break;
9901 count++;
9902
9903 // Search again, from the next character after the beginning of this
9904 // capture. If the capture starts with a surrogate pair, both together
9905 // count as "one character".
9906 index = match.capturedStart();
9907 if (index < len && haystack[index].isHighSurrogate())
9908 ++index;
9909 }
9910 return count;
9911}
9912
9913#endif // QT_CONFIG(regularexpression)
9914
9927{
9928 QString rich;
9929 const qsizetype len = size();
9930 rich.reserve(qsizetype(len * 1.1));
9931 for (QChar ch : *this) {
9932 if (ch == u'<')
9933 rich += "&lt;"_L1;
9934 else if (ch == u'>')
9935 rich += "&gt;"_L1;
9936 else if (ch == u'&')
9937 rich += "&amp;"_L1;
9938 else if (ch == u'"')
9939 rich += "&quot;"_L1;
9940 else
9941 rich += ch;
9942 }
9943 rich.squeeze();
9944 return rich;
9945}
9946
9991#if QT_DEPRECATED_SINCE(6, 8)
10015#endif // QT_DEPRECATED_SINCE(6, 8)
10016
10046{
10047 qt_from_latin1(reinterpret_cast<char16_t *>(out), in.data(), size_t(in.size()));
10048}
10049
10135
10136#undef REHASH
\inmodule QtCore
static Q_CORE_EXPORT int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Returns an integer that compares to zero as lhs compares to rhs.
Definition qstring.cpp:1601
static Q_CORE_EXPORT bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
Definition qstring.cpp:1450
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
bool isNull() const noexcept
Returns true if this byte array is null; otherwise returns false.
\inmodule QtCore
Definition qchar.h:48
static constexpr QChar fromUcs2(char16_t c) noexcept
Definition qchar.h:98
@ ReplacementCharacter
Definition qchar.h:59
static constexpr bool requiresSurrogates(char32_t ucs4) noexcept
Returns true if the UCS-4-encoded character specified by ucs4 can be split into the high and low part...
Definition qchar.h:504
int digitValue() const noexcept
Returns the numeric value of the digit, or -1 if the character is not a digit.
Definition qchar.h:447
Direction direction() const noexcept
Returns the character's direction.
Definition qchar.h:437
@ DirFSI
Definition qchar.h:348
@ DirNSM
Definition qchar.h:347
@ DirPDF
Definition qchar.h:347
@ DirON
Definition qchar.h:346
@ DirLRO
Definition qchar.h:347
@ DirWS
Definition qchar.h:346
@ DirL
Definition qchar.h:346
@ DirEN
Definition qchar.h:346
@ DirCS
Definition qchar.h:346
@ DirRLO
Definition qchar.h:347
@ DirAN
Definition qchar.h:346
@ DirAL
Definition qchar.h:347
@ DirB
Definition qchar.h:346
@ DirRLI
Definition qchar.h:348
@ DirS
Definition qchar.h:346
@ DirPDI
Definition qchar.h:348
@ DirLRE
Definition qchar.h:347
@ DirLRI
Definition qchar.h:348
@ DirBN
Definition qchar.h:347
@ DirRLE
Definition qchar.h:347
@ DirET
Definition qchar.h:346
@ DirR
Definition qchar.h:346
@ DirES
Definition qchar.h:346
UnicodeVersion
Specifies which version of the \l{Unicode standard} introduced a certain character.
Definition qchar.h:407
@ Unicode_Unassigned
Definition qchar.h:408
static constexpr char16_t highSurrogate(char32_t ucs4) noexcept
Returns the high surrogate part of a UCS-4-encoded code point.
Definition qchar.h:518
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
QChar toCaseFolded() const noexcept
Returns the case folded equivalent of the character.
Definition qchar.h:451
static constexpr char16_t lowSurrogate(char32_t ucs4) noexcept
Returns the low surrogate part of a UCS-4-encoded code point.
Definition qchar.h:522
static UnicodeVersion QT_FASTCALL currentUnicodeVersion() noexcept Q_DECL_CONST_FUNCTION
Returns the most recent supported Unicode version.
Definition qchar.cpp:1513
static int defaultCompare(QStringView s1, QStringView s2)
\inmodule QtCore\reentrant
Definition qdatastream.h:30
constexpr QLatin1Char front() const
int compare(QStringView other, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr qsizetype size() const noexcept
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
QList< T > mid(qsizetype pos, qsizetype len=-1) const
Definition qlist.h:968
void append(parameter_type t)
Definition qlist.h:441
@ OmitGroupSeparator
Definition qlocale.h:869
@ IncludeTrailingZeroesAfterDot
Definition qlocale.h:873
@ OmitLeadingZeroInExponent
Definition qlocale.h:871
\inmodule QtCore \reentrant
\inmodule QtCore \reentrant
bool hasMatch() const
Returns true if the regular expression matched against the subject string, or false otherwise.
\inmodule QtCore \reentrant
bool isValid() const
Returns true if the regular expression is a valid regular expression (that is, it contains no syntax ...
int captureCount() const
Returns the number of capturing groups inside the pattern string, or -1 if the regular expression is ...
QRegularExpressionMatch matchView(QStringView subjectView, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
QString pattern() const
Returns the pattern string of the regular expression.
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
QRegularExpressionMatchIterator globalMatchView(QStringView subjectView, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
QRegularExpressionMatchIterator globalMatch(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to perform a global match of the regular expression against the given subject string,...
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
\inmodule QtCore
\inmodule QtCore
char32_t next(char32_t invalidAs=QChar::ReplacementCharacter)
bool hasNext() const
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
Q_CORE_EXPORT double toDouble(bool *ok=nullptr) const
Returns the string view converted to a double value.
Definition qstring.cpp:7647
Q_CORE_EXPORT float toFloat(bool *ok=nullptr) const
Returns the string view converted to a float value.
Definition qstring.cpp:7693
constexpr const storage_type * utf16() const noexcept
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
const_pointer data() const noexcept
const_iterator begin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the st...
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:7987
constexpr QStringView() noexcept
Constructs a null string view.
constexpr QStringView sliced(qsizetype pos) const noexcept
const_iterator end() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary character after...
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString right(qsizetype n) const
Returns a substring that contains the n rightmost characters of the string.
Definition qstring.cpp:5180
bool isSimpleText() const
Definition qstring.cpp:9046
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in the string.
Definition qstring.h:1197
QByteArray toLatin1() const &
Definition qstring.h:559
bool isDetached() const
Definition qstring.h:1105
QChar * iterator
Definition qstring.h:839
QString repeated(qsizetype times) const
Definition qstring.cpp:8112
double toDouble(bool *ok=nullptr) const
Returns the string converted to a double value.
Definition qstring.cpp:7642
QString last(qsizetype n) const
Definition qstring.h:339
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
QString & fill(QChar c, qsizetype size=-1)
Sets every character in the string to character ch.
Definition qstring.cpp:6198
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1173
QString rightJustified(qsizetype width, QChar fill=u' ', bool trunc=false) const
Returns a string of size() width that contains the fill character followed by the string.
Definition qstring.cpp:6803
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:7956
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6159
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:5883
static QString fromUcs4(const char32_t *, qsizetype size=-1)
Definition qstring.cpp:5915
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
const_iterator cbegin() const
Definition qstring.h:1201
QString & operator=(QChar c)
Definition qstring.cpp:2869
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
QString & setUnicode(const QChar *unicode, qsizetype size)
Resizes the string to size characters and copies unicode into the string.
Definition qstring.cpp:5938
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QList< uint > toUcs4() const
Definition qstring.cpp:5662
const_iterator cend() const
Definition qstring.h:1209
QStringPrivate DataPointer
Definition qstring.h:160
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
bool isLower() const
Returns true if the string is lowercase, that is, it's identical to its toLower() folding.
Definition qstring.cpp:5429
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
@ SectionCaseInsensitiveSeps
Definition qstring.h:324
@ SectionIncludeLeadingSep
Definition qstring.h:322
@ SectionSkipEmpty
Definition qstring.h:321
@ SectionIncludeTrailingSep
Definition qstring.h:323
void swap(QString &other) noexcept
Definition qstring.h:181
QString section(QChar sep, qsizetype start, qsizetype end=-1, SectionFlags flags=SectionDefault) const
This function returns a section of the string.
Definition qstring.h:1139
static QString fromRawData(const QChar *, qsizetype size)
Constructs a QString that uses the first size Unicode characters in the array unicode.
Definition qstring.cpp:9242
constexpr QString() noexcept
Constructs a null string.
Definition qstring.h:1170
qsizetype capacity() const
Returns the maximum number of characters that can be stored in the string without forcing a reallocat...
Definition qstring.h:1111
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last character in the ...
Definition qstring.h:1205
QString leftJustified(qsizetype width, QChar fill=u' ', bool trunc=false) const
Returns a string of size width that contains this string padded by the fill character.
Definition qstring.cpp:6764
QString & assign(QAnyStringView s)
Definition qstring.cpp:3377
bool isUpper() const
Returns true if the string is uppercase, that is, it's identical to its toUpper() folding.
Definition qstring.cpp:5403
friend class QByteArray
Definition qstring.h:964
float toFloat(bool *ok=nullptr) const
Returns the string converted to a float value.
Definition qstring.cpp:7688
QChar front() const
Definition qstring.h:214
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6498
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3110
friend qsizetype erase(QString &s, const T &t)
Definition qstring.h:1461
DataPointer & data_ptr()
Definition qstring.h:986
QByteArray toLocal8Bit() const &
Definition qstring.h:567
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4732
static QString vasprintf(const char *format, va_list ap) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7099
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1217
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString & append(QChar c)
Definition qstring.cpp:3227
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
void squeeze()
Releases any memory not required to store the character data.
Definition qstring.h:1181
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString & setUtf16(const ushort *utf16, qsizetype size)
Resizes the string to size characters and copies unicode into the string.
Definition qstring.h:1191
int localeAwareCompare(const QString &s) const
Definition qstring.cpp:6649
bool isRightToLeft() const
Returns true if the string is read right to left.
Definition qstring.cpp:9068
QString & setNum(short, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.h:1112
QString & setRawData(const QChar *unicode, qsizetype size)
Definition qstring.cpp:9261
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
friend class QStringView
Definition qstring.h:963
const_iterator constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the st...
Definition qstring.h:1203
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7005
QString toHtmlEscaped() const
Definition qstring.cpp:9926
NormalizationForm
This enum describes the various normalized forms of Unicode text.
Definition qstring.h:546
@ NormalizationForm_KD
Definition qstring.h:549
@ NormalizationForm_C
Definition qstring.h:548
@ NormalizationForm_D
Definition qstring.h:547
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
const QChar * unicode() const
Returns a Unicode representation of the string.
Definition qstring.h:1085
QString normalized(NormalizationForm mode, QChar::UnicodeVersion version=QChar::Unicode_Unassigned) const
Returns the string in the given Unicode normalization mode, according to the given version of the Uni...
Definition qstring.cpp:8212
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2654
@ BigEndian
Definition qsysinfo.h:29
@ ByteOrder
Definition qsysinfo.h:34
T * data() noexcept
QString str
[2]
double e
QSet< QString >::iterator it
else opt state
[0]
short next
Definition keywords.cpp:445
typename C::iterator iterator
Combined button and popup list for selecting options.
static QString convertCase(T &str, QUnicodeTables::Case which)
Definition qstring.cpp:6900
static Q_NEVER_INLINE QString detachAndConvertCase(T &str, QStringIterator it, QUnicodeTables::Case which)
Definition qstring.cpp:6865
static Q_DECL_CONST_FUNCTION const Properties * qGetProp(char32_t ucs4) noexcept
static constexpr NormalizationCorrection uc_normalization_corrections[]
constexpr bool isAsciiDigit(char32_t c) noexcept
Definition qtools_p.h:67
constexpr bool isAsciiUpper(char32_t c) noexcept
Definition qtools_p.h:72
constexpr int qt_lencmp(qsizetype lhs, qsizetype rhs) noexcept
Definition qtools_p.h:109
constexpr char toAsciiLower(char ch) noexcept
Definition qtools_p.h:87
\macro QT_NAMESPACE
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
Q_CORE_EXPORT QString convertToQString(QAnyStringView s)
static constexpr bool q_points_into_range(const T *p, const T *b, const T *e, Cmp less={}) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrlen(const char16_t *str) noexcept
Definition qstring.cpp:686
Q_CORE_EXPORT QList< uint > convertToUcs4(QStringView str)
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isValidUtf16(QStringView s) noexcept
Definition qstring.cpp:915
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QByteArrayView trimmed(QByteArrayView s) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QByteArrayView haystack, QByteArrayView needle) noexcept
Q_CORE_EXPORT QByteArray convertToLocal8Bit(QStringView str)
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool equalStrings(QStringView lhs, QStringView rhs) noexcept
Definition qstring.cpp:1405
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Definition qstring.cpp:9631
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isRightToLeft(QStringView string) noexcept
Q_CORE_EXPORT QByteArray convertToLatin1(QStringView str)
Q_CORE_EXPORT QString argToQString(QStringView pattern, size_t n, const ArgBase **args)
Definition qstring.cpp:9032
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrnlen(const char16_t *str, qsizetype maxlen) noexcept
Definition qstring.cpp:701
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
qsizetype indexOf(const QList< V > &list, const U &u, qsizetype from) noexcept
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION const char16_t * qustrchr(QStringView str, char16_t ch) noexcept
Definition qstring.cpp:714
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QLatin1StringView s) noexcept
Definition qstring.cpp:860
Q_CORE_EXPORT QByteArray convertToUtf8(QStringView str)
constexpr bool isLatin1(QLatin1StringView s) noexcept
Definition qstring.h:64
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
constexpr Initialization Uninitialized
@ KeepEmptyParts
Definition qnamespace.h:126
Initialization
QString self
Definition language.cpp:57
QT_POPCOUNT_RELAXED_CONSTEXPR uint qCountLeadingZeroBits(quint32 v) noexcept
constexpr uint qCountTrailingZeroBits(quint32 v) noexcept
static jboolean copy(JNIEnv *, jobject)
const int blockSize
size_t qstrlen(const char *str)
size_t qstrnlen(const char *str, size_t maxlen)
static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, qsizetype from)
Definition qchar.cpp:1972
static auto fullConvertCase(char32_t uc, QUnicodeTables::Case which) noexcept
Definition qchar.cpp:1518
static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion version, qsizetype from)
Definition qchar.cpp:1812
static void composeHelper(QString *str, QChar::UnicodeVersion version, qsizetype from)
Definition qchar.cpp:1912
static bool normalizationQuickCheckHelper(QString *str, QString::NormalizationForm mode, qsizetype from, qsizetype *lastStable)
Definition qchar.cpp:2054
static char32_t foldCase(const char16_t *ch, const char16_t *start)
Definition qchar.cpp:1632
#define Q_UNLIKELY(x)
#define Q_NEVER_INLINE
#define Q_DECL_COLD_FUNCTION
#define Q_ALWAYS_INLINE
AudioChannelLayoutTag tag
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QT_BEGIN_NAMESPACE Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest)
Definition qendian.h:34
bool qIsFinite(qfloat16 f) noexcept
Definition qfloat16.h:239
QString qdtoBasicLatin(double d, QLocaleData::DoubleForm form, int precision, bool uppercase)
QSimpleParsedNumber< qulonglong > qstrntoull(const char *begin, qsizetype size, int base)
QSimpleParsedNumber< double > qt_asciiToDouble(const char *num, qsizetype numLen, StrayCharacterMode strayCharMode)
QString qulltoBasicLatin(qulonglong number, int base, bool negative)
#define qWarning
Definition qlogging.h:162
return ret
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLenum src
GLenum GLuint buffer
GLint GLsizei width
GLint left
GLenum GLenum dst
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint GLsizei GLsizei GLenum format
GLsizei GLenum const void * indices
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLboolean reset
GLuint res
const GLubyte * c
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint in
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLuint GLenum option
GLuint num
GLubyte * pattern
GLenum GLenum GLenum input
GLenum GLint GLint * precision
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_DECL_COLD_FUNCTION void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *where)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
static constexpr QChar sep
static const uint64_t qCompilerCpuFeatures
Definition qsimd_p.h:322
SSL_CTX int(*) void arg)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args)
Definition qstring.cpp:8989
static bool isAscii_helper(const char16_t *&ptr, const char16_t *end)
Definition qstring.cpp:868
static Int toIntegral(QStringView string, bool *ok, int base)
Definition qstring.cpp:7380
void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length)
Definition qstring.cpp:1193
static void append_utf8(QString &qs, const char *cs, qsizetype len)
Definition qstring.cpp:7014
#define ATTRIBUTE_NO_SANITIZE
Definition qstring.cpp:395
bool qt_is_ascii(const char *&ptr, const char *end) noexcept
Definition qstring.cpp:796
QDataStream & operator<<(QDataStream &out, const QString &str)
Definition qstring.cpp:9318
static int ucstrcmp(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
Definition qstring.cpp:1374
static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs)
Definition qstring.cpp:3464
Q_ALWAYS_INLINE QString to_string(QLatin1StringView s) noexcept
Definition qstring.cpp:8985
static bool needsReallocate(const QString &str, qsizetype newSize)
Definition qstring.cpp:2617
static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, QStringView after)
Definition qstring.cpp:3729
static int qArgDigitValue(QChar ch) noexcept
Definition qstring.cpp:1633
static void replace_with_copy(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, QStringView after)
Definition qstring.cpp:3661
#define REHASH(a)
Definition qstring.cpp:69
static int ucstrncmp(const char16_t *a, const char16_t *b, size_t l)
Definition qstring.cpp:1286
static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
Definition qstring.cpp:1361
static QByteArray qt_convert_to_latin1(QStringView string)
Definition qstring.cpp:5482
static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, QStringView after)
Definition qstring.cpp:3684
static QList< uint > qt_convert_to_ucs4(QStringView string)
Definition qstring.cpp:5667
qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs)
static QByteArray qt_convert_to_local_8bit(QStringView string)
Definition qstring.cpp:5574
static LengthMod parse_length_modifier(const char *&c) noexcept
Definition qstring.cpp:7070
static ArgEscapeData findArgEscapes(QStringView s)
Definition qstring.cpp:8257
static QByteArray qt_convert_to_utf8(QStringView str)
Definition qstring.cpp:5620
static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype length)
Definition qstring.cpp:1014
LengthMod
Definition qstring.cpp:7059
@ lm_none
Definition qstring.cpp:7059
@ lm_l
Definition qstring.cpp:7059
@ lm_hh
Definition qstring.cpp:7059
@ lm_j
Definition qstring.cpp:7059
@ lm_L
Definition qstring.cpp:7059
@ lm_h
Definition qstring.cpp:7059
@ lm_z
Definition qstring.cpp:7059
@ lm_ll
Definition qstring.cpp:7059
@ lm_t
Definition qstring.cpp:7059
static void insert_helper(QString &str, qsizetype i, const T &toInsert)
Definition qstring.cpp:2947
static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar, qsizetype rSize)
Definition qstring.cpp:1387
static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetype field_width, QStringView arg, QStringView larg, QChar fillChar)
Definition qstring.cpp:8333
static QVarLengthArray< char16_t > qt_from_latin1_to_qvla(QLatin1StringView str)
Definition qstring.cpp:1005
static Q_NEVER_INLINE int ucstricmp8(const char *utf8, const char *utf8end, const QChar *utf16, const QChar *utf16end)
Definition qstring.cpp:1249
void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, qsizetype from)
Definition qstring.cpp:8147
static uint parse_flag_characters(const char *&c) noexcept
Definition qstring.cpp:7022
#define CSTR_LESS_THAN
Definition qstring.cpp:6629
static Q_NEVER_INLINE int ucstricmp(qsizetype alen, const char16_t *a, qsizetype blen, const char16_t *b)
Definition qstring.cpp:1204
#define CSTR_GREATER_THAN
Definition qstring.cpp:6631
void qt_to_latin1_unchecked(uchar *dst, const char16_t *src, qsizetype length)
Definition qstring.cpp:1198
static char16_t to_unicode(const QChar c)
Definition qstring.cpp:8816
Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept
Definition qstring.cpp:930
QDataStream & operator>>(QDataStream &in, QString &str)
Definition qstring.cpp:9350
static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber=999)
Definition qstring.cpp:8820
static bool can_consume(const char *&c, char ch) noexcept
Definition qstring.cpp:7061
static int parse_field_width(const char *&c, qsizetype size)
Definition qstring.cpp:7042
#define qUtf16Printable(string)
Definition qstring.h:1403
@ DetectEndianness
QBasicUtf8StringView< false > QUtf8StringView
Definition qstringfwd.h:46
QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
#define s2
char Char
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
@ Q_PRIMITIVE_TYPE
Definition qtypeinfo.h:144
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:145
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:163
unsigned int quint32
Definition qtypes.h:45
unsigned char uchar
Definition qtypes.h:27
unsigned short quint16
Definition qtypes.h:43
size_t quintptr
Definition qtypes.h:72
unsigned long ulong
Definition qtypes.h:30
ptrdiff_t qptrdiff
Definition qtypes.h:69
quint64 qulonglong
Definition qtypes.h:59
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned short ushort
Definition qtypes.h:28
unsigned char quint8
Definition qtypes.h:41
qint64 qlonglong
Definition qtypes.h:58
static QString escape(const QString &input)
QT_BEGIN_NAMESPACE typedef uchar * output
QList< int > list
[14]
Q_CHECK_PTR(a=new int[80])
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QMimeDatabase db
[0]
static const auto matcher
[0]
ba fill(true)
list lastIndexOf("B")
list indexOf("B")
QSharedPointer< T > other(t)
[5]
dialog exec()
QAction * at
QQuickView * view
[0]
QJSValueList args
qsizetype occurrences
Definition qstring.cpp:8251
qsizetype escape_len
Definition qstring.cpp:8254
qsizetype locale_occurrences
Definition qstring.cpp:8252
static void appendLatin1To(QLatin1StringView in, QChar *out) noexcept
void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, const T **data, QArrayDataPointer *old)
bool isShared() const noexcept
qsizetype freeSpaceAtBegin() const noexcept
bool needsDetach() const noexcept
qsizetype allocatedCapacity() noexcept
void setBegin(T *begin) noexcept
qsizetype constAllocatedCapacity() const noexcept
void clear() noexcept(std::is_nothrow_destructible< T >::value)
static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
bool isMutable() const noexcept
static Q_NODISCARD_CTOR QArrayDataPointer fromRawData(const char16_t *rawData, qsizetype length) noexcept
@ GrowsAtBeginning
Definition qarraydata.h:25
\inmodule QtCore \reentrant
Definition qchar.h:17
constexpr char16_t unicode() const noexcept
Converts a Latin-1 character to an 16-bit-encoded Unicode representation of the character.
Definition qchar.h:21
static char16_t * convertToUnicode(char16_t *dst, QLatin1StringView in) noexcept
Definition qstring.cpp:5526
static char * convertFromUnicode(char *out, QStringView in, QStringConverter::State *state) noexcept
static quint64 bytearrayToUnsLongLong(QByteArrayView num, int base, bool *ok)
Definition qlocale.cpp:4361
static float convertDoubleToFloat(double d, bool *ok)
Definition qlocale_p.h:283
QString doubleToString(double d, int precision=-1, DoubleForm form=DFSignificantDigits, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:3546
static const QLocaleData * c()
Definition qlocale.cpp:832
@ BlankBeforePositive
Definition qlocale_p.h:237
@ AddTrailingZeroes
Definition qlocale_p.h:234
QString longLongToString(qint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:3785
@ DFSignificantDigits
Definition qlocale_p.h:228
static Q_CORE_EXPORT qint64 bytearrayToLongLong(QByteArrayView num, int base, bool *ok)
Definition qlocale.cpp:4352
QString unsLongLongToString(quint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition qlocale.cpp:3800
static StringType trimmed_helper(StringType &str)
static void trimmed_helper_positions(const Char *&begin, const Char *&end)
static StringType simplified_helper(StringType &str)
static QPair< QTypedArrayData *, char16_t * > allocate(qsizetype capacity, AllocationOption option=QArrayData::KeepSize)
Definition qarraydata.h:101
static QChar * convertToUnicode(QChar *out, QByteArrayView, QStringConverter::State *state, DataEndianness endian)
static Q_CORE_EXPORT QByteArray convertFromUnicode(QStringView in)
static int compareUtf8(QByteArrayView utf8, QStringView utf16, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
static QChar * convertToUnicode(QChar *buffer, QByteArrayView in) noexcept
static int difference(char lhs, char rhs)
void growAppend(const T *b, const T *e)
void copyAppend(const T *b, const T *e)
void erase(T *b, qsizetype n)