QtBase  v6.3.1
qstring.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Copyright (C) 2022 Intel Corporation.
5 ** Copyright (C) 2019 Mail.ru Group.
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtCore module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qstringlist.h"
43 #if QT_CONFIG(regularexpression)
44 #include "qregularexpression.h"
45 #endif
46 #include "qunicodetables_p.h"
47 #include <private/qstringconverter_p.h>
48 #include "qlocale_tools_p.h"
49 #include "private/qsimd_p.h"
50 #include <qnumeric.h>
51 #include <qdatastream.h>
52 #include <qlist.h>
53 #include "qlocale.h"
54 #include "qlocale_p.h"
55 #include "qstringbuilder.h"
56 #include "qstringmatcher.h"
57 #include "qvarlengtharray.h"
58 #include "qdebug.h"
59 #include "qendian.h"
60 #include "qcollator.h"
61 
62 #ifdef Q_OS_MAC
63 #include <private/qcore_mac_p.h>
64 #endif
65 
66 #include <private/qfunctions_p.h>
67 
68 #include <limits.h>
69 #include <string.h>
70 #include <stdlib.h>
71 #include <stdio.h>
72 #include <stdarg.h>
73 #include <wchar.h>
74 
75 #include "qchar.cpp"
76 #include "qstringmatcher.cpp"
77 #include "qstringiterator_p.h"
78 #include "qstringalgorithms_p.h"
79 #include "qthreadstorage.h"
80 
81 #include "qbytearraymatcher.h" // Helper for comparison of QLatin1String
82 
83 #include <algorithm>
84 #include <functional>
85 
86 #ifdef Q_OS_WIN
87 # include <qt_windows.h>
88 #endif
89 
90 #ifdef truncate
91 # undef truncate
92 #endif
93 
94 #ifndef LLONG_MAX
95 #define LLONG_MAX qint64_C(9223372036854775807)
96 #endif
97 #ifndef LLONG_MIN
98 #define LLONG_MIN (-LLONG_MAX - qint64_C(1))
99 #endif
100 #ifndef ULLONG_MAX
101 #define ULLONG_MAX quint64_C(18446744073709551615)
102 #endif
103 
104 #define IS_RAW_DATA(d) ((d.d)->flags & QArrayData::RawDataType)
105 #define REHASH(a) \
106  if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
107  hashHaystack -= std::size_t(a) << sl_minus_1; \
108  hashHaystack <<= 1
109 
111 
112 const char16_t QString::_empty = 0;
113 
114 // in qstringmatcher.cpp
116 
117 namespace {
118 inline bool qIsUpper(char ch)
119 {
120  return ch >= 'A' && ch <= 'Z';
121 }
122 
123 inline bool qIsDigit(char ch)
124 {
125  return ch >= '0' && ch <= '9';
126 }
127 
128 inline char qToLower(char ch)
129 {
130  if (ch >= 'A' && ch <= 'Z')
131  return ch - 'A' + 'a';
132  else
133  return ch;
134 }
135 template <typename Pointer>
136 char32_t foldCaseHelper(Pointer ch, Pointer start) = delete;
137 
138 template <>
139 char32_t foldCaseHelper<const QChar*>(const QChar* ch, const QChar* start)
140 {
141  return foldCase(reinterpret_cast<const char16_t*>(ch),
142  reinterpret_cast<const char16_t*>(start));
143 }
144 
145 template <>
146 char32_t foldCaseHelper<const char*>(const char* ch, const char*)
147 {
148  return foldCase(char16_t(uchar(*ch)));
149 }
150 
151 template <typename T>
152 char16_t valueTypeToUtf16(T t) = delete;
153 
154 template <>
155 char16_t valueTypeToUtf16<QChar>(QChar t)
156 {
157  return t.unicode();
158 }
159 
160 template <>
161 char16_t valueTypeToUtf16<char>(char t)
162 {
163  return char16_t{uchar(t)};
164 }
165 
174 static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept
175 {
176  if (-from > str.size())
177  return -1;
178  if (from < 0)
179  from = qMax(from + str.size(), qsizetype(0));
180  if (from < str.size()) {
181  const char16_t *s = str.utf16();
182  char16_t c = ch.unicode();
183  const char16_t *n = s + from;
184  const char16_t *e = s + str.size();
185  if (cs == Qt::CaseSensitive) {
187  if (n != e)
188  return n - s;
189  } else {
190  c = foldCase(c);
191  --n;
192  while (++n != e)
193  if (foldCase(*n) == c)
194  return n - s;
195  }
196  }
197  return -1;
198 }
199 
200 template <typename Haystack>
201 static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
202  qsizetype from, Qt::CaseSensitivity cs) noexcept
203 {
204  if (haystack.size() == 0)
205  return -1;
206  if (from < 0)
207  from += haystack.size();
208  else if (std::size_t(from) > std::size_t(haystack.size()))
209  from = haystack.size() - 1;
210  if (from >= 0) {
211  char16_t c = needle.unicode();
212  const auto b = haystack.data();
213  auto n = b + from;
214  if (cs == Qt::CaseSensitive) {
215  for (; n >= b; --n)
216  if (valueTypeToUtf16(*n) == c)
217  return n - b;
218  } else {
219  c = foldCase(c);
220  for (; n >= b; --n)
221  if (foldCase(valueTypeToUtf16(*n)) == c)
222  return n - b;
223  }
224  }
225  return -1;
226 }
227 template <> qsizetype
228 qLastIndexOf(QString, QChar, qsizetype, Qt::CaseSensitivity) noexcept = delete; // unwanted, would detach
229 
230 template<typename Haystack, typename Needle>
231 static qsizetype qLastIndexOf(Haystack haystack0, qsizetype from,
232  Needle needle0, Qt::CaseSensitivity cs) noexcept
233 {
234  const qsizetype sl = needle0.size();
235  if (sl == 1)
236  return qLastIndexOf(haystack0, needle0.front(), from, cs);
237 
238  const qsizetype l = haystack0.size();
239  if (from < 0)
240  from += l;
241  if (from == l && sl == 0)
242  return from;
243  const qsizetype delta = l - sl;
244  if (std::size_t(from) > std::size_t(l) || delta < 0)
245  return -1;
246  if (from > delta)
247  from = delta;
248 
249  auto sv = [sl](const typename Haystack::value_type *v) { return Haystack(v, sl); };
250 
251  auto haystack = haystack0.data();
252  const auto needle = needle0.data();
253  const auto *end = haystack;
254  haystack += from;
255  const std::size_t sl_minus_1 = sl ? sl - 1 : 0;
256  const auto *n = needle + sl_minus_1;
257  const auto *h = haystack + sl_minus_1;
258  std::size_t hashNeedle = 0, hashHaystack = 0;
259 
260  if (cs == Qt::CaseSensitive) {
261  for (qsizetype idx = 0; idx < sl; ++idx) {
262  hashNeedle = (hashNeedle << 1) + valueTypeToUtf16(*(n - idx));
263  hashHaystack = (hashHaystack << 1) + valueTypeToUtf16(*(h - idx));
264  }
265  hashHaystack -= valueTypeToUtf16(*haystack);
266 
267  while (haystack >= end) {
268  hashHaystack += valueTypeToUtf16(*haystack);
269  if (hashHaystack == hashNeedle
270  && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
271  return haystack - end;
272  --haystack;
273  REHASH(valueTypeToUtf16(haystack[sl]));
274  }
275  } else {
276  for (qsizetype idx = 0; idx < sl; ++idx) {
277  hashNeedle = (hashNeedle << 1) + foldCaseHelper(n - idx, needle);
278  hashHaystack = (hashHaystack << 1) + foldCaseHelper(h - idx, end);
279  }
280  hashHaystack -= foldCaseHelper(haystack, end);
281 
282  while (haystack >= end) {
283  hashHaystack += foldCaseHelper(haystack, end);
284  if (hashHaystack == hashNeedle
285  && QtPrivate::compareStrings(sv(haystack), needle0, Qt::CaseInsensitive) == 0)
286  return haystack - end;
287  --haystack;
288  REHASH(foldCaseHelper(haystack + sl, end));
289  }
290  }
291  return -1;
292 }
293 } // unnamed namespace
294 
295 /*
296  * Note on the use of SIMD in qstring.cpp:
297  *
298  * Several operations with strings are improved with the use of SIMD code,
299  * since they are repetitive. For MIPS, we have hand-written assembly code
300  * outside of qstring.cpp targeting MIPS DSP and MIPS DSPr2. For ARM and for
301  * x86, we can only use intrinsics and therefore everything is contained in
302  * qstring.cpp. We need to use intrinsics only for those platforms due to the
303  * different compilers and toolchains used, which have different syntax for
304  * assembly sources.
305  *
306  * ** SSE notes: **
307  *
308  * Whenever multiple alternatives are equivalent or near so, we prefer the one
309  * using instructions from SSE2, since SSE2 is guaranteed to be enabled for all
310  * 64-bit builds and we enable it for 32-bit builds by default. Use of higher
311  * SSE versions should be done when there is a clear performance benefit and
312  * requires fallback code to SSE2, if it exists.
313  *
314  * Performance measurement in the past shows that most strings are short in
315  * size and, therefore, do not benefit from alignment prologues. That is,
316  * trying to find a 16-byte-aligned boundary to operate on is often more
317  * expensive than executing the unaligned operation directly. In addition, note
318  * that the QString private data is designed so that the data is stored on
319  * 16-byte boundaries if the system malloc() returns 16-byte aligned pointers
320  * on its own (64-bit glibc on Linux does; 32-bit glibc on Linux returns them
321  * 50% of the time), so skipping the alignment prologue is actually optimizing
322  * for the common case.
323  */
324 
325 #if defined(__mips_dsp)
326 // From qstring_mips_dsp_asm.S
327 extern "C" void qt_fromlatin1_mips_asm_unroll4 (char16_t*, const char*, uint);
328 extern "C" void qt_fromlatin1_mips_asm_unroll8 (char16_t*, const char*, uint);
329 extern "C" void qt_toLatin1_mips_dsp_asm(uchar *dst, const char16_t *src, int length);
330 #endif
331 
332 static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
333 static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
334 static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
335 static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
336 static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs);
337 static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
338 
339 #if defined(__SSE2__) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
340 # if defined(__SANITIZE_ADDRESS__) && Q_CC_GNU < 800 && !defined(Q_CC_CLANG)
341 # warning "The __attribute__ on below will likely cause a build failure with your GCC version. Your choices are:"
342 # warning "1) disable ASan;"
343 # warning "2) disable the optimized code in qustrlen (change __SSE2__ to anything else);"
344 # warning "3) upgrade your compiler (preferred)."
345 # endif
346 
347 // We may overrun the buffer, but that's a false positive:
348 // this won't crash nor produce incorrect results
349 __attribute__((__no_sanitize_address__))
350 #endif
351 qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
352 {
353  qsizetype result = 0;
354 
355 #if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
356  // find the 16-byte alignment immediately prior or equal to str
357  quintptr misalignment = quintptr(str) & 0xf;
358  Q_ASSERT((misalignment & 1) == 0);
359  const char16_t *ptr = str - (misalignment / 2);
360 
361  // load 16 bytes and see if we have a null
362  // (aligned loads can never segfault)
363  const __m128i zeroes = _mm_setzero_si128();
364  __m128i data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr));
365  __m128i comparison = _mm_cmpeq_epi16(data, zeroes);
366  quint32 mask = _mm_movemask_epi8(comparison);
367 
368  // ignore the result prior to the beginning of str
369  mask >>= misalignment;
370 
371  // Have we found something in the first block? Need to handle it now
372  // because of the left shift above.
373  if (mask)
374  return qCountTrailingZeroBits(quint32(mask)) / 2;
375 
376  do {
377  ptr += 8;
378  data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr));
379 
380  comparison = _mm_cmpeq_epi16(data, zeroes);
381  mask = _mm_movemask_epi8(comparison);
382  } while (mask == 0);
383 
384  // found a null
386  return ptr - str + idx / 2;
387 #endif
388 
389  if (sizeof(wchar_t) == sizeof(char16_t))
390  return wcslen(reinterpret_cast<const wchar_t *>(str));
391 
392  while (*str++)
393  ++result;
394  return result;
395 }
396 
397 #if !defined(__OPTIMIZE_SIZE__)
398 namespace {
399 template <uint MaxCount> struct UnrollTailLoop
400 {
401  template <typename RetType, typename Functor1, typename Functor2, typename Number>
402  static inline RetType exec(Number count, RetType returnIfExited, Functor1 loopCheck, Functor2 returnIfFailed, Number i = 0)
403  {
404  /* equivalent to:
405  * while (count--) {
406  * if (loopCheck(i))
407  * return returnIfFailed(i);
408  * }
409  * return returnIfExited;
410  */
411 
412  if (!count)
413  return returnIfExited;
414 
415  bool check = loopCheck(i);
416  if (check)
417  return returnIfFailed(i);
418 
419  return UnrollTailLoop<MaxCount - 1>::exec(count - 1, returnIfExited, loopCheck, returnIfFailed, i + 1);
420  }
421 
422  template <typename Functor, typename Number>
423  static inline void exec(Number count, Functor code)
424  {
425  /* equivalent to:
426  * for (Number i = 0; i < count; ++i)
427  * code(i);
428  */
429  exec(count, 0, [=](Number i) -> bool { code(i); return false; }, [](Number) { return 0; });
430  }
431 };
432 template <> template <typename RetType, typename Functor1, typename Functor2, typename Number>
433 inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, Functor2, Number)
434 {
435  return returnIfExited;
436 }
437 }
438 #endif
439 
448 const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
449 {
450  const char16_t *n = str.utf16();
451  const char16_t *e = n + str.size();
452 
453 #ifdef __SSE2__
454  bool loops = true;
455  // Using the PMOVMSKB instruction, we get two bits for each character
456  // we compare.
457 # if defined(__AVX2__) && !defined(__OPTIMIZE_SIZE__)
458  // we're going to read n[0..15] (32 bytes)
459  __m256i mch256 = _mm256_set1_epi32(c | (c << 16));
460  for (const char16_t *next = n + 16; next <= e; n = next, next += 16) {
461  __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n));
462  __m256i result = _mm256_cmpeq_epi16(data, mch256);
463  uint mask = uint(_mm256_movemask_epi8(result));
464  if (mask) {
466  return n + idx / 2;
467  }
468  }
469  loops = false;
470  __m128i mch = _mm256_castsi256_si128(mch256);
471 # else
472  __m128i mch = _mm_set1_epi32(c | (c << 16));
473 # endif
474 
475  auto hasMatch = [mch, &n](__m128i data, ushort validityMask) {
476  __m128i result = _mm_cmpeq_epi16(data, mch);
477  uint mask = uint(_mm_movemask_epi8(result));
478  if ((mask & validityMask) == 0)
479  return false;
481  n += idx / 2;
482  return true;
483  };
484 
485  // we're going to read n[0..7] (16 bytes)
486  for (const char16_t *next = n + 8; next <= e; n = next, next += 8) {
487  __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(n));
488  if (hasMatch(data, 0xffff))
489  return n;
490 
491  if (!loops) {
492  n += 8;
493  break;
494  }
495  }
496 
497 # if !defined(__OPTIMIZE_SIZE__)
498  // we're going to read n[0..3] (8 bytes)
499  if (e - n > 3) {
500  __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(n));
501  if (hasMatch(data, 0xff))
502  return n;
503 
504  n += 4;
505  }
506 
507  return UnrollTailLoop<3>::exec(e - n, e,
508  [=](int i) { return n[i] == c; },
509  [=](int i) { return n + i; });
510 # endif
511 #elif defined(__ARM_NEON__)
512  const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
513  const uint16x8_t ch_vec = vdupq_n_u16(c);
514  for (const char16_t *next = n + 8; next <= e; n = next, next += 8) {
515  uint16x8_t data = vld1q_u16(reinterpret_cast<const uint16_t *>(n));
516  uint mask = vaddvq_u16(vandq_u16(vceqq_u16(data, ch_vec), vmask));
517  if (ushort(mask)) {
518  // found a match
519  return n + qCountTrailingZeroBits(mask);
520  }
521  }
522 #endif // aarch64
523 
524  --n;
525  while (++n != e)
526  if (*n == c)
527  return n;
528 
529  return n;
530 }
531 
532 #ifdef __SSE2__
533 // Scans from \a ptr to \a end until \a maskval is non-zero. Returns true if
534 // the no non-zero was found. Returns false and updates \a ptr to point to the
535 // first 16-bit word that has any bit set (note: if the input is 8-bit, \a ptr
536 // may be updated to one byte short).
537 static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
538 {
539  auto updatePtr = [&](uint result) {
540  // found a character matching the mask
542  ptr += idx;
543  return false;
544  };
545 
546 # if defined(__SSE4_1__)
547  __m128i mask;
548  auto updatePtrSimd = [&](__m128i data) {
549  __m128i masked = _mm_and_si128(mask, data);
550  __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
551  uint result = _mm_movemask_epi8(comparison);
552  return updatePtr(result);
553  };
554 
555 # if defined(__AVX2__)
556  // AVX2 implementation: test 32 bytes at a time
557  const __m256i mask256 = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(maskval));
558  while (ptr + 32 <= end) {
559  __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
560  if (!_mm256_testz_si256(mask256, data)) {
561  // found a character matching the mask
562  __m256i masked256 = _mm256_and_si256(mask256, data);
563  __m256i comparison256 = _mm256_cmpeq_epi16(masked256, _mm256_setzero_si256());
564  return updatePtr(_mm256_movemask_epi8(comparison256));
565  }
566  ptr += 32;
567  }
568 
569  mask = _mm256_castsi256_si128(mask256);
570 # else
571  // SSE 4.1 implementation: test 32 bytes at a time (two 16-byte
572  // comparisons, unrolled)
573  mask = _mm_set1_epi32(maskval);
574  while (ptr + 32 <= end) {
575  __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
576  __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16));
577  if (!_mm_testz_si128(mask, data1))
578  return updatePtrSimd(data1);
579 
580  ptr += 16;
581  if (!_mm_testz_si128(mask, data2))
582  return updatePtrSimd(data2);
583  ptr += 16;
584  }
585 # endif
586 
587  // AVX2 and SSE4.1: final 16-byte comparison
588  if (ptr + 16 <= end) {
589  __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
590  if (!_mm_testz_si128(mask, data1))
591  return updatePtrSimd(data1);
592  ptr += 16;
593  }
594 
595  // and final 8-byte comparison
596  if (ptr + 8 <= end) {
597  __m128i data1 = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
598  if (!_mm_testz_si128(mask, data1))
599  return updatePtrSimd(data1);
600  ptr += 8;
601  }
602 
603 # else
604  // SSE2 implementation: test 16 bytes at a time.
605  const __m128i mask = _mm_set1_epi32(maskval);
606  while (ptr + 16 <= end) {
607  __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
608  __m128i masked = _mm_and_si128(mask, data);
609  __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
610  quint16 result = _mm_movemask_epi8(comparison);
611  if (result != 0xffff)
612  return updatePtr(result);
613  ptr += 16;
614  }
615 
616  // and one 8-byte comparison
617  if (ptr + 8 <= end) {
618  __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
619  __m128i masked = _mm_and_si128(mask, data);
620  __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
621  quint8 result = _mm_movemask_epi8(comparison);
622  if (result != 0xff)
623  return updatePtr(result);
624  ptr += 8;
625  }
626 # endif
627 
628  return true;
629 }
630 
631 static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr)
632 {
633  const __m128i *dataptr = static_cast<const __m128i *>(ptr);
634 #if defined(__SSE4_1__)
635  // use a MOVQ followed by PMOVZXBW
636  // if AVX2 is present, these should combine into a single VPMOVZXBW instruction
637  __m128i data = _mm_loadl_epi64(dataptr);
638  return _mm_cvtepu8_epi16(data);
639 # else
640  // use MOVQ followed by PUNPCKLBW
641  __m128i data = _mm_loadl_epi64(dataptr);
642  return _mm_unpacklo_epi8(data, _mm_setzero_si128());
643 # endif
644 }
645 #endif
646 
647 // Note: ptr on output may be off by one and point to a preceding US-ASCII
648 // character. Usually harmless.
649 bool qt_is_ascii(const char *&ptr, const char *end) noexcept
650 {
651 #if defined(__SSE2__)
652  // Testing for the high bit can be done efficiently with just PMOVMSKB
653  bool loops = true;
654 # if defined(__AVX2__)
655  while (ptr + 32 <= end) {
656  __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
657  quint32 mask = _mm256_movemask_epi8(data);
658  if (mask) {
660  ptr += idx;
661  return false;
662  }
663  ptr += 32;
664  }
665  loops = false;
666 # endif
667 
668  while (ptr + 16 <= end) {
669  __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
670  quint32 mask = _mm_movemask_epi8(data);
671  if (mask) {
673  ptr += idx;
674  return false;
675  }
676  ptr += 16;
677 
678  if (!loops)
679  break;
680  }
681  if (ptr + 8 <= end) {
682  __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(ptr));
683  quint8 mask = _mm_movemask_epi8(data);
684  if (mask) {
686  ptr += idx;
687  return false;
688  }
689  ptr += 8;
690  }
691 #endif
692 
693  while (ptr + 4 <= end) {
694  quint32 data = qFromUnaligned<quint32>(ptr);
695  if (data &= 0x80808080U) {
699  ptr += idx / 8;
700  return false;
701  }
702  ptr += 4;
703  }
704 
705  while (ptr != end) {
706  if (quint8(*ptr) & 0x80)
707  return false;
708  ++ptr;
709  }
710  return true;
711 }
712 
714 {
715  const char *ptr = s.begin();
716  const char *end = s.end();
717 
718  return qt_is_ascii(ptr, end);
719 }
720 
721 static bool isAscii_helper(const char16_t *&ptr, const char16_t *end)
722 {
723 #ifdef __SSE2__
724  const char *ptr8 = reinterpret_cast<const char *>(ptr);
725  const char *end8 = reinterpret_cast<const char *>(end);
726  bool ok = simdTestMask(ptr8, end8, 0xff80ff80);
727  ptr = reinterpret_cast<const char16_t *>(ptr8);
728  if (!ok)
729  return false;
730 #endif
731 
732  while (ptr != end) {
733  if (*ptr & 0xff80)
734  return false;
735  ++ptr;
736  }
737  return true;
738 }
739 
741 {
742  const char16_t *ptr = s.utf16();
743  const char16_t *end = ptr + s.size();
744 
745  return isAscii_helper(ptr, end);
746 }
747 
749 {
750  const char16_t *ptr = s.utf16();
751  const char16_t *end = ptr + s.size();
752 
753 #ifdef __SSE2__
754  const char *ptr8 = reinterpret_cast<const char *>(ptr);
755  const char *end8 = reinterpret_cast<const char *>(end);
756  if (!simdTestMask(ptr8, end8, 0xff00ff00))
757  return false;
758  ptr = reinterpret_cast<const char16_t *>(ptr8);
759 #endif
760 
761  while (ptr != end) {
762  if (*ptr++ > 0xff)
763  return false;
764  }
765  return true;
766 }
767 
769 {
770  constexpr char32_t InvalidCodePoint = UINT_MAX;
771 
773  while (i.hasNext()) {
774  const char32_t c = i.next(InvalidCodePoint);
775  if (c == InvalidCodePoint)
776  return false;
777  }
778 
779  return true;
780 }
781 
782 // conversion between Latin 1 and UTF-16
783 Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept
784 {
785  /* SIMD:
786  * Unpacking with SSE has been shown to improve performance on recent CPUs
787  * The same method gives no improvement with NEON. On Aarch64, clang will do the vectorization
788  * itself in exactly the same way as one would do it with intrinsics.
789  */
790 #if defined(__SSE2__)
791  const char *e = str + size;
792  qptrdiff offset = 0;
793 
794  // we're going to read str[offset..offset+15] (16 bytes)
795  for ( ; str + offset + 15 < e; offset += 16) {
796  const __m128i chunk = _mm_loadu_si128((const __m128i*)(str + offset)); // load
797 #ifdef __AVX2__
798  // zero extend to an YMM register
799  const __m256i extended = _mm256_cvtepu8_epi16(chunk);
800 
801  // store
802  _mm256_storeu_si256((__m256i*)(dst + offset), extended);
803 #else
804  const __m128i nullMask = _mm_set1_epi32(0);
805 
806  // unpack the first 8 bytes, padding with zeros
807  const __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullMask);
808  _mm_storeu_si128((__m128i*)(dst + offset), firstHalf); // store
809 
810  // unpack the last 8 bytes, padding with zeros
811  const __m128i secondHalf = _mm_unpackhi_epi8 (chunk, nullMask);
812  _mm_storeu_si128((__m128i*)(dst + offset + 8), secondHalf); // store
813 #endif
814  }
815 
816  // we're going to read str[offset..offset+7] (8 bytes)
817  if (str + offset + 7 < e) {
818  const __m128i unpacked = mm_load8_zero_extend(str + offset);
819  _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + offset), unpacked);
820  offset += 8;
821  }
822 
823  size = size % 8;
824  dst += offset;
825  str += offset;
826 # if !defined(__OPTIMIZE_SIZE__)
827  return UnrollTailLoop<7>::exec(int(size), [=](int i) { dst[i] = (uchar)str[i]; });
828 # endif
829 #endif
830 #if defined(__mips_dsp)
831  if (size > 20)
832  qt_fromlatin1_mips_asm_unroll8(dst, str, size);
833  else
834  qt_fromlatin1_mips_asm_unroll4(dst, str, size);
835 #else
836  while (size--)
837  *dst++ = (uchar)*str++;
838 #endif
839 }
840 
841 template <bool Checked>
842 static void qt_to_latin1_internal(uchar *dst, const char16_t *src, qsizetype length)
843 {
844 #if defined(__SSE2__)
845  uchar *e = dst + length;
846  qptrdiff offset = 0;
847 
848 # ifdef __AVX2__
849  const __m256i questionMark256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128('?'));
850  const __m256i outOfRange256 = _mm256_broadcastw_epi16(_mm_cvtsi32_si128(0x100));
851  const __m128i questionMark = _mm256_castsi256_si128(questionMark256);
852  const __m128i outOfRange = _mm256_castsi256_si128(outOfRange256);
853 # else
854  const __m128i questionMark = _mm_set1_epi16('?');
855  const __m128i outOfRange = _mm_set1_epi16(0x100);
856 # endif
857 
858  auto mergeQuestionMarks = [=](__m128i chunk) {
859  // SSE has no compare instruction for unsigned comparison.
860 # ifdef __SSE4_1__
861  // We use an unsigned uc = qMin(uc, 0x100) and then compare for equality.
862  chunk = _mm_min_epu16(chunk, outOfRange);
863  const __m128i offLimitMask = _mm_cmpeq_epi16(chunk, outOfRange);
864  chunk = _mm_blendv_epi8(chunk, questionMark, offLimitMask);
865 # else
866  // The variables must be shiffted + 0x8000 to be compared
867  const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000));
868  const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000));
869 
870  const __m128i signedChunk = _mm_add_epi16(chunk, signedBitOffset);
871  const __m128i offLimitMask = _mm_cmpgt_epi16(signedChunk, thresholdMask);
872 
873  // offLimitQuestionMark contains '?' for each 16 bits that was off-limit
874  // the 16 bits that were correct contains zeros
875  const __m128i offLimitQuestionMark = _mm_and_si128(offLimitMask, questionMark);
876 
877  // correctBytes contains the bytes that were in limit
878  // the 16 bits that were off limits contains zeros
879  const __m128i correctBytes = _mm_andnot_si128(offLimitMask, chunk);
880 
881  // merge offLimitQuestionMark and correctBytes to have the result
882  chunk = _mm_or_si128(correctBytes, offLimitQuestionMark);
883 
884  Q_UNUSED(outOfRange);
885 # endif
886  return chunk;
887  };
888 
889  // we're going to write to dst[offset..offset+15] (16 bytes)
890  for ( ; dst + offset + 15 < e; offset += 16) {
891 # if defined(__AVX2__)
892  __m256i chunk = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + offset));
893  if (Checked) {
894  // See mergeQuestionMarks lambda above for details
895  chunk = _mm256_min_epu16(chunk, outOfRange256);
896  const __m256i offLimitMask = _mm256_cmpeq_epi16(chunk, outOfRange256);
897  chunk = _mm256_blendv_epi8(chunk, questionMark256, offLimitMask);
898  }
899 
900  const __m128i chunk2 = _mm256_extracti128_si256(chunk, 1);
901  const __m128i chunk1 = _mm256_castsi256_si128(chunk);
902 # else
903  __m128i chunk1 = _mm_loadu_si128((const __m128i*)(src + offset)); // load
904  if (Checked)
905  chunk1 = mergeQuestionMarks(chunk1);
906 
907  __m128i chunk2 = _mm_loadu_si128((const __m128i*)(src + offset + 8)); // load
908  if (Checked)
909  chunk2 = mergeQuestionMarks(chunk2);
910 # endif
911 
912  // pack the two vector to 16 x 8bits elements
913  const __m128i result = _mm_packus_epi16(chunk1, chunk2);
914  _mm_storeu_si128((__m128i*)(dst + offset), result); // store
915  }
916 
917 # if !defined(__OPTIMIZE_SIZE__)
918  // we're going to write to dst[offset..offset+7] (8 bytes)
919  if (dst + offset + 7 < e) {
920  __m128i chunk = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + offset));
921  if (Checked)
922  chunk = mergeQuestionMarks(chunk);
923 
924  // pack, where the upper half is ignored
925  const __m128i result = _mm_packus_epi16(chunk, chunk);
926  _mm_storel_epi64(reinterpret_cast<__m128i *>(dst + offset), result);
927  offset += 8;
928  }
929 
930  // we're going to write to dst[offset..offset+3] (4 bytes)
931  if (dst + offset + 3 < e) {
932  __m128i chunk = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(src + offset));
933  if (Checked)
934  chunk = mergeQuestionMarks(chunk);
935 
936  // pack, we'll the upper three quarters
937  const __m128i result = _mm_packus_epi16(chunk, chunk);
938  qToUnaligned(_mm_cvtsi128_si32(result), dst + offset);
939  offset += 4;
940  }
941 
942  length = length % 4;
943 # else
944  length = length % 16;
945 # endif // optimize size
946 
947  // advance dst, src for tail processing
948  dst += offset;
949  src += offset;
950 
951 # if !defined(__OPTIMIZE_SIZE__)
952  return UnrollTailLoop<3>::exec(length, [=](int i) {
953  if (Checked)
954  dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i];
955  else
956  dst[i] = src[i];
957  });
958 # endif
959 #elif defined(__ARM_NEON__)
960  // Refer to the documentation of the SSE2 implementation.
961  // This uses exactly the same method as for SSE except:
962  // 1) neon has unsigned comparison
963  // 2) packing is done to 64 bits (8 x 8bits component).
964  if (length >= 16) {
965  const int chunkCount = length >> 3; // divided by 8
966  const uint16x8_t questionMark = vdupq_n_u16('?'); // set
967  const uint16x8_t thresholdMask = vdupq_n_u16(0xff); // set
968  for (int i = 0; i < chunkCount; ++i) {
969  uint16x8_t chunk = vld1q_u16((uint16_t *)src); // load
970  src += 8;
971 
972  if (Checked) {
973  const uint16x8_t offLimitMask = vcgtq_u16(chunk, thresholdMask); // chunk > thresholdMask
974  const uint16x8_t offLimitQuestionMark = vandq_u16(offLimitMask, questionMark); // offLimitMask & questionMark
975  const uint16x8_t correctBytes = vbicq_u16(chunk, offLimitMask); // !offLimitMask & chunk
976  chunk = vorrq_u16(correctBytes, offLimitQuestionMark); // correctBytes | offLimitQuestionMark
977  }
978  const uint8x8_t result = vmovn_u16(chunk); // narrowing move->packing
979  vst1_u8(dst, result); // store
980  dst += 8;
981  }
982  length = length % 8;
983  }
984 #endif
985 #if defined(__mips_dsp)
986  qt_toLatin1_mips_dsp_asm(dst, src, length);
987 #else
988  while (length--) {
989  if (Checked)
990  *dst++ = (*src>0xff) ? '?' : (uchar) *src;
991  else
992  *dst++ = *src;
993  ++src;
994  }
995 #endif
996 }
997 
998 static void qt_to_latin1(uchar *dst, const char16_t *src, qsizetype length)
999 {
1000  qt_to_latin1_internal<true>(dst, src, length);
1001 }
1002 
1004 {
1005  qt_to_latin1_internal<false>(dst, src, length);
1006 }
1007 
1008 // Unicode case-insensitive comparison
1009 static int ucstricmp(const QChar *a, const QChar *ae, const QChar *b, const QChar *be)
1010 {
1011  if (a == b)
1012  return (ae - be);
1013 
1014  const QChar *e = ae;
1015  if (be - b < ae - a)
1016  e = a + (be - b);
1017 
1018  char32_t alast = 0;
1019  char32_t blast = 0;
1020  while (a < e) {
1021 // qDebug() << Qt::hex << alast << blast;
1022 // qDebug() << Qt::hex << "*a=" << *a << "alast=" << alast << "folded=" << foldCase (*a, alast);
1023 // qDebug() << Qt::hex << "*b=" << *b << "blast=" << blast << "folded=" << foldCase (*b, blast);
1024  int diff = foldCase(a->unicode(), alast) - foldCase(b->unicode(), blast);
1025  if ((diff))
1026  return diff;
1027  ++a;
1028  ++b;
1029  }
1030  if (a == ae) {
1031  if (b == be)
1032  return 0;
1033  return -1;
1034  }
1035  return 1;
1036 }
1037 
1038 // Case-insensitive comparison between a Unicode string and a QLatin1String
1039 static int ucstricmp(const QChar *a, const QChar *ae, const char *b, const char *be)
1040 {
1041  auto e = ae;
1042  if (be - b < ae - a)
1043  e = a + (be - b);
1044 
1045  while (a < e) {
1046  int diff = foldCase(a->unicode()) - foldCase(char16_t{uchar(*b)});
1047  if ((diff))
1048  return diff;
1049  ++a;
1050  ++b;
1051  }
1052  if (a == ae) {
1053  if (b == be)
1054  return 0;
1055  return -1;
1056  }
1057  return 1;
1058 }
1059 
1060 // Case-insensitive comparison between a Unicode string and a UTF-8 string
1061 static int ucstricmp8(const char *utf8, const char *utf8end, const QChar *utf16, const QChar *utf16end)
1062 {
1063  auto src1 = reinterpret_cast<const uchar *>(utf8);
1064  auto end1 = reinterpret_cast<const uchar *>(utf8end);
1065  QStringIterator src2(utf16, utf16end);
1066 
1067  while (src1 < end1 && src2.hasNext()) {
1068  char32_t uc1 = 0;
1069  char32_t *output = &uc1;
1070  uchar b = *src1++;
1071  int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, output, src1, end1);
1072  if (res < 0) {
1073  // decoding error
1075  } else {
1076  uc1 = QChar::toCaseFolded(uc1);
1077  }
1078 
1079  char32_t uc2 = QChar::toCaseFolded(src2.next());
1080  int diff = uc1 - uc2; // can't underflow
1081  if (diff)
1082  return diff;
1083  }
1084 
1085  // the shorter string sorts first
1086  return (end1 > src1) - int(src2.hasNext());
1087 }
1088 
1089 #if defined(__mips_dsp)
1090 // From qstring_mips_dsp_asm.S
1091 extern "C" int qt_ucstrncmp_mips_dsp_asm(const char16_t *a,
1092  const char16_t *b,
1093  unsigned len);
1094 #endif
1095 
1096 // Unicode case-sensitive compare two same-sized strings
1097 static int ucstrncmp(const QChar *a, const QChar *b, size_t l)
1098 {
1099 #ifdef __OPTIMIZE_SIZE__
1100  const QChar *end = a + l;
1101  while (a < end) {
1102  if (int diff = (int)a->unicode() - (int)b->unicode())
1103  return diff;
1104  ++a;
1105  ++b;
1106  }
1107  return 0;
1108 #else
1109 #if defined(__mips_dsp)
1110  static_assert(sizeof(uint) == sizeof(size_t));
1111  if (l >= 8) {
1112  return qt_ucstrncmp_mips_dsp_asm(reinterpret_cast<const char16_t*>(a),
1113  reinterpret_cast<const char16_t*>(b),
1114  l);
1115  }
1116 #endif // __mips_dsp
1117 #ifdef __SSE2__
1118  const QChar *end = a + l;
1119  qptrdiff offset = 0;
1120 
1121  // Using the PMOVMSKB instruction, we get two bits for each character
1122  // we compare.
1123  int retval;
1124  auto isDifferent = [a, b, &offset, &retval](__m128i a_data, __m128i b_data) {
1125  __m128i result = _mm_cmpeq_epi16(a_data, b_data);
1126  uint mask = ~uint(_mm_movemask_epi8(result));
1127  if (ushort(mask) == 0)
1128  return false;
1130  retval = a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode();
1131  return true;
1132  };
1133 
1134  // we're going to read a[0..15] and b[0..15] (32 bytes)
1135  for ( ; end - a >= offset + 16; offset += 16) {
1136 #ifdef __AVX2__
1137  __m256i a_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(a + offset));
1138  __m256i b_data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(b + offset));
1139  __m256i result = _mm256_cmpeq_epi16(a_data, b_data);
1140  uint mask = _mm256_movemask_epi8(result);
1141 #else
1142  __m128i a_data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset));
1143  __m128i a_data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset + 8));
1144  __m128i b_data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
1145  __m128i b_data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset + 8));
1146  __m128i result1 = _mm_cmpeq_epi16(a_data1, b_data1);
1147  __m128i result2 = _mm_cmpeq_epi16(a_data2, b_data2);
1148  uint mask = _mm_movemask_epi8(result1) | (_mm_movemask_epi8(result2) << 16);
1149 #endif
1150  mask = ~mask;
1151  if (mask) {
1152  // found a different character
1154  return a[offset + idx / 2].unicode() - b[offset + idx / 2].unicode();
1155  }
1156  }
1157 
1158  // we're going to read a[0..7] and b[0..7] (16 bytes)
1159  if (end - a >= offset + 8) {
1160  __m128i a_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(a + offset));
1161  __m128i b_data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(b + offset));
1162  if (isDifferent(a_data, b_data))
1163  return retval;
1164 
1165  offset += 8;
1166  }
1167 
1168  // we're going to read a[0..3] and b[0..3] (8 bytes)
1169  if (end - a >= offset + 4) {
1170  __m128i a_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(a + offset));
1171  __m128i b_data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(b + offset));
1172  if (isDifferent(a_data, b_data))
1173  return retval;
1174 
1175  offset += 4;
1176  }
1177 
1178  // reset l
1179  l &= 3;
1180 
1181  const auto lambda = [=](size_t i) -> int {
1182  return a[offset + i].unicode() - b[offset + i].unicode();
1183  };
1184  return UnrollTailLoop<3>::exec(l, 0, lambda, lambda);
1185 #endif
1186 #ifdef __ARM_NEON__
1187  if (l >= 8) {
1188  const QChar *end = a + l;
1189  const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
1190  while (end - a > 7) {
1191  uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
1192  uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));
1193 
1194  uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
1195  if (r) {
1196  // found a different QChar
1198  return (int)a[idx].unicode() - (int)b[idx].unicode();
1199  }
1200  a += 8;
1201  b += 8;
1202  }
1203  l &= 7;
1204  }
1205  const auto lambda = [=](size_t i) -> int {
1206  return a[i].unicode() - b[i].unicode();
1207  };
1208  return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
1209 #endif // __ARM_NEON__
1210  if (!l)
1211  return 0;
1212 
1213  // check alignment
1214  if ((reinterpret_cast<quintptr>(a) & 2) == (reinterpret_cast<quintptr>(b) & 2)) {
1215  // both addresses have the same alignment
1216  if (reinterpret_cast<quintptr>(a) & 2) {
1217  // both addresses are not aligned to 4-bytes boundaries
1218  // compare the first character
1219  if (*a != *b)
1220  return a->unicode() - b->unicode();
1221  --l;
1222  ++a;
1223  ++b;
1224 
1225  // now both addresses are 4-bytes aligned
1226  }
1227 
1228  // both addresses are 4-bytes aligned
1229  // do a fast 32-bit comparison
1230  const quint32 *da = reinterpret_cast<const quint32 *>(a);
1231  const quint32 *db = reinterpret_cast<const quint32 *>(b);
1232  const quint32 *e = da + (l >> 1);
1233  for ( ; da != e; ++da, ++db) {
1234  if (*da != *db) {
1235  a = reinterpret_cast<const QChar *>(da);
1236  b = reinterpret_cast<const QChar *>(db);
1237  if (*a != *b)
1238  return a->unicode() - b->unicode();
1239  return a[1].unicode() - b[1].unicode();
1240  }
1241  }
1242 
1243  // do we have a tail?
1244  a = reinterpret_cast<const QChar *>(da);
1245  b = reinterpret_cast<const QChar *>(db);
1246  return (l & 1) ? a->unicode() - b->unicode() : 0;
1247  } else {
1248  // one of the addresses isn't 4-byte aligned but the other is
1249  const QChar *e = a + l;
1250  for ( ; a != e; ++a, ++b) {
1251  if (*a != *b)
1252  return a->unicode() - b->unicode();
1253  }
1254  }
1255  return 0;
1256 #endif
1257 }
1258 
1259 static int ucstrncmp(const QChar *a, const uchar *c, size_t l)
1260 {
1261  const char16_t *uc = reinterpret_cast<const char16_t *>(a);
1262  const char16_t *e = uc + l;
1263 
1264 #ifdef __SSE2__
1265  __m128i nullmask = _mm_setzero_si128();
1266  qptrdiff offset = 0;
1267 
1268 # if !defined(__OPTIMIZE_SIZE__)
1269  // Using the PMOVMSKB instruction, we get two bits for each character
1270  // we compare.
1271  int retval;
1272  auto isDifferent = [uc, c, &offset, &retval](__m128i a_data, __m128i b_data) {
1273  __m128i result = _mm_cmpeq_epi16(a_data, b_data);
1274  uint mask = ~uint(_mm_movemask_epi8(result));
1275  if (ushort(mask) == 0)
1276  return false;
1278  retval = uc[offset + idx / 2] - c[offset + idx / 2];
1279  return true;
1280  };
1281 # endif
1282 
1283  // we're going to read uc[offset..offset+15] (32 bytes)
1284  // and c[offset..offset+15] (16 bytes)
1285  for ( ; uc + offset + 15 < e; offset += 16) {
1286  // similar to fromLatin1_helper:
1287  // load 16 bytes of Latin 1 data
1288  __m128i chunk = _mm_loadu_si128((const __m128i*)(c + offset));
1289 
1290 # ifdef __AVX2__
1291  // expand Latin 1 data via zero extension
1292  __m256i ldata = _mm256_cvtepu8_epi16(chunk);
1293 
1294  // load UTF-16 data and compare
1295  __m256i ucdata = _mm256_loadu_si256((const __m256i*)(uc + offset));
1296  __m256i result = _mm256_cmpeq_epi16(ldata, ucdata);
1297 
1298  uint mask = ~_mm256_movemask_epi8(result);
1299 # else
1300  // expand via unpacking
1301  __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullmask);
1302  __m128i secondHalf = _mm_unpackhi_epi8(chunk, nullmask);
1303 
1304  // load UTF-16 data and compare
1305  __m128i ucdata1 = _mm_loadu_si128((const __m128i*)(uc + offset));
1306  __m128i ucdata2 = _mm_loadu_si128((const __m128i*)(uc + offset + 8));
1307  __m128i result1 = _mm_cmpeq_epi16(firstHalf, ucdata1);
1308  __m128i result2 = _mm_cmpeq_epi16(secondHalf, ucdata2);
1309 
1310  uint mask = ~(_mm_movemask_epi8(result1) | _mm_movemask_epi8(result2) << 16);
1311 # endif
1312  if (mask) {
1313  // found a different character
1315  return uc[offset + idx / 2] - c[offset + idx / 2];
1316  }
1317  }
1318 
1319 # if !defined(__OPTIMIZE_SIZE__)
1320  // we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes)
1321  if (uc + offset + 7 < e) {
1322  // same, but we're using an 8-byte load
1323  __m128i secondHalf = mm_load8_zero_extend(c + offset);
1324 
1325  __m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset));
1326  if (isDifferent(ucdata, secondHalf))
1327  return retval;
1328 
1329  // still matched
1330  offset += 8;
1331  }
1332 
1333  enum { MaxTailLength = 3 };
1334  // we'll read uc[offset..offset+3] (8 bytes) and c[offset..offset+3] (4 bytes)
1335  if (uc + offset + 3 < e) {
1336  __m128i chunk = _mm_cvtsi32_si128(qFromUnaligned<int>(c + offset));
1337  __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask);
1338 
1339  __m128i ucdata = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(uc + offset));
1340  if (isDifferent(ucdata, secondHalf))
1341  return retval;
1342 
1343  // still matched
1344  offset += 4;
1345  }
1346 # endif // optimize size
1347 
1348  // reset uc and c
1349  uc += offset;
1350  c += offset;
1351 
1352 # if !defined(__OPTIMIZE_SIZE__)
1353  const auto lambda = [=](size_t i) { return uc[i] - char16_t(c[i]); };
1354  return UnrollTailLoop<MaxTailLength>::exec(e - uc, 0, lambda, lambda);
1355 # endif
1356 #endif
1357 
1358  while (uc < e) {
1359  int diff = *uc - *c;
1360  if (diff)
1361  return diff;
1362  uc++, c++;
1363  }
1364 
1365  return 0;
1366 }
1367 
1368 constexpr int lencmp(qsizetype lhs, qsizetype rhs) noexcept
1369 {
1370  return lhs == rhs ? 0 :
1371  lhs > rhs ? 1 :
1372  /* else */ -1 ;
1373 }
1374 
1375 // Unicode case-sensitive comparison
1376 static int ucstrcmp(const QChar *a, size_t alen, const QChar *b, size_t blen)
1377 {
1378  if (a == b && alen == blen)
1379  return 0;
1380  const size_t l = qMin(alen, blen);
1381  int cmp = ucstrncmp(a, b, l);
1382  return cmp ? cmp : lencmp(alen, blen);
1383 }
1384 
1385 static int ucstrcmp(const QChar *a, size_t alen, const char *b, size_t blen)
1386 {
1387  const size_t l = qMin(alen, blen);
1388  const int cmp = ucstrncmp(a, reinterpret_cast<const uchar*>(b), l);
1389  return cmp ? cmp : lencmp(alen, blen);
1390 }
1391 
1392 static constexpr uchar latin1Lower[256] = {
1393  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1394  0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
1395  0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
1396  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
1397  0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
1398  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
1399  0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
1400  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
1401  0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
1402  0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
1403  0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
1404  0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
1405  // 0xd7 (multiplication sign) and 0xdf (sz ligature) complicate life
1406  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
1407  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xd7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xdf,
1408  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
1409  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
1410 };
1411 static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar, qsizetype rSize)
1412 {
1413  // We're called with QLatin1String's .data() and .size():
1414  Q_ASSERT(lSize >= 0 && rSize >= 0);
1415  if (!lSize)
1416  return rSize ? -1 : 0;
1417  if (!rSize)
1418  return 1;
1419  const qsizetype size = std::min(lSize, rSize);
1420 
1421  const uchar *lhs = reinterpret_cast<const uchar *>(lhsChar);
1422  const uchar *rhs = reinterpret_cast<const uchar *>(rhsChar);
1423  Q_ASSERT(lhs && rhs); // since both lSize and rSize are positive
1424  for (qsizetype i = 0; i < size; i++) {
1425  if (int res = latin1Lower[lhs[i]] - latin1Lower[rhs[i]])
1426  return res;
1427  }
1428  return lencmp(lSize, rSize);
1429 }
1431 {
1432  return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size()) == 0;
1433 }
1434 
1436 {
1437  return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size()) == 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  return QUtf8::compareUtf8(lhs, rhs) == 0;
1453 }
1454 
1456 {
1457  return QtPrivate::equalStrings(rhs, lhs);
1458 }
1459 
1461 {
1462  QString r = rhs.toString();
1463  return QtPrivate::equalStrings(lhs, r); // ### optimize!
1464 }
1465 
1467 {
1468  return QtPrivate::equalStrings(rhs, lhs);
1469 }
1470 
1472 {
1473  return lhs.size() == rhs.size() && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
1474 }
1475 
1477 {
1478  if (lhs.size() != rhs.size() && lhs.isUtf8() == rhs.isUtf8())
1479  return false;
1480  return lhs.visit([rhs](auto lhs) {
1481  return rhs.visit([lhs](auto rhs) {
1482  return QtPrivate::equalStrings(lhs, rhs);
1483  });
1484  });
1485 }
1486 
1504 {
1505  if (cs == Qt::CaseSensitive)
1506  return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size());
1507  return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1508 }
1509 
1528 {
1529  if (cs == Qt::CaseSensitive)
1530  return ucstrcmp(lhs.begin(), lhs.size(), rhs.begin(), rhs.size());
1531  return ucstricmp(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1532 }
1533 
1541 {
1542  return -compareStrings(rhs, lhs, cs);
1543 }
1544 
1552 {
1553  return -compareStrings(rhs, lhs, cs);
1554 }
1555 
1574 {
1575  if (lhs.isEmpty())
1576  return lencmp(qsizetype(0), rhs.size());
1577  if (cs == Qt::CaseInsensitive)
1578  return latin1nicmp(lhs.data(), lhs.size(), rhs.data(), rhs.size());
1579  const auto l = std::min(lhs.size(), rhs.size());
1580  int r = memcmp(lhs.data(), rhs.data(), l);
1581  return r ? r : lencmp(lhs.size(), rhs.size());
1582 }
1583 
1591 {
1592  return compareStrings(lhs, rhs.toString(), cs); // ### optimize!
1593 }
1594 
1602 {
1603  if (cs == Qt::CaseSensitive)
1604  return QUtf8::compareUtf8(lhs, rhs);
1605  return ucstricmp8(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1606 }
1607 
1615 {
1616  return -compareStrings(rhs, lhs, cs);
1617 }
1618 
1626 {
1627  if (lhs.isEmpty())
1628  return lencmp(0, rhs.size());
1629  if (cs == Qt::CaseInsensitive)
1630  return compareStrings(lhs.toString(), rhs.toString(), cs); // ### optimize!
1631  const auto l = std::min(lhs.size(), rhs.size());
1632  int r = memcmp(lhs.data(), rhs.data(), l);
1633  return r ? r : lencmp(lhs.size(), rhs.size());
1634 }
1635 
1637 {
1638  return lhs.visit([rhs, cs](auto lhs) {
1639  return rhs.visit([lhs, cs](auto rhs) {
1640  return QtPrivate::compareStrings(lhs, rhs, cs);
1641  });
1642  });
1643 }
1644 
1645 // ### Qt 7: do not allow anything but ASCII digits
1646 // in arg()'s replacements.
1647 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1648 static bool supportUnicodeDigitValuesInArg()
1649 {
1650  static const bool result = []() {
1651  static const char supportUnicodeDigitValuesEnvVar[]
1652  = "QT_USE_UNICODE_DIGIT_VALUES_IN_STRING_ARG";
1653 
1654  if (qEnvironmentVariableIsSet(supportUnicodeDigitValuesEnvVar))
1655  return qEnvironmentVariableIntValue(supportUnicodeDigitValuesEnvVar) != 0;
1656 
1657 #if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) // keep it in sync with the test
1658  return true;
1659 #else
1660  return false;
1661 #endif
1662  }();
1663 
1664  return result;
1665 }
1666 #endif
1667 
1668 static int qArgDigitValue(QChar ch) noexcept
1669 {
1670 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1671  if (supportUnicodeDigitValuesInArg())
1672  return ch.digitValue();
1673 #endif
1674  if (ch >= u'0' && ch <= u'9')
1675  return int(ch.unicode() - u'0');
1676  return -1;
1677 }
1678 
1679 
2229 
2232 
2445 qsizetype QString::toUcs4_helper(const ushort *uc, qsizetype length, uint *out)
2446 {
2447  qsizetype count = 0;
2448 
2450  while (i.hasNext())
2451  out[count++] = i.next();
2452 
2453  return count;
2454 }
2455 
2504 {
2505  if (!unicode) {
2506  d.clear();
2507  } else {
2508  if (size < 0) {
2509  size = 0;
2510  while (!unicode[size].isNull())
2511  ++size;
2512  }
2513  if (!size) {
2514  d = DataPointer::fromRawData(&_empty, 0);
2515  } else {
2517  Q_CHECK_PTR(d.data());
2518  memcpy(d.data(), unicode, size * sizeof(QChar));
2519  d.data()[size] = '\0';
2520  }
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  char16_t *i = d.data() + size;
2539  char16_t *b = d.data();
2540  const char16_t value = ch.unicode();
2541  while (i != b)
2542  *--i = value;
2543  }
2544 }
2545 
2553 {
2554  if (size <= 0) {
2555  d = DataPointer::fromRawData(&_empty, 0);
2556  } else {
2558  Q_CHECK_PTR(d.data());
2559  d.data()[size] = '\0';
2560  }
2561 }
2562 
2574 {
2575  d = DataPointer(Data::allocate(1), 1);
2576  Q_CHECK_PTR(d.data());
2577  d.data()[0] = ch.unicode();
2578  d.data()[1] = '\0';
2579 }
2580 
2671 {
2672  if (size < 0)
2673  size = 0;
2674 
2675  const auto capacityAtEnd = capacity() - d.freeSpaceAtBegin();
2676  if (d->needsDetach() || size > capacityAtEnd)
2677  reallocData(size, QArrayData::Grow);
2678  d.size = size;
2679  if (d->allocatedCapacity())
2680  d.data()[size] = 0;
2681 }
2682 
2694 {
2695  const qsizetype oldSize = length();
2696  resize(size);
2697  const qsizetype difference = length() - oldSize;
2698  if (difference > 0)
2699  std::fill_n(d.data() + oldSize, difference, fillChar.unicode());
2700 }
2701 
2770 void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
2771 {
2772  if (!alloc) {
2773  d = DataPointer::fromRawData(&_empty, 0);
2774  return;
2775  }
2776 
2777  // don't use reallocate path when reducing capacity and there's free space
2778  // at the beginning: might shift data pointer outside of allocated space
2779  const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
2780 
2781  if (d->needsDetach() || cannotUseReallocate) {
2782  DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size));
2783  Q_CHECK_PTR(dd.data());
2784  if (dd.size > 0)
2785  ::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
2786  dd.data()[dd.size] = 0;
2787  d = dd;
2788  } else {
2789  d->reallocate(alloc, option);
2790  }
2791 }
2792 
2793 void QString::reallocGrowData(qsizetype n)
2794 {
2795  if (!n) // expected to always allocate
2796  n = 1;
2797 
2798  if (d->needsDetach()) {
2800  Q_CHECK_PTR(dd.data());
2801  dd->copyAppend(d.data(), d.data() + d.size);
2802  dd.data()[dd.size] = 0;
2803  d = dd;
2804  } else {
2805  d->reallocate(d.constAllocatedCapacity() + n, QArrayData::Grow);
2806  }
2807 }
2808 
2823 {
2824  d = other.d;
2825  return *this;
2826 }
2827 
2843 {
2844  const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
2845  if (isDetached() && other.size() <= capacityAtEnd) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
2846  d.size = other.size();
2847  d.data()[other.size()] = 0;
2848  qt_from_latin1(d.data(), other.latin1(), other.size());
2849  } else {
2850  *this = fromLatin1(other.latin1(), other.size());
2851  }
2852  return *this;
2853 }
2854 
2887 {
2888  const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
2889  if (isDetached() && capacityAtEnd >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
2890  // re-use existing capacity:
2891  d.data()[0] = ch.unicode();
2892  d.data()[1] = 0;
2893  d.size = 1;
2894  } else {
2895  operator=(QString(ch));
2896  }
2897  return *this;
2898 }
2899 
2911 
2915 
2970 {
2971  const char *s = str.latin1();
2972  if (i < 0 || !s || !(*s))
2973  return *this;
2974 
2975  qsizetype len = str.size();
2976  qsizetype difference = 0;
2977  if (Q_UNLIKELY(i > size()))
2978  difference = i - size();
2979  d.detachAndGrow(Data::GrowsAtEnd, difference + len, nullptr, nullptr);
2980  Q_CHECK_PTR(d.data());
2981  d->copyAppend(difference, u' ');
2982  d.size += len;
2983 
2984  ::memmove(d.data() + i + len, d.data() + i, (d.size - i - len) * sizeof(QChar));
2985  qt_from_latin1(d.data() + i, s, size_t(len));
2986  d.data()[d.size] = u'\0';
2987  return *this;
2988 }
2989 
3003 {
3004  if (i < 0 || size <= 0)
3005  return *this;
3006 
3007  const char16_t *s = reinterpret_cast<const char16_t *>(unicode);
3008 
3009  // handle this specially, as QArrayDataOps::insert() doesn't handle out of
3010  // bounds positions
3011  if (i >= d->size) {
3012  // In case when data points into the range or is == *this, we need to
3013  // defer a call to free() so that it comes after we copied the data from
3014  // the old memory:
3015  DataPointer detached{}; // construction is free
3017  Q_CHECK_PTR(d.data());
3018  d->copyAppend(i - d->size, u' ');
3019  d->copyAppend(s, s + size);
3020  d.data()[d.size] = u'\0';
3021  return *this;
3022  }
3023 
3024  if (!d->needsDetach() && QtPrivate::q_points_into_range(s, d.data(), d.data() + d.size))
3025  return insert(i, QStringView{QVarLengthArray(s, s + size)});
3026 
3027  d->insert(i, s, size);
3028  d.data()[d.size] = u'\0';
3029  return *this;
3030 }
3031 
3044 {
3045  if (i < 0)
3046  i += d.size;
3047  return insert(i, &ch, 1);
3048 }
3049 
3069 {
3070  if (!str.isNull()) {
3071  if (isNull()) {
3072  operator=(str);
3073  } else if (str.size()) {
3074  append(str.constData(), str.size());
3075  }
3076  }
3077  return *this;
3078 }
3079 
3087 {
3088  if (str && len > 0) {
3089  static_assert(sizeof(QChar) == sizeof(char16_t), "Unexpected difference in sizes");
3090  // the following should be safe as QChar uses char16_t as underlying data
3091  const char16_t *char16String = reinterpret_cast<const char16_t *>(str);
3092  d->growAppend(char16String, char16String + len);
3093  d.data()[d.size] = u'\0';
3094  }
3095  return *this;
3096 }
3097 
3104 {
3105  const char *s = str.latin1();
3106  const qsizetype len = str.size();
3107  if (s && len > 0) {
3108  d.detachAndGrow(Data::GrowsAtEnd, len, nullptr, nullptr);
3109  Q_CHECK_PTR(d.data());
3110  Q_ASSERT(len <= d->freeSpaceAtEnd());
3111  char16_t *i = d.data() + d.size;
3112  qt_from_latin1(i, s, size_t(len));
3113  d.size += len;
3114  d.data()[d.size] = '\0';
3115  } else if (d.isNull() && !str.isNull()) { // special case
3116  d = DataPointer::fromRawData(&_empty, 0);
3117  }
3118  return *this;
3119 }
3120 
3153 {
3154  d.detachAndGrow(QArrayData::GrowsAtEnd, 1, nullptr, nullptr);
3155  d->copyAppend(1, ch.unicode());
3156  d.data()[d.size] = '\0';
3157  return *this;
3158 }
3159 
3245 
3249 
3253 {
3254  if (pos < 0) // count from end of string
3255  pos += size();
3256  if (size_t(pos) >= size_t(size())) {
3257  // range problems
3258  } else if (len >= size() - pos) {
3259  resize(pos); // truncate
3260  } else if (len > 0) {
3261  detach();
3262  d->erase(d.begin() + pos, len);
3263  d.data()[d.size] = u'\0';
3264  }
3265  return *this;
3266 }
3267 
3268 template<typename T>
3269 static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs)
3270 {
3271  const auto needleSize = needle.size();
3272  if (!needleSize)
3273  return;
3274 
3275  // avoid detach if nothing to do:
3276  qsizetype i = s.indexOf(needle, 0, cs);
3277  if (i < 0)
3278  return;
3279 
3280  const auto beg = s.begin(); // detaches
3281  auto dst = beg + i;
3282  auto src = beg + i + needleSize;
3283  const auto end = s.end();
3284  // loop invariant: [beg, dst[ is partial result
3285  // [src, end[ still to be checked for needles
3286  while (src < end) {
3287  const auto i = s.indexOf(needle, src - beg, cs);
3288  const auto hit = i == -1 ? end : beg + i;
3289  const auto skipped = hit - src;
3290  memmove(dst, src, skipped * sizeof(QChar));
3291  dst += skipped;
3292  src = hit + needleSize;
3293  }
3294  s.truncate(dst - beg);
3295 }
3296 
3311 {
3312  const auto s = str.d.data();
3313  if (QtPrivate::q_points_into_range(s, d.data(), d.data() + d.size))
3314  removeStringImpl(*this, QStringView{QVarLengthArray(s, s + str.size())}, cs);
3315  else
3316  removeStringImpl(*this, qToStringViewIgnoringNull(str), cs);
3317  return *this;
3318 }
3319 
3337 {
3338  removeStringImpl(*this, str, cs);
3339  return *this;
3340 }
3341 
3360 {
3361  const qsizetype idx = indexOf(ch, 0, cs);
3362  if (idx != -1) {
3363  const auto first = begin(); // implicit detach()
3364  auto last = end();
3365  if (cs == Qt::CaseSensitive) {
3366  last = std::remove(first + idx, last, ch);
3367  } else {
3368  const QChar c = ch.toCaseFolded();
3369  auto caseInsensEqual = [c](QChar x) {
3370  return c == x.toCaseFolded();
3371  };
3372  last = std::remove_if(first + idx, last, caseInsensEqual);
3373  }
3374  resize(last - first);
3375  }
3376  return *this;
3377 }
3378 
3420 {
3421  return replace(pos, len, after.constData(), after.length());
3422 }
3423 
3432 {
3433  if (size_t(pos) > size_t(this->size()))
3434  return *this;
3435  if (len > this->size() - pos)
3436  len = this->size() - pos;
3437 
3438  size_t index = pos;
3439  replace_helper(&index, 1, len, unicode, size);
3440  return *this;
3441 }
3442 
3451 {
3452  return replace(pos, len, &after, 1);
3453 }
3454 
3474 {
3475  return replace(before.constData(), before.size(), after.constData(), after.size(), cs);
3476 }
3477 
3478 namespace { // helpers for replace and its helper:
3479 QChar *textCopy(const QChar *start, qsizetype len)
3480 {
3481  const size_t size = len * sizeof(QChar);
3482  QChar *const copy = static_cast<QChar *>(::malloc(size));
3483  Q_CHECK_PTR(copy);
3484  ::memcpy(copy, start, size);
3485  return copy;
3486 }
3487 
3488 static bool pointsIntoRange(const QChar *ptr, const char16_t *base, qsizetype len)
3489 {
3490  const QChar *const start = reinterpret_cast<const QChar *>(base);
3491  const std::less<const QChar *> less;
3492  return !less(ptr, start) && less(ptr, start + len);
3493 }
3494 } // end namespace
3495 
3499 void QString::replace_helper(size_t *indices, qsizetype nIndices, qsizetype blen, const QChar *after, qsizetype alen)
3500 {
3501  // Copy after if it lies inside our own d.b area (which we could
3502  // possibly invalidate via a realloc or modify by replacement).
3503  QChar *afterBuffer = nullptr;
3504  if (pointsIntoRange(after, d.data(), d.size)) // Use copy in place of vulnerable original:
3505  after = afterBuffer = textCopy(after, alen);
3506 
3507  QT_TRY {
3508  if (blen == alen) {
3509  // replace in place
3510  detach();
3511  for (qsizetype i = 0; i < nIndices; ++i)
3512  memcpy(d.data() + indices[i], after, alen * sizeof(QChar));
3513  } else if (alen < blen) {
3514  // replace from front
3515  detach();
3516  size_t to = indices[0];
3517  if (alen)
3518  memcpy(d.data()+to, after, alen*sizeof(QChar));
3519  to += alen;
3520  size_t movestart = indices[0] + blen;
3521  for (qsizetype i = 1; i < nIndices; ++i) {
3522  qsizetype msize = indices[i] - movestart;
3523  if (msize > 0) {
3524  memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar));
3525  to += msize;
3526  }
3527  if (alen) {
3528  memcpy(d.data() + to, after, alen * sizeof(QChar));
3529  to += alen;
3530  }
3531  movestart = indices[i] + blen;
3532  }
3533  qsizetype msize = d.size - movestart;
3534  if (msize > 0)
3535  memmove(d.data() + to, d.data() + movestart, msize * sizeof(QChar));
3536  resize(d.size - nIndices*(blen-alen));
3537  } else {
3538  // replace from back
3539  qsizetype adjust = nIndices*(alen-blen);
3540  qsizetype newLen = d.size + adjust;
3541  qsizetype moveend = d.size;
3542  resize(newLen);
3543 
3544  while (nIndices) {
3545  --nIndices;
3546  qsizetype movestart = indices[nIndices] + blen;
3547  qsizetype insertstart = indices[nIndices] + nIndices*(alen-blen);
3548  qsizetype moveto = insertstart + alen;
3549  memmove(d.data() + moveto, d.data() + movestart,
3550  (moveend - movestart)*sizeof(QChar));
3551  memcpy(d.data() + insertstart, after, alen * sizeof(QChar));
3552  moveend = movestart-blen;
3553  }
3554  }
3555  } QT_CATCH(const std::bad_alloc &) {
3556  ::free(afterBuffer);
3557  QT_RETHROW;
3558  }
3559  ::free(afterBuffer);
3560 }
3561 
3574  const QChar *after, qsizetype alen,
3576 {
3577  if (d.size == 0) {
3578  if (blen)
3579  return *this;
3580  } else {
3581  if (cs == Qt::CaseSensitive && before == after && blen == alen)
3582  return *this;
3583  }
3584  if (alen == 0 && blen == 0)
3585  return *this;
3586 
3587  QStringMatcher matcher(before, blen, cs);
3588  QChar *beforeBuffer = nullptr, *afterBuffer = nullptr;
3589 
3590  qsizetype index = 0;
3591  while (1) {
3592  size_t indices[1024];
3593  size_t pos = 0;
3594  while (pos < 1024) {
3595  index = matcher.indexIn(*this, index);
3596  if (index == -1)
3597  break;
3598  indices[pos++] = index;
3599  if (blen) // Step over before:
3600  index += blen;
3601  else // Only count one instance of empty between any two characters:
3602  index++;
3603  }
3604  if (!pos) // Nothing to replace
3605  break;
3606 
3607  if (Q_UNLIKELY(index != -1)) {
3608  /*
3609  We're about to change data, that before and after might point
3610  into, and we'll need that data for our next batch of indices.
3611  */
3612  if (!afterBuffer && pointsIntoRange(after, d.data(), d.size))
3613  after = afterBuffer = textCopy(after, alen);
3614 
3615  if (!beforeBuffer && pointsIntoRange(before, d.data(), d.size)) {
3616  beforeBuffer = textCopy(before, blen);
3617  matcher = QStringMatcher(beforeBuffer, blen, cs);
3618  }
3619  }
3620 
3621  replace_helper(indices, pos, blen, after, alen);
3622 
3623  if (Q_LIKELY(index == -1)) // Nothing left to replace
3624  break;
3625  // The call to replace_helper just moved what index points at:
3626  index += pos*(alen-blen);
3627  }
3628  ::free(afterBuffer);
3629  ::free(beforeBuffer);
3630 
3631  return *this;
3632 }
3633 
3643 {
3644  if (after.size() == 0)
3645  return remove(ch, cs);
3646 
3647  if (after.size() == 1)
3648  return replace(ch, after.front(), cs);
3649 
3650  if (size() == 0)
3651  return *this;
3652 
3653  char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode());
3654 
3655  qsizetype index = 0;
3656  while (1) {
3657  size_t indices[1024];
3658  size_t pos = 0;
3659  if (cs == Qt::CaseSensitive) {
3660  while (pos < 1024 && index < size()) {
3661  if (d.data()[index] == cc)
3662  indices[pos++] = index;
3663  index++;
3664  }
3665  } else {
3666  while (pos < 1024 && index < size()) {
3667  if (QChar::toCaseFolded(d.data()[index]) == cc)
3668  indices[pos++] = index;
3669  index++;
3670  }
3671  }
3672  if (!pos) // Nothing to replace
3673  break;
3674 
3675  replace_helper(indices, pos, 1, after.constData(), after.size());
3676 
3677  if (Q_LIKELY(index == size())) // Nothing left to replace
3678  break;
3679  // The call to replace_helper just moved what index points at:
3680  index += pos*(after.size() - 1);
3681  }
3682  return *this;
3683 }
3684 
3694 {
3695  if (d.size) {
3696  const qsizetype idx = indexOf(before, 0, cs);
3697  if (idx != -1) {
3698  detach();
3699  const char16_t a = after.unicode();
3700  char16_t *i = d.data();
3701  char16_t *const e = i + d.size;
3702  i += idx;
3703  *i = a;
3704  if (cs == Qt::CaseSensitive) {
3705  const char16_t b = before.unicode();
3706  while (++i != e) {
3707  if (*i == b)
3708  *i = a;
3709  }
3710  } else {
3711  const char16_t b = foldCase(before.unicode());
3712  while (++i != e) {
3713  if (foldCase(*i) == b)
3714  *i = a;
3715  }
3716  }
3717  }
3718  }
3719  return *this;
3720 }
3721 
3735 {
3736  qsizetype alen = after.size();
3737  qsizetype blen = before.size();
3740  qt_from_latin1(a.data(), after.latin1(), alen);
3741  qt_from_latin1(b.data(), before.latin1(), blen);
3742  return replace((const QChar *)b.data(), blen, (const QChar *)a.data(), alen, cs);
3743 }
3744 
3758 {
3759  qsizetype blen = before.size();
3761  qt_from_latin1(b.data(), before.latin1(), blen);
3762  return replace((const QChar *)b.data(), blen, after.constData(), after.d.size, cs);
3763 }
3764 
3778 {
3779  qsizetype alen = after.size();
3781  qt_from_latin1(a.data(), after.latin1(), alen);
3782  return replace(before.constData(), before.d.size, (const QChar *)a.data(), alen, cs);
3783 }
3784 
3798 {
3799  qsizetype alen = after.size();
3801  qt_from_latin1(a.data(), after.latin1(), alen);
3802  return replace(&c, 1, (const QChar *)a.data(), alen, cs);
3803 }
3804 
3805 
4124 #if QT_STRINGVIEW_LEVEL < 2
4143 {
4145 }
4146 #endif // QT_STRINGVIEW_LEVEL < 2
4147 
4186 {
4187  return QtPrivate::findString(QStringView(unicode(), size()), from, str, cs);
4188 }
4189 
4198 {
4199  return qFindChar(QStringView(unicode(), length()), ch, from, cs);
4200 }
4201 
4202 #if QT_STRINGVIEW_LEVEL < 2
4227 {
4228  return QtPrivate::lastIndexOf(QStringView(*this), from, str, cs);
4229 }
4230 
4249 #endif // QT_STRINGVIEW_LEVEL < 2
4250 
4278 {
4279  return QtPrivate::lastIndexOf(*this, from, str, cs);
4280 }
4281 
4307 {
4308  return qLastIndexOf(QStringView(*this), ch, from, cs);
4309 }
4310 
4355 #if QT_CONFIG(regularexpression)
4356 struct QStringCapture
4357 {
4358  qsizetype pos;
4359  qsizetype len;
4360  int no;
4361 };
4362 Q_DECLARE_TYPEINFO(QStringCapture, Q_PRIMITIVE_TYPE);
4363 
4382 QString &QString::replace(const QRegularExpression &re, const QString &after)
4383 {
4384  if (!re.isValid()) {
4385  qWarning("QString::replace: invalid QRegularExpression object");
4386  return *this;
4387  }
4388 
4389  const QString copy(*this);
4391  if (!iterator.hasNext()) // no matches at all
4392  return *this;
4393 
4394  reallocData(d.size, QArrayData::KeepSize);
4395 
4396  qsizetype numCaptures = re.captureCount();
4397 
4398  // 1. build the backreferences list, holding where the backreferences
4399  // are in the replacement string
4400  QList<QStringCapture> backReferences;
4401  const qsizetype al = after.length();
4402  const QChar *ac = after.unicode();
4403 
4404  for (qsizetype i = 0; i < al - 1; i++) {
4405  if (ac[i] == QLatin1Char('\\')) {
4406  int no = ac[i + 1].digitValue();
4407  if (no > 0 && no <= numCaptures) {
4408  QStringCapture backReference;
4409  backReference.pos = i;
4410  backReference.len = 2;
4411 
4412  if (i < al - 2) {
4413  int secondDigit = ac[i + 2].digitValue();
4414  if (secondDigit != -1 && ((no * 10) + secondDigit) <= numCaptures) {
4415  no = (no * 10) + secondDigit;
4416  ++backReference.len;
4417  }
4418  }
4419 
4420  backReference.no = no;
4421  backReferences.append(backReference);
4422  }
4423  }
4424  }
4425 
4426  // 2. iterate on the matches. For every match, copy in chunks
4427  // - the part before the match
4428  // - the after string, with the proper replacements for the backreferences
4429 
4430  qsizetype newLength = 0; // length of the new string, with all the replacements
4431  qsizetype lastEnd = 0;
4432  QList<QStringView> chunks;
4433  const QStringView copyView{ copy }, afterView{ after };
4434  while (iterator.hasNext()) {
4435  QRegularExpressionMatch match = iterator.next();
4436  qsizetype len;
4437  // add the part before the match
4438  len = match.capturedStart() - lastEnd;
4439  if (len > 0) {
4440  chunks << copyView.mid(lastEnd, len);
4441  newLength += len;
4442  }
4443 
4444  lastEnd = 0;
4445  // add the after string, with replacements for the backreferences
4446  for (const QStringCapture &backReference : qAsConst(backReferences)) {
4447  // part of "after" before the backreference
4448  len = backReference.pos - lastEnd;
4449  if (len > 0) {
4450  chunks << afterView.mid(lastEnd, len);
4451  newLength += len;
4452  }
4453 
4454  // backreference itself
4455  len = match.capturedLength(backReference.no);
4456  if (len > 0) {
4457  chunks << copyView.mid(match.capturedStart(backReference.no), len);
4458  newLength += len;
4459  }
4460 
4461  lastEnd = backReference.pos + backReference.len;
4462  }
4463 
4464  // add the last part of the after string
4465  len = afterView.length() - lastEnd;
4466  if (len > 0) {
4467  chunks << afterView.mid(lastEnd, len);
4468  newLength += len;
4469  }
4470 
4471  lastEnd = match.capturedEnd();
4472  }
4473 
4474  // 3. trailing string after the last match
4475  if (copyView.length() > lastEnd) {
4476  chunks << copyView.mid(lastEnd);
4477  newLength += copyView.length() - lastEnd;
4478  }
4479 
4480  // 4. assemble the chunks together
4481  resize(newLength);
4482  qsizetype i = 0;
4483  QChar *uc = data();
4484  for (const QStringView &chunk : qAsConst(chunks)) {
4485  qsizetype len = chunk.length();
4486  memcpy(uc + i, chunk.constData(), len * sizeof(QChar));
4487  i += len;
4488  }
4489 
4490  return *this;
4491 }
4492 #endif // QT_CONFIG(regularexpression)
4493 
4505 {
4507 }
4508 
4521 {
4522  return QtPrivate::count(QStringView(unicode(), size()), ch, cs);
4523 }
4524 
4537 {
4538  return QtPrivate::count(*this, str, cs);
4539 }
4540 
4541 #if QT_STRINGVIEW_LEVEL < 2
4555 #endif // QT_STRINGVIEW_LEVEL < 2
4556 
4587 #if QT_CONFIG(regularexpression)
4604 {
4605  return QtPrivate::indexOf(QStringView(*this), re, from, rmatch);
4606 }
4607 
4638 {
4639  return QtPrivate::lastIndexOf(QStringView(*this), re, from, rmatch);
4640 }
4641 
4676 bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *rmatch) const
4677 {
4678  return QtPrivate::contains(QStringView(*this), re, rmatch);
4679 }
4680 
4700 {
4701  return QtPrivate::count(QStringView(*this), re);
4702 }
4703 #endif // QT_CONFIG(regularexpression)
4704 
4778 {
4779  const QList<QStringView> sections = QStringView{ *this }.split(
4781  const qsizetype sectionsSize = sections.size();
4782  if (!(flags & SectionSkipEmpty)) {
4783  if (start < 0)
4784  start += sectionsSize;
4785  if (end < 0)
4786  end += sectionsSize;
4787  } else {
4788  qsizetype skip = 0;
4789  for (qsizetype k = 0; k < sectionsSize; ++k) {
4790  if (sections.at(k).isEmpty())
4791  skip++;
4792  }
4793  if (start < 0)
4794  start += sectionsSize - skip;
4795  if (end < 0)
4796  end += sectionsSize - skip;
4797  }
4798  if (start >= sectionsSize || end < 0 || start > end)
4799  return QString();
4800 
4801  QString ret;
4802  qsizetype first_i = start, last_i = end;
4803  for (qsizetype x = 0, i = 0; x <= end && i < sectionsSize; ++i) {
4804  const QStringView &section = sections.at(i);
4805  const bool empty = section.isEmpty();
4806  if (x >= start) {
4807  if (x == start)
4808  first_i = i;
4809  if (x == end)
4810  last_i = i;
4811  if (x > start && i > 0)
4812  ret += sep;
4813  ret += section;
4814  }
4815  if (!empty || !(flags & SectionSkipEmpty))
4816  x++;
4817  }
4818  if ((flags & SectionIncludeLeadingSep) && first_i > 0)
4819  ret.prepend(sep);
4820  if ((flags & SectionIncludeTrailingSep) && last_i < sectionsSize - 1)
4821  ret += sep;
4822  return ret;
4823 }
4824 
4825 #if QT_CONFIG(regularexpression)
4826 class qt_section_chunk {
4827 public:
4828  qt_section_chunk() {}
4829  qt_section_chunk(qsizetype l, QStringView s) : length(l), string(std::move(s)) {}
4830  qsizetype length;
4832 };
4833 Q_DECLARE_TYPEINFO(qt_section_chunk, Q_RELOCATABLE_TYPE);
4834 
4835 static QString extractSections(const QList<qt_section_chunk> &sections, qsizetype start, qsizetype end,
4836  QString::SectionFlags flags)
4837 {
4838  const qsizetype sectionsSize = sections.size();
4839 
4840  if (!(flags & QString::SectionSkipEmpty)) {
4841  if (start < 0)
4842  start += sectionsSize;
4843  if (end < 0)
4844  end += sectionsSize;
4845  } else {
4846  qsizetype skip = 0;
4847  for (qsizetype k = 0; k < sectionsSize; ++k) {
4848  const qt_section_chunk &section = sections.at(k);
4849  if (section.length == section.string.length())
4850  skip++;
4851  }
4852  if (start < 0)
4853  start += sectionsSize - skip;
4854  if (end < 0)
4855  end += sectionsSize - skip;
4856  }
4857  if (start >= sectionsSize || end < 0 || start > end)
4858  return QString();
4859 
4860  QString ret;
4861  qsizetype x = 0;
4862  qsizetype first_i = start, last_i = end;
4863  for (qsizetype i = 0; x <= end && i < sectionsSize; ++i) {
4864  const qt_section_chunk &section = sections.at(i);
4865  const bool empty = (section.length == section.string.length());
4866  if (x >= start) {
4867  if (x == start)
4868  first_i = i;
4869  if (x == end)
4870  last_i = i;
4871  if (x != start)
4872  ret += section.string;
4873  else
4874  ret += section.string.mid(section.length);
4875  }
4876  if (!empty || !(flags & QString::SectionSkipEmpty))
4877  x++;
4878  }
4879 
4880  if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) {
4881  const qt_section_chunk &section = sections.at(first_i);
4882  ret.prepend(section.string.left(section.length));
4883  }
4884 
4886  && last_i < sectionsSize - 1) {
4887  const qt_section_chunk &section = sections.at(last_i+1);
4888  ret += section.string.left(section.length);
4889  }
4890 
4891  return ret;
4892 }
4893 
4909 {
4910  if (!re.isValid()) {
4911  qWarning("QString::section: invalid QRegularExpression object");
4912  return QString();
4913  }
4914 
4915  const QChar *uc = unicode();
4916  if (!uc)
4917  return QString();
4918 
4919  QRegularExpression sep(re);
4921  sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption);
4922 
4923  QList<qt_section_chunk> sections;
4924  qsizetype n = length(), m = 0, last_m = 0, last_len = 0;
4925  QRegularExpressionMatchIterator iterator = sep.globalMatch(*this);
4926  while (iterator.hasNext()) {
4927  QRegularExpressionMatch match = iterator.next();
4928  m = match.capturedStart();
4929  sections.append(qt_section_chunk(last_len, QStringView{ *this }.sliced(last_m, m - last_m)));
4930  last_m = m;
4931  last_len = match.capturedLength();
4932  }
4933  sections.append(qt_section_chunk(last_len, QStringView{ *this }.sliced(last_m, n - last_m)));
4934 
4935  return extractSections(sections, start, end, flags);
4936 }
4937 #endif // QT_CONFIG(regularexpression)
4938 
4952 {
4953  if (size_t(n) >= size_t(size()))
4954  return *this;
4955  return QString((const QChar*) d.data(), n);
4956 }
4957 
4971 {
4972  if (size_t(n) >= size_t(size()))
4973  return *this;
4974  return QString(constData() + size() - n, n);
4975 }
4976 
4995 {
4996  qsizetype p = position;
4997  qsizetype l = n;
4998  using namespace QtPrivate;
4999  switch (QContainerImplHelper::mid(size(), &p, &l)) {
5001  return QString();
5002  case QContainerImplHelper::Empty:
5003  return QString(DataPointer::fromRawData(&_empty, 0));
5004  case QContainerImplHelper::Full:
5005  return *this;
5006  case QContainerImplHelper::Subset:
5007  return QString(constData() + p, l);
5008  }
5009  Q_UNREACHABLE();
5010  return QString();
5011 }
5012 
5080 #if QT_STRINGVIEW_LEVEL < 2
5093 {
5094  return qt_starts_with(*this, s, cs);
5095 }
5096 #endif
5097 
5102 {
5103  return qt_starts_with(*this, s, cs);
5104 }
5105 
5113 {
5114  return qt_starts_with(*this, c, cs);
5115 }
5116 
5131 #if QT_STRINGVIEW_LEVEL < 2
5144 {
5145  return qt_ends_with(*this, s, cs);
5146 }
5147 #endif // QT_STRINGVIEW_LEVEL < 2
5148 
5166 {
5167  return qt_ends_with(*this, s, cs);
5168 }
5169 
5177 {
5178  return qt_ends_with(*this, c, cs);
5179 }
5180 
5194 bool QString::isUpper() const
5195 {
5196  QStringIterator it(*this);
5197 
5198  while (it.hasNext()) {
5199  const char32_t uc = it.next();
5200  if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff)
5201  return false;
5202  }
5203 
5204  return true;
5205 }
5206 
5220 bool QString::isLower() const
5221 {
5222  QStringIterator it(*this);
5223 
5224  while (it.hasNext()) {
5225  const char32_t uc = it.next();
5226  if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff)
5227  return false;
5228  }
5229 
5230  return true;
5231 }
5232 
5233 static QByteArray qt_convert_to_latin1(QStringView string);
5234 
5235 QByteArray QString::toLatin1_helper(const QString &string)
5236 {
5237  return qt_convert_to_latin1(string);
5238 }
5239 
5251 {
5252  return string.visit([] (auto string) { return string.toString(); });
5253 }
5254 
5268 {
5269  return qt_convert_to_latin1(string);
5270 }
5271 
5272 static QByteArray qt_convert_to_latin1(QStringView string)
5273 {
5274  if (Q_UNLIKELY(string.isNull()))
5275  return QByteArray();
5276 
5278 
5279  // since we own the only copy, we're going to const_cast the constData;
5280  // that avoids an unnecessary call to detach() and expansion code that will never get used
5281  qt_to_latin1(reinterpret_cast<uchar *>(const_cast<char *>(ba.constData())),
5282  string.utf16(), string.size());
5283  return ba;
5284 }
5285 
5286 QByteArray QString::toLatin1_helper_inplace(QString &s)
5287 {
5288  if (!s.isDetached())
5289  return qt_convert_to_latin1(s);
5290 
5291  // We can return our own buffer to the caller.
5292  // Conversion to Latin-1 always shrinks the buffer by half.
5293  const char16_t *data = s.d.data();
5294  qsizetype length = s.d.size;
5295 
5296  // Move the d pointer over to the bytearray.
5297  // Kids, avert your eyes. Don't try this at home.
5298 
5299  // this relies on the fact that we use QArrayData for everything behind the scenes which has the same layout
5300  static_assert(sizeof(QByteArray::DataPointer) == sizeof(QString::DataPointer), "sizes have to be equal");
5301  QByteArray::DataPointer ba_d(reinterpret_cast<QByteArray::Data *>(s.d.d_ptr()), reinterpret_cast<char *>(s.d.data()), length);
5302  ba_d.ref();
5303  s.clear();
5304 
5305  char *ddata = ba_d.data();
5306 
5307  // multiply the allocated capacity by sizeof(char16_t)
5308  ba_d.d_ptr()->alloc *= sizeof(char16_t);
5309 
5310  // do the in-place conversion
5311  qt_to_latin1(reinterpret_cast<uchar *>(ddata), data, length);
5312  ddata[length] = '\0';
5313  return QByteArray(ba_d);
5314 }
5315 
5328 static QByteArray qt_convert_to_local_8bit(QStringView string);
5329 
5347 QByteArray QString::toLocal8Bit_helper(const QChar *data, qsizetype size)
5348 {
5349  return qt_convert_to_local_8bit(QStringView(data, size));
5350 }
5351 
5352 static QByteArray qt_convert_to_local_8bit(QStringView string)
5353 {
5354  if (string.isNull())
5355  return QByteArray();
5357  return fromUtf16(string);
5358 }
5359 
5376 {
5377  return qt_convert_to_local_8bit(string);
5378 }
5379 
5380 static QByteArray qt_convert_to_utf8(QStringView str);
5381 
5393 QByteArray QString::toUtf8_helper(const QString &str)
5394 {
5395  return qt_convert_to_utf8(str);
5396 }
5397 
5398 static QByteArray qt_convert_to_utf8(QStringView str)
5399 {
5400  if (str.isNull())
5401  return QByteArray();
5402 
5404 }
5405 
5419 {
5420  return qt_convert_to_utf8(string);
5421 }
5422 
5423 static QList<uint> qt_convert_to_ucs4(QStringView string);
5424 
5441 {
5442  return qt_convert_to_ucs4(*this);
5443 }
5444 
5445 static QList<uint> qt_convert_to_ucs4(QStringView string)
5446 {
5447  QList<uint> v(string.length());
5448  uint *a = const_cast<uint*>(v.constData());
5449  QStringIterator it(string);
5450  while (it.hasNext())
5451  *a++ = it.next();
5452  v.resize(a - v.constData());
5453  return v;
5454 }
5455 
5474 {
5475  return qt_convert_to_ucs4(string);
5476 }
5477 
5489 {
5490  DataPointer d;
5491  if (!ba.data()) {
5492  // nothing to do
5493  } else if (ba.size() == 0) {
5494  d = DataPointer::fromRawData(&_empty, 0);
5495  } else {
5497  Q_CHECK_PTR(d.data());
5498  d.data()[ba.size()] = '\0';
5499  char16_t *dst = d.data();
5500 
5501  qt_from_latin1(dst, ba.data(), size_t(ba.size()));
5502  }
5503  return QString(std::move(d));
5504 }
5505 
5564 {
5565  if (ba.isNull())
5566  return QString();
5567  if (ba.isEmpty())
5568  return QString(DataPointer::fromRawData(&_empty, 0));
5570  return toUtf16(ba);
5571 }
5572 
5633 {
5634  if (ba.isNull())
5635  return QString();
5636  if (ba.isEmpty())
5637  return QString(DataPointer::fromRawData(&_empty, 0));
5638  return QUtf8::convertToUnicode(ba);
5639 }
5640 
5659 {
5660  if (!unicode)
5661  return QString();
5662  if (size < 0)
5665  return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 2));
5666 }
5667 
5691 {
5692  if (!unicode)
5693  return QString();
5694  if (size < 0) {
5695  size = 0;
5696  while (unicode[size] != 0)
5697  ++size;
5698  }
5700  return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 4));
5701 }
5702 
5703 
5714 {
5715  resize(size);
5716  if (unicode && size)
5717  memcpy(d.data(), unicode, size * sizeof(QChar));
5718  return *this;
5719 }
5720 
5753 QString QString::simplified_helper(const QString &str)
5754 {
5756 }
5757 
5758 QString QString::simplified_helper(QString &str)
5759 {
5761 }
5762 
5763 namespace {
5764  template <typename StringView>
5765  StringView qt_trimmed(StringView s) noexcept
5766  {
5767  auto begin = s.begin();
5768  auto end = s.end();
5770  return StringView{begin, end};
5771  }
5772 }
5773 
5790 {
5791  return qt_trimmed(s);
5792 }
5793 
5795 {
5796  return qt_trimmed(s);
5797 }
5798 
5817 QString QString::trimmed_helper(const QString &str)
5818 {
5820 }
5821 
5822 QString QString::trimmed_helper(QString &str)
5823 {
5825 }
5826 
5935 {
5936  if (pos < size())
5937  resize(pos);
5938 }
5939 
5940 
5956 {
5957  if (n > 0)
5958  resize(d.size - n);
5959 }
5960 
5974 {
5975  resize(size < 0 ? d.size : size);
5976  if (d.size) {
5977  QChar *i = (QChar*)d.data() + d.size;
5978  QChar *b = (QChar*)d.data();
5979  while (i != b)
5980  *--i = ch;
5981  }
5982  return *this;
5983 }
5984 
6251 #if QT_STRINGVIEW_LEVEL < 2
6263 int QString::compare(const QString &other, Qt::CaseSensitivity cs) const noexcept
6264 {
6265  return QtPrivate::compareStrings(*this, other, cs);
6266 }
6267 #endif
6268 
6273 int QString::compare_helper(const QChar *data1, qsizetype length1, const QChar *data2, qsizetype length2,
6274  Qt::CaseSensitivity cs) noexcept
6275 {
6276  Q_ASSERT(length1 >= 0);
6277  Q_ASSERT(length2 >= 0);
6278  Q_ASSERT(data1 || length1 == 0);
6279  Q_ASSERT(data2 || length2 == 0);
6280  return QtPrivate::compareStrings(QStringView(data1, length1), QStringView(data2, length2), cs);
6281 }
6282 
6290 {
6291  return QtPrivate::compareStrings(*this, other, cs);
6292 }
6293 
6298 int QString::compare_helper(const QChar *data1, qsizetype length1, const char *data2, qsizetype length2,
6299  Qt::CaseSensitivity cs) noexcept
6300 {
6301  Q_ASSERT(length1 >= 0);
6302  Q_ASSERT(data1 || length1 == 0);
6303  if (!data2)
6304  return length1;
6305  if (Q_UNLIKELY(length2 < 0))
6306  length2 = qsizetype(strlen(data2));
6307  return QtPrivate::compareStrings(QStringView(data1, length1),
6308  QUtf8StringView(data2, length2), cs);
6309 }
6310 
6325 int QLatin1String::compare_helper(const QChar *data1, qsizetype length1, QLatin1String s2,
6326  Qt::CaseSensitivity cs) noexcept
6327 {
6328  Q_ASSERT(length1 >= 0);
6329  Q_ASSERT(data1 || length1 == 0);
6330  return QtPrivate::compareStrings(QStringView(data1, length1), s2, cs);
6331 }
6332 
6382 #if !defined(CSTR_LESS_THAN)
6383 #define CSTR_LESS_THAN 1
6384 #define CSTR_EQUAL 2
6385 #define CSTR_GREATER_THAN 3
6386 #endif
6387 
6404 {
6405  return localeAwareCompare_helper(constData(), length(), other.constData(), other.length());
6406 }
6407 
6412 int QString::localeAwareCompare_helper(const QChar *data1, qsizetype length1,
6413  const QChar *data2, qsizetype length2)
6414 {
6415  Q_ASSERT(length1 >= 0);
6416  Q_ASSERT(data1 || length1 == 0);
6417  Q_ASSERT(length2 >= 0);
6418  Q_ASSERT(data2 || length2 == 0);
6419 
6420  // do the right thing for null and empty
6421  if (length1 == 0 || length2 == 0)
6422  return QtPrivate::compareStrings(QStringView(data1, length1), QStringView(data2, length2),
6424 
6425 #if QT_CONFIG(icu)
6426  return QCollator::defaultCompare(QStringView(data1, length1), QStringView(data2, length2));
6427 #else
6430 # if defined(Q_OS_WIN)
6431  int res = CompareStringEx(LOCALE_NAME_USER_DEFAULT, 0, (LPWSTR)lhs.constData(), lhs.length(), (LPWSTR)rhs.constData(), rhs.length(), NULL, NULL, 0);
6432 
6433  switch (res) {
6434  case CSTR_LESS_THAN:
6435  return -1;
6436  case CSTR_GREATER_THAN:
6437  return 1;
6438  default:
6439  return 0;
6440  }
6441 # elif defined (Q_OS_DARWIN)
6442  // Use CFStringCompare for comparing strings on Mac. This makes Qt order
6443  // strings the same way as native applications do, and also respects
6444  // the "Order for sorted lists" setting in the International preferences
6445  // panel.
6446  const CFStringRef thisString =
6447  CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
6448  reinterpret_cast<const UniChar *>(lhs.constData()), lhs.length(), kCFAllocatorNull);
6449  const CFStringRef otherString =
6450  CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
6451  reinterpret_cast<const UniChar *>(rhs.constData()), rhs.length(), kCFAllocatorNull);
6452 
6453  const int result = CFStringCompare(thisString, otherString, kCFCompareLocalized);
6454  CFRelease(thisString);
6455  CFRelease(otherString);
6456  return result;
6457 # elif defined(Q_OS_UNIX)
6458  // declared in <string.h> (no better than QtPrivate::compareStrings() on Android, sadly)
6459  return strcoll(lhs.toLocal8Bit().constData(), rhs.toLocal8Bit().constData());
6460 # else
6461 # error "This case shouldn't happen"
6463 # endif
6464 #endif // !QT_CONFIG(icu)
6465 }
6466 
6467 
6491 const ushort *QString::utf16() const
6492 {
6493  if (!d->isMutable()) {
6494  // ensure '\0'-termination for ::fromRawData strings
6495  const_cast<QString*>(this)->reallocData(d.size, QArrayData::KeepSize);
6496  }
6497  return reinterpret_cast<const ushort *>(d.data());
6498 }
6499 
6519 {
6520  QString result;
6521  qsizetype len = length();
6522  qsizetype padlen = width - len;
6523  if (padlen > 0) {
6524  result.resize(len+padlen);
6525  if (len)
6526  memcpy(result.d.data(), d.data(), sizeof(QChar)*len);
6527  QChar *uc = (QChar*)result.d.data() + len;
6528  while (padlen--)
6529  * uc++ = fill;
6530  } else {
6531  if (truncate)
6532  result = left(width);
6533  else
6534  result = *this;
6535  }
6536  return result;
6537 }
6538 
6558 {
6559  QString result;
6560  qsizetype len = length();
6561  qsizetype padlen = width - len;
6562  if (padlen > 0) {
6563  result.resize(len+padlen);
6564  QChar *uc = (QChar*)result.d.data();
6565  while (padlen--)
6566  * uc++ = fill;
6567  if (len)
6568  memcpy(static_cast<void *>(uc), static_cast<const void *>(d.data()), sizeof(QChar)*len);
6569  } else {
6570  if (truncate)
6571  result = left(width);
6572  else
6573  result = *this;
6574  }
6575  return result;
6576 }
6577 
6591 namespace QUnicodeTables {
6592 /*
6593  \internal
6594  Converts the \a str string starting from the position pointed to by the \a
6595  it iterator, using the Unicode case traits \c Traits, and returns the
6596  result. The input string must not be empty (the convertCase function below
6597  guarantees that).
6598 
6599  The string type \c{T} is also a template and is either \c{const QString} or
6600  \c{QString}. This function can do both copy-conversion and in-place
6601  conversion depending on the state of the \a str parameter:
6602  \list
6603  \li \c{T} is \c{const QString}: copy-convert
6604  \li \c{T} is \c{QString} and its refcount != 1: copy-convert
6605  \li \c{T} is \c{QString} and its refcount == 1: in-place convert
6606  \endlist
6607 
6608  In copy-convert mode, the local variable \c{s} is detached from the input
6609  \a str. In the in-place convert mode, \a str is in moved-from state and
6610  \c{s} contains the only copy of the string, without reallocation (thus,
6611  \a it is still valid).
6612 
6613  There is one pathological case left: when the in-place conversion needs to
6614  reallocate memory to grow the buffer. In that case, we need to adjust the \a
6615  it pointer.
6616  */
6617 template <typename T>
6618 Q_NEVER_INLINE
6619 static QString detachAndConvertCase(T &str, QStringIterator it, QUnicodeTables::Case which)
6620 {
6621  Q_ASSERT(!str.isEmpty());
6622  QString s = std::move(str); // will copy if T is const QString
6623  QChar *pp = s.begin() + it.index(); // will detach if necessary
6624 
6625  do {
6626  const auto folded = fullConvertCase(it.next(), which);
6627  if (Q_UNLIKELY(folded.size() > 1)) {
6628  if (folded.chars[0] == *pp && folded.size() == 2) {
6629  // special case: only second actually changed (e.g. surrogate pairs),
6630  // avoid slow case
6631  ++pp;
6632  *pp++ = folded.chars[1];
6633  } else {
6634  // slow path: the string is growing
6635  qsizetype inpos = it.index() - 1;
6636  qsizetype outpos = pp - s.constBegin();
6637 
6638  s.replace(outpos, 1, reinterpret_cast<const QChar *>(folded.data()), folded.size());
6639  pp = const_cast<QChar *>(s.constBegin()) + outpos + folded.size();
6640 
6641  // Adjust the input iterator if we are performing an in-place conversion
6642  if constexpr (!std::is_const<T>::value)
6643  it = QStringIterator(s.constBegin(), inpos + folded.size(), s.constEnd());
6644  }
6645  } else {
6646  *pp++ = folded.chars[0];
6647  }
6648  } while (it.hasNext());
6649 
6650  return s;
6651 }
6652 
6653 template <typename T>
6654 static QString convertCase(T &str, QUnicodeTables::Case which)
6655 {
6656  const QChar *p = str.constBegin();
6657  const QChar *e = p + str.size();
6658 
6659  // this avoids out of bounds check in the loop
6660  while (e != p && e[-1].isHighSurrogate())
6661  --e;
6662 
6663  QStringIterator it(p, e);
6664  while (it.hasNext()) {
6665  const char32_t uc = it.next();
6666  if (qGetProp(uc)->cases[which].diff) {
6667  it.recede();
6668  return detachAndConvertCase(str, it, which);
6669  }
6670  }
6671  return std::move(str);
6672 }
6673 } // namespace QUnicodeTables
6674 
6675 QString QString::toLower_helper(const QString &str)
6676 {
6677  return QUnicodeTables::convertCase(str, QUnicodeTables::LowerCase);
6678 }
6679 
6680 QString QString::toLower_helper(QString &str)
6681 {
6682  return QUnicodeTables::convertCase(str, QUnicodeTables::LowerCase);
6683 }
6684 
6692 QString QString::toCaseFolded_helper(const QString &str)
6693 {
6694  return QUnicodeTables::convertCase(str, QUnicodeTables::CaseFold);
6695 }
6696 
6697 QString QString::toCaseFolded_helper(QString &str)
6698 {
6699  return QUnicodeTables::convertCase(str, QUnicodeTables::CaseFold);
6700 }
6701 
6715 QString QString::toUpper_helper(const QString &str)
6716 {
6717  return QUnicodeTables::convertCase(str, QUnicodeTables::UpperCase);
6718 }
6719 
6720 QString QString::toUpper_helper(QString &str)
6721 {
6722  return QUnicodeTables::convertCase(str, QUnicodeTables::UpperCase);
6723 }
6724 
6759 QString QString::asprintf(const char *cformat, ...)
6760 {
6761  va_list ap;
6762  va_start(ap, cformat);
6763  const QString s = vasprintf(cformat, ap);
6764  va_end(ap);
6765  return s;
6766 }
6767 
6768 static void append_utf8(QString &qs, const char *cs, int len)
6769 {
6770  const int oldSize = qs.size();
6771  qs.resize(oldSize + len);
6772  const QChar *newEnd = QUtf8::convertToUnicode(qs.data() + oldSize, QByteArrayView(cs, len));
6773  qs.resize(newEnd - qs.constData());
6774 }
6775 
6776 static uint parse_flag_characters(const char * &c) noexcept
6777 {
6779  while (true) {
6780  switch (*c) {
6781  case '#':
6784  break;
6785  case '0': flags |= QLocaleData::ZeroPadded; break;
6786  case '-': flags |= QLocaleData::LeftAdjusted; break;
6787  case ' ': flags |= QLocaleData::BlankBeforePositive; break;
6788  case '+': flags |= QLocaleData::AlwaysShowSign; break;
6789  case '\'': flags |= QLocaleData::GroupDigits; break;
6790  default: return flags;
6791  }
6792  ++c;
6793  }
6794 }
6795 
6796 static int parse_field_width(const char *&c, qsizetype size)
6797 {
6798  Q_ASSERT(qIsDigit(*c));
6799  const char *const stop = c + size;
6800 
6801  // can't be negative - started with a digit
6802  // contains at least one digit
6803  const char *endp;
6804  bool ok;
6805  const qulonglong result = qstrntoull(c, size, &endp, 10, &ok);
6806  c = endp;
6807  // preserve Qt 5.5 behavior of consuming all digits, no matter how many
6808  while (c < stop && qIsDigit(*c))
6809  ++c;
6810  return ok && result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0;
6811 }
6812 
6814 
6815 static inline bool can_consume(const char * &c, char ch) noexcept
6816 {
6817  if (*c == ch) {
6818  ++c;
6819  return true;
6820  }
6821  return false;
6822 }
6823 
6824 static LengthMod parse_length_modifier(const char * &c) noexcept
6825 {
6826  switch (*c++) {
6827  case 'h': return can_consume(c, 'h') ? lm_hh : lm_h;
6828  case 'l': return can_consume(c, 'l') ? lm_ll : lm_l;
6829  case 'L': return lm_L;
6830  case 'j': return lm_j;
6831  case 'z':
6832  case 'Z': return lm_z;
6833  case 't': return lm_t;
6834  }
6835  --c; // don't consume *c - it wasn't a flag
6836  return lm_none;
6837 }
6838 
6853 QString QString::vasprintf(const char *cformat, va_list ap)
6854 {
6855  if (!cformat || !*cformat) {
6856  // Qt 1.x compat
6857  return fromLatin1("");
6858  }
6859 
6860  // Parse cformat
6861 
6862  QString result;
6863  const char *c = cformat;
6864  const char *formatEnd = cformat + qstrlen(cformat);
6865  for (;;) {
6866  // Copy non-escape chars to result
6867  const char *cb = c;
6868  while (*c != '\0' && *c != '%')
6869  c++;
6870  append_utf8(result, cb, qsizetype(c - cb));
6871 
6872  if (*c == '\0')
6873  break;
6874 
6875  // Found '%'
6876  const char *escape_start = c;
6877  ++c;
6878 
6879  if (*c == '\0') {
6880  result.append(QLatin1Char('%')); // a % at the end of the string - treat as non-escape text
6881  break;
6882  }
6883  if (*c == '%') {
6884  result.append(QLatin1Char('%')); // %%
6885  ++c;
6886  continue;
6887  }
6888 
6889  uint flags = parse_flag_characters(c);
6890 
6891  if (*c == '\0') {
6892  result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
6893  break;
6894  }
6895 
6896  // Parse field width
6897  int width = -1; // -1 means unspecified
6898  if (qIsDigit(*c)) {
6899  width = parse_field_width(c, formatEnd - c);
6900  } else if (*c == '*') { // can't parse this in another function, not portably, at least
6901  width = va_arg(ap, int);
6902  if (width < 0)
6903  width = -1; // treat all negative numbers as unspecified
6904  ++c;
6905  }
6906 
6907  if (*c == '\0') {
6908  result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
6909  break;
6910  }
6911 
6912  // Parse precision
6913  int precision = -1; // -1 means unspecified
6914  if (*c == '.') {
6915  ++c;
6916  if (qIsDigit(*c)) {
6917  precision = parse_field_width(c, formatEnd - c);
6918  } else if (*c == '*') { // can't parse this in another function, not portably, at least
6919  precision = va_arg(ap, int);
6920  if (precision < 0)
6921  precision = -1; // treat all negative numbers as unspecified
6922  ++c;
6923  }
6924  }
6925 
6926  if (*c == '\0') {
6927  result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
6928  break;
6929  }
6930 
6931  const LengthMod length_mod = parse_length_modifier(c);
6932 
6933  if (*c == '\0') {
6934  result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text
6935  break;
6936  }
6937 
6938  // Parse the conversion specifier and do the conversion
6939  QString subst;
6940  switch (*c) {
6941  case 'd':
6942  case 'i': {
6943  qint64 i;
6944  switch (length_mod) {
6945  case lm_none: i = va_arg(ap, int); break;
6946  case lm_hh: i = va_arg(ap, int); break;
6947  case lm_h: i = va_arg(ap, int); break;
6948  case lm_l: i = va_arg(ap, long int); break;
6949  case lm_ll: i = va_arg(ap, qint64); break;
6950  case lm_j: i = va_arg(ap, long int); break;
6951 
6952  /* ptrdiff_t actually, but it should be the same for us */
6953  case lm_z: i = va_arg(ap, qsizetype); break;
6954  case lm_t: i = va_arg(ap, qsizetype); break;
6955  default: i = 0; break;
6956  }
6958  ++c;
6959  break;
6960  }
6961  case 'o':
6962  case 'u':
6963  case 'x':
6964  case 'X': {
6965  quint64 u;
6966  switch (length_mod) {
6967  case lm_none: u = va_arg(ap, uint); break;
6968  case lm_hh: u = va_arg(ap, uint); break;
6969  case lm_h: u = va_arg(ap, uint); break;
6970  case lm_l: u = va_arg(ap, ulong); break;
6971  case lm_ll: u = va_arg(ap, quint64); break;
6972  case lm_t: u = va_arg(ap, size_t); break;
6973  case lm_z: u = va_arg(ap, size_t); break;
6974  default: u = 0; break;
6975  }
6976 
6977  if (qIsUpper(*c))
6979 
6980  int base = 10;
6981  switch (qToLower(*c)) {
6982  case 'o':
6983  base = 8; break;
6984  case 'u':
6985  base = 10; break;
6986  case 'x':
6987  base = 16; break;
6988  default: break;
6989  }
6991  ++c;
6992  break;
6993  }
6994  case 'E':
6995  case 'e':
6996  case 'F':
6997  case 'f':
6998  case 'G':
6999  case 'g':
7000  case 'A':
7001  case 'a': {
7002  double d;
7003  if (length_mod == lm_L)
7004  d = va_arg(ap, long double); // not supported - converted to a double
7005  else
7006  d = va_arg(ap, double);
7007 
7008  if (qIsUpper(*c))
7010 
7012  switch (qToLower(*c)) {
7013  case 'e': form = QLocaleData::DFExponent; break;
7014  case 'a': // not supported - decimal form used instead
7015  case 'f': form = QLocaleData::DFDecimal; break;
7016  case 'g': form = QLocaleData::DFSignificantDigits; break;
7017  default: break;
7018  }
7020  ++c;
7021  break;
7022  }
7023  case 'c': {
7024  if (length_mod == lm_l)
7025  subst = QChar::fromUcs2(va_arg(ap, int));
7026  else
7027  subst = QLatin1Char((uchar) va_arg(ap, int));
7028  ++c;
7029  break;
7030  }
7031  case 's': {
7032  if (length_mod == lm_l) {
7033  const ushort *buff = va_arg(ap, const ushort*);
7034  const ushort *ch = buff;
7035  while (precision != 0 && *ch != 0) {
7036  ++ch;
7037  --precision;
7038  }
7039  subst.setUtf16(buff, ch - buff);
7040  } else if (precision == -1) {
7041  subst = QString::fromUtf8(va_arg(ap, const char*));
7042  } else {
7043  const char *buff = va_arg(ap, const char*);
7044  subst = QString::fromUtf8(buff, qstrnlen(buff, precision));
7045  }
7046  ++c;
7047  break;
7048  }
7049  case 'p': {
7050  void *arg = va_arg(ap, void*);
7051  const quint64 i = reinterpret_cast<quintptr>(arg);
7054  ++c;
7055  break;
7056  }
7057  case 'n':
7058  switch (length_mod) {
7059  case lm_hh: {
7060  signed char *n = va_arg(ap, signed char*);
7061  *n = result.length();
7062  break;
7063  }
7064  case lm_h: {
7065  short int *n = va_arg(ap, short int*);
7066  *n = result.length();
7067  break;
7068  }
7069  case lm_l: {
7070  long int *n = va_arg(ap, long int*);
7071  *n = result.length();
7072  break;
7073  }
7074  case lm_ll: {
7075  qint64 *n = va_arg(ap, qint64*);
7076  *n = result.length();
7077  break;
7078  }
7079  default: {
7080  int *n = va_arg(ap, int*);
7081  *n = result.length();
7082  break;
7083  }
7084  }
7085  ++c;
7086  break;
7087 
7088  default: // bad escape, treat as non-escape text
7089  for (const char *cc = escape_start; cc != c; ++cc)
7090  result.append(QLatin1Char(*cc));
7091  continue;
7092  }
7093 
7095  result.append(subst.leftJustified(width));
7096  else
7097  result.append(subst.rightJustified(width));
7098  }
7099 
7100  return result;
7101 }
7102 
7128 {
7129  return toIntegral_helper<qlonglong>(*this, ok, base);
7130 }
7131 
7132 qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
7133 {
7134 #if defined(QT_CHECK_RANGE)
7135  if (base != 0 && (base < 2 || base > 36)) {
7136  qWarning("QString::toULongLong: Invalid base (%d)", base);
7137  base = 10;
7138  }
7139 #endif
7140 
7142 }
7143 
7144 
7170 {
7171  return toIntegral_helper<qulonglong>(*this, ok, base);
7172 }
7173 
7174 qulonglong QString::toIntegral_helper(QStringView string, bool *ok, uint base)
7175 {
7176 #if defined(QT_CHECK_RANGE)
7177  if (base != 0 && (base < 2 || base > 36)) {
7178  qWarning("QString::toULongLong: Invalid base (%d)", base);
7179  base = 10;
7180  }
7181 #endif
7182 
7184 }
7185 
7374 double QString::toDouble(bool *ok) const
7375 {
7377 }
7378 
7409 float QString::toFloat(bool *ok) const
7410 {
7412 }
7413 
7449 {
7450  return *this = number(n, base);
7451 }
7452 
7457 {
7458  return *this = number(n, base);
7459 }
7460 
7481 {
7482  return *this = number(n, format, precision);
7483 }
7484 
7521 {
7522  return number(qlonglong(n), base);
7523 }
7524 
7531 {
7532  return number(qulonglong(n), base);
7533 }
7534 
7539 {
7540  return number(qlonglong(n), base);
7541 }
7542 
7547 {
7548  return number(qulonglong(n), base);
7549 }
7550 
7555 {
7556 #if defined(QT_CHECK_RANGE)
7557  if (base < 2 || base > 36) {
7558  qWarning("QString::setNum: Invalid base (%d)", base);
7559  base = 10;
7560  }
7561 #endif
7562  bool negative = n < 0;
7563  /*
7564  Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
7565  taking an absolute value has to take a slight detour.
7566  */
7567  return qulltoBasicLatin(negative ? 1u + qulonglong(-(n + 1)) : qulonglong(n), base, negative);
7568 }
7569 
7574 {
7575 #if defined(QT_CHECK_RANGE)
7576  if (base < 2 || base > 36) {
7577  qWarning("QString::setNum: Invalid base (%d)", base);
7578  base = 10;
7579  }
7580 #endif
7581  return qulltoBasicLatin(n, base, false);
7582 }
7583 
7584 
7597 {
7599 
7600  switch (qToLower(format)) {
7601  case 'f':
7603  break;
7604  case 'e':
7606  break;
7607  case 'g':
7609  break;
7610  default:
7611 #if defined(QT_CHECK_RANGE)
7612  qWarning("QString::setNum: Invalid format char '%c'", format);
7613 #endif
7614  break;
7615  }
7616 
7617  return qdtoBasicLatin(n, form, precision, qIsUpper(format));
7618 }
7619 
7620 namespace {
7621 template<class ResultList, class StringSource>
7622 static ResultList splitString(const StringSource &source, QStringView sep,
7623  Qt::SplitBehavior behavior, Qt::CaseSensitivity cs)
7624 {
7625  ResultList list;
7626  typename StringSource::size_type start = 0;
7627  typename StringSource::size_type end;
7628  typename StringSource::size_type extra = 0;
7629  while ((end = QtPrivate::findString(QStringView(source.constData(), source.size()), start + extra, sep, cs)) != -1) {
7630  if (start != end || behavior == Qt::KeepEmptyParts)
7631  list.append(source.sliced(start, end - start));
7632  start = end + sep.size();
7633  extra = (sep.size() == 0 ? 1 : 0);
7634  }
7635  if (start != source.size() || behavior == Qt::KeepEmptyParts)
7636  list.append(source.sliced(start));
7637  return list;
7638 }
7639 
7640 } // namespace
7641 
7672 QStringList QString::split(const QString &sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
7673 {
7674  return splitString<QStringList>(*this, sep, behavior, cs);
7675 }
7676 
7681 QStringList QString::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
7682 {
7683  return splitString<QStringList>(*this, QStringView(&sep, 1), behavior, cs);
7684 }
7685 
7702 QList<QStringView> QStringView::split(QStringView sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
7703 {
7704  return splitString<QList<QStringView>>(QStringView(*this), sep, behavior, cs);
7705 }
7706 
7707 QList<QStringView> QStringView::split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const
7708 {
7709  return split(QStringView(&sep, 1), behavior, cs);
7710 }
7711 
7712 #if QT_CONFIG(regularexpression)
7713 namespace {
7714 template<class ResultList, typename String>
7715 static ResultList splitString(const String &source, const QRegularExpression &re,
7716  Qt::SplitBehavior behavior)
7717 {
7718  ResultList list;
7719  if (!re.isValid()) {
7720  qWarning("QString::split: invalid QRegularExpression object");
7721  return list;
7722  }
7723 
7724  qsizetype start = 0;
7725  qsizetype end = 0;
7727  while (iterator.hasNext()) {
7728  QRegularExpressionMatch match = iterator.next();
7729  end = match.capturedStart();
7730  if (start != end || behavior == Qt::KeepEmptyParts)
7731  list.append(source.sliced(start, end - start));
7732  start = match.capturedEnd();
7733  }
7734 
7735  if (start != source.size() || behavior == Qt::KeepEmptyParts)
7736  list.append(source.sliced(start));
7737 
7738  return list;
7739 }
7740 } // namespace
7741 
7769 QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
7770 {
7771  return splitString<QStringList>(*this, re, behavior);
7772 }
7773 
7786 QList<QStringView> QStringView::split(const QRegularExpression &re, Qt::SplitBehavior behavior) const
7787 {
7788  return splitString<QList<QStringView>>(*this, re, behavior);
7789 }
7790 
7791 #endif // QT_CONFIG(regularexpression)
7792 
7819 {
7820  if (d.size == 0)
7821  return *this;
7822 
7823  if (times <= 1) {
7824  if (times == 1)
7825  return *this;
7826  return QString();
7827  }
7828 
7829  const qsizetype resultSize = times * d.size;
7830 
7831  QString result;
7832  result.reserve(resultSize);
7833  if (result.capacity() != resultSize)
7834  return QString(); // not enough memory
7835 
7836  memcpy(result.d.data(), d.data(), d.size * sizeof(QChar));
7837 
7838  qsizetype sizeSoFar = d.size;
7839  char16_t *end = result.d.data() + sizeSoFar;
7840 
7841  const qsizetype halfResultSize = resultSize >> 1;
7842  while (sizeSoFar <= halfResultSize) {
7843  memcpy(end, result.d.data(), sizeSoFar * sizeof(QChar));
7844  end += sizeSoFar;
7845  sizeSoFar <<= 1;
7846  }
7847  memcpy(end, result.d.data(), (resultSize - sizeSoFar) * sizeof(QChar));
7848  result.d.data()[resultSize] = '\0';
7849  result.d.size = resultSize;
7850  return result;
7851 }
7852 
7854 {
7855  {
7856  // check if it's fully ASCII first, because then we have no work
7857  auto start = reinterpret_cast<const char16_t *>(data->constData());
7858  const char16_t *p = start + from;
7859  if (isAscii_helper(p, p + data->length() - from))
7860  return;
7861  if (p > start + from)
7862  from = p - start - 1; // need one before the non-ASCII to perform NFC
7863  }
7864 
7867  } else if (int(version) <= NormalizationCorrectionsVersionMax) {
7868  const QString &s = *data;
7869  QChar *d = nullptr;
7870  for (int i = 0; i < NumNormalizationCorrections; ++i) {
7871  const NormalizationCorrection &n = uc_normalization_corrections[i];
7872  if (n.version > version) {
7873  qsizetype pos = from;
7874  if (QChar::requiresSurrogates(n.ucs4)) {
7875  char16_t ucs4High = QChar::highSurrogate(n.ucs4);
7876  char16_t ucs4Low = QChar::lowSurrogate(n.ucs4);
7877  char16_t oldHigh = QChar::highSurrogate(n.old_mapping);
7878  char16_t oldLow = QChar::lowSurrogate(n.old_mapping);
7879  while (pos < s.length() - 1) {
7880  if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) {
7881  if (!d)
7882  d = data->data();
7883  d[pos] = QChar(oldHigh);
7884  d[++pos] = QChar(oldLow);
7885  }
7886  ++pos;
7887  }
7888  } else {
7889  while (pos < s.length()) {
7890  if (s.at(pos).unicode() == n.ucs4) {
7891  if (!d)
7892  d = data->data();
7893  d[pos] = QChar(n.old_mapping);
7894  }
7895  ++pos;
7896  }
7897  }
7898  }
7899  }
7900  }
7901 
7902  if (normalizationQuickCheckHelper(data, mode, from, &from))
7903  return;
7904 
7905  decomposeHelper(data, mode < QString::NormalizationForm_KD, version, from);
7906 
7907  canonicalOrderHelper(data, version, from);
7908 
7910  return;
7911 
7912  composeHelper(data, version, from);
7913 }
7914 
7920 {
7921  QString copy = *this;
7922  qt_string_normalize(&copy, mode, version, 0);
7923  return copy;
7924 }
7925 
7926 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
7927 static void checkArgEscape(QStringView s)
7928 {
7929  // If we're in here, it means that qArgDigitValue has accepted the
7930  // digit. We can skip the check in case we already know it will
7931  // succeed.
7932  if (!supportUnicodeDigitValuesInArg())
7933  return;
7934 
7935  const auto isNonAsciiDigit = [](QChar c) {
7936  return c.unicode() < u'0' || c.unicode() > u'9';
7937  };
7938 
7939  if (std::any_of(s.begin(), s.end(), isNonAsciiDigit)) {
7940  const auto accumulateDigit = [](int partial, QChar digit) {
7941  return partial * 10 + digit.digitValue();
7942  };
7943  const int parsedNumber = std::accumulate(s.begin(), s.end(), 0, accumulateDigit);
7944 
7945  qWarning("QString::arg(): the replacement \"%%%ls\" contains non-ASCII digits;\n"
7946  " it is currently being interpreted as the %d-th substitution.\n"
7947  " This is deprecated; support for non-ASCII digits will be dropped\n"
7948  " in a future version of Qt.",
7949  qUtf16Printable(s.toString()),
7950  parsedNumber);
7951  }
7952 }
7953 #endif
7954 
7956 {
7957  int min_escape; // lowest escape sequence number
7958  int occurrences; // number of occurrences of the lowest escape sequence number
7959  int locale_occurrences; // number of occurrences of the lowest escape sequence number that
7960  // contain 'L'
7961  int escape_len; // total length of escape sequences which will be replaced
7962 };
7963 
7964 static ArgEscapeData findArgEscapes(QStringView s)
7965 {
7966  const QChar *uc_begin = s.begin();
7967  const QChar *uc_end = s.end();
7968 
7969  ArgEscapeData d;
7970 
7971  d.min_escape = INT_MAX;
7972  d.occurrences = 0;
7973  d.escape_len = 0;
7974  d.locale_occurrences = 0;
7975 
7976  const QChar *c = uc_begin;
7977  while (c != uc_end) {
7978  while (c != uc_end && c->unicode() != '%')
7979  ++c;
7980 
7981  if (c == uc_end)
7982  break;
7983  const QChar *escape_start = c;
7984  if (++c == uc_end)
7985  break;
7986 
7987  bool locale_arg = false;
7988  if (c->unicode() == 'L') {
7989  locale_arg = true;
7990  if (++c == uc_end)
7991  break;
7992  }
7993 
7994  int escape = qArgDigitValue(*c);
7995  if (escape == -1)
7996  continue;
7997 
7998  // ### Qt 7: do not allow anything but ASCII digits
7999  // in arg()'s replacements.
8000 #if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
8001  const QChar *escapeBegin = c;
8002  const QChar *escapeEnd = escapeBegin + 1;
8003 #endif
8004 
8005  ++c;
8006 
8007  if (c != uc_end) {
8008  const int next_escape = qArgDigitValue(*c);
8009  if (next_escape != -1) {
8010  escape = (10 * escape) + next_escape;
8011  ++c;
8012 #if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
8013  ++escapeEnd;
8014 #endif
8015  }
8016  }
8017 
8018 #if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
8019  checkArgEscape(QStringView(escapeBegin, escapeEnd));
8020 #endif
8021 
8022  if (escape > d.min_escape)
8023  continue;
8024 
8025  if (escape < d.min_escape) {
8026  d.min_escape = escape;
8027  d.occurrences = 0;
8028  d.escape_len = 0;
8029  d.locale_occurrences = 0;
8030  }
8031 
8032  ++d.occurrences;
8033  if (locale_arg)
8034  ++d.locale_occurrences;
8035  d.escape_len += c - escape_start;
8036  }
8037  return d;
8038 }
8039 
8040 static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetype field_width,
8041  QStringView arg, QStringView larg, QChar fillChar)
8042 {
8043  // Negative field-width for right-padding, positive for left-padding:
8044  const qsizetype abs_field_width = qAbs(field_width);
8045  const qsizetype result_len =
8046  s.length() - d.escape_len
8047  + (d.occurrences - d.locale_occurrences) * qMax(abs_field_width, arg.length())
8048  + d.locale_occurrences * qMax(abs_field_width, larg.length());
8049 
8050  QString result(result_len, Qt::Uninitialized);
8051  QChar *rc = const_cast<QChar *>(result.unicode());
8052  QChar *const result_end = rc + result_len;
8053  int repl_cnt = 0;
8054 
8055  const QChar *c = s.begin();
8056  const QChar *const uc_end = s.end();
8057  while (c != uc_end) {
8058  Q_ASSERT(d.occurrences > repl_cnt);
8059  /* We don't have to check increments of c against uc_end because, as
8060  long as d.occurrences > repl_cnt, we KNOW there are valid escape
8061  sequences remaining. */
8062 
8063  const QChar *text_start = c;
8064  while (c->unicode() != '%')
8065  ++c;
8066 
8067  const QChar *escape_start = c++;
8068  const bool localize = c->unicode() == 'L';
8069  if (localize)
8070  ++c;
8071 
8072  int escape = qArgDigitValue(*c);
8073  if (escape != -1 && c + 1 != uc_end) {
8074  const int digit = qArgDigitValue(c[1]);
8075  if (digit != -1) {
8076  ++c;
8077  escape = 10 * escape + digit;
8078  }
8079  }
8080 
8081  if (escape != d.min_escape) {
8082  memcpy(rc, text_start, (c - text_start) * sizeof(QChar));
8083  rc += c - text_start;
8084  } else {
8085  ++c;
8086 
8087  memcpy(rc, text_start, (escape_start - text_start) * sizeof(QChar));
8088  rc += escape_start - text_start;
8089 
8090  const QStringView use = localize ? larg : arg;
8091  const qsizetype pad_chars = abs_field_width - use.length();
8092  // (If negative, relevant loops are no-ops: no need to check.)
8093 
8094  if (field_width > 0) { // left padded
8095  for (qsizetype i = 0; i < pad_chars; ++i)
8096  *rc++ = fillChar;
8097  }
8098 
8099  memcpy(rc, use.data(), use.length() * sizeof(QChar));
8100  rc += use.length();
8101 
8102  if (field_width < 0) { // right padded
8103  for (qsizetype i = 0; i < pad_chars; ++i)
8104  *rc++ = fillChar;
8105  }
8106 
8107  if (++repl_cnt == d.occurrences) {
8108  memcpy(rc, c, (uc_end - c) * sizeof(QChar));
8109  rc += uc_end - c;
8110  Q_ASSERT(rc == result_end);
8111  c = uc_end;
8112  }
8113  }
8114  }
8115  Q_ASSERT(rc == result_end);
8116 
8117  return result;
8118 }
8119 
8120 #if QT_STRINGVIEW_LEVEL < 2
8150 QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
8151 {
8152  return arg(qToStringViewIgnoringNull(a), fieldWidth, fillChar);
8153 }
8154 #endif // QT_STRINGVIEW_LEVEL < 2
8155 
8188 QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
8189 {
8190  ArgEscapeData d = findArgEscapes(*this);
8191 
8192  if (Q_UNLIKELY(d.occurrences == 0)) {
8193  qWarning("QString::arg: Argument missing: %ls, %ls", qUtf16Printable(*this),
8194  qUtf16Printable(a.toString()));
8195  return *this;
8196  }
8197  return replaceArgEscapes(*this, d, fieldWidth, a, a, fillChar);
8198 }
8199 
8224 QString QString::arg(QLatin1String a, int fieldWidth, QChar fillChar) const
8225 {
8227  qt_from_latin1(utf16.data(), a.data(), a.size());
8228  return arg(QStringView(utf16.data(), utf16.size()), fieldWidth, fillChar);
8229 }
8230 
8318 QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
8319 {
8320  ArgEscapeData d = findArgEscapes(*this);
8321 
8322  if (d.occurrences == 0) {
8323  qWarning() << "QString::arg: Argument missing:" << *this << ',' << a;
8324  return *this;
8325  }
8326 
8327  unsigned flags = QLocaleData::NoFlags;
8328  // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
8329  if (fillChar == QLatin1Char('0'))
8331 
8332  QString arg;
8333  if (d.occurrences > d.locale_occurrences) {
8334  arg = QLocaleData::c()->longLongToString(a, -1, base, fieldWidth, flags);
8335  Q_ASSERT(fillChar != QLatin1Char('0') || !qIsFinite(a)
8336  || fieldWidth <= arg.length());
8337  }
8338 
8339  QString localeArg;
8340  if (d.locale_occurrences > 0) {
8341  QLocale locale;
8342  if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
8344  localeArg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags);
8345  Q_ASSERT(fillChar != QLatin1Char('0') || !qIsFinite(a)
8346  || fieldWidth <= localeArg.length());
8347  }
8348 
8349  return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
8350 }
8351 
8366 QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) const
8367 {
8368  ArgEscapeData d = findArgEscapes(*this);
8369 
8370  if (d.occurrences == 0) {
8371  qWarning() << "QString::arg: Argument missing:" << *this << ',' << a;
8372  return *this;
8373  }
8374 
8375  unsigned flags = QLocaleData::NoFlags;
8376  // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
8377  if (fillChar == QLatin1Char('0'))
8379 
8380  QString arg;
8381  if (d.occurrences > d.locale_occurrences) {
8382  arg = QLocaleData::c()->unsLongLongToString(a, -1, base, fieldWidth, flags);
8383  Q_ASSERT(fillChar != QLatin1Char('0') || !qIsFinite(a)
8384  || fieldWidth <= arg.length());
8385  }
8386 
8387  QString localeArg;
8388  if (d.locale_occurrences > 0) {
8389  QLocale locale;
8390  if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
8392  localeArg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags);
8393  Q_ASSERT(fillChar != QLatin1Char('0') || !qIsFinite(a)
8394  || fieldWidth <= localeArg.length());
8395  }
8396 
8397  return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
8398 }
8399 
8436 QString QString::arg(QChar a, int fieldWidth, QChar fillChar) const
8437 {
8438  return arg(QStringView{&a, 1}, fieldWidth, fillChar);
8439 }
8440 
8446 QString QString::arg(char a, int fieldWidth, QChar fillChar) const
8447 {
8448  return arg(QLatin1Char(a), fieldWidth, fillChar);
8449 }
8450 
8466 QString QString::arg(double a, int fieldWidth, char format, int precision, QChar fillChar) const
8467 {
8468  ArgEscapeData d = findArgEscapes(*this);
8469 
8470  if (d.occurrences == 0) {
8471  qWarning("QString::arg: Argument missing: %s, %g", toLocal8Bit().data(), a);
8472  return *this;
8473  }
8474 
8475  unsigned flags = QLocaleData::NoFlags;
8476  // ZeroPadded sorts out left-padding when the fill is zero, to the right of sign:
8477  if (fillChar == QLatin1Char('0'))
8479 
8480  if (qIsUpper(format))
8482 
8484  switch (qToLower(format)) {
8485  case 'f':
8487  break;
8488  case 'e':
8490  break;
8491  case 'g':
8493  break;
8494  default:
8495 #if defined(QT_CHECK_RANGE)
8496  qWarning("QString::arg: Invalid format char '%c'", format);
8497 #endif
8498  break;
8499  }
8500 
8501  QString arg;
8502  if (d.occurrences > d.locale_occurrences) {
8503  arg = QLocaleData::c()->doubleToString(a, precision, form, fieldWidth,
8505  Q_ASSERT(fillChar != QLatin1Char('0') || !qIsFinite(a)
8506  || fieldWidth <= arg.length());
8507  }
8508 
8509  QString localeArg;
8510  if (d.locale_occurrences > 0) {
8511  QLocale locale;
8512 
8513  const QLocale::NumberOptions numberOptions = locale.numberOptions();
8514  if (!(numberOptions & QLocale::OmitGroupSeparator))
8516  if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
8518  if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
8520  localeArg = locale.d->m_data->doubleToString(a, precision, form, fieldWidth, flags);
8521  Q_ASSERT(fillChar != QLatin1Char('0') || !qIsFinite(a)
8522  || fieldWidth <= localeArg.length());
8523  }
8524 
8525  return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
8526 }
8527 
8528 static inline char16_t to_unicode(const QChar c) { return c.unicode(); }
8529 static inline char16_t to_unicode(const char c) { return QLatin1Char{c}.unicode(); }
8530 
8531 template <typename Char>
8532 static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999)
8533 {
8534  int i = *pos;
8535  ++i;
8536  if (i < len && uc[i] == QLatin1Char('L'))
8537  ++i;
8538  if (i < len) {
8539  int escape = to_unicode(uc[i]) - '0';
8540  if (uint(escape) >= 10U)
8541  return -1;
8542  ++i;
8543  while (i < len) {
8544  int digit = to_unicode(uc[i]) - '0';
8545  if (uint(digit) >= 10U)
8546  break;
8547  escape = (escape * 10) + digit;
8548  ++i;
8549  }
8550  if (escape <= maxNumber) {
8551  *pos = i;
8552  return escape;
8553  }
8554  }
8555  return -1;
8556 }
8557 
8558 /*
8559  Algorithm for multiArg:
8560 
8561  1. Parse the string as a sequence of verbatim text and placeholders (%L?\d{,3}).
8562  The L is parsed and accepted for compatibility with non-multi-arg, but since
8563  multiArg only accepts strings as replacements, the localization request can
8564  be safely ignored.
8565  2. The result of step (1) is a list of (string-ref,int)-tuples. The string-ref
8566  either points at text to be copied verbatim (in which case the int is -1),
8567  or, initially, at the textual representation of the placeholder. In that case,
8568  the int contains the numerical number as parsed from the placeholder.
8569  3. Next, collect all the non-negative ints found, sort them in ascending order and
8570  remove duplicates.
8571  3a. If the result has more entries than multiArg() was given replacement strings,
8572  we have found placeholders we can't satisfy with replacement strings. That is
8573  fine (there could be another .arg() call coming after this one), so just
8574  truncate the result to the number of actual multiArg() replacement strings.
8575  3b. If the result has less entries than multiArg() was given replacement strings,
8576  the string is missing placeholders. This is an error that the user should be
8577  warned about.
8578  4. The result of step (3) is a mapping from the index of any replacement string to
8579  placeholder number. This is the wrong way around, but since placeholder
8580  numbers could get as large as 999, while we typically don't have more than 9
8581  replacement strings, we trade 4K of sparsely-used memory for doing a reverse lookup
8582  each time we need to map a placeholder number to a replacement string index
8583  (that's a linear search; but still *much* faster than using an associative container).
8584  5. Next, for each of the tuples found in step (1), do the following:
8585  5a. If the int is negative, do nothing.
8586  5b. Otherwise, if the int is found in the result of step (3) at index I, replace
8587  the string-ref with a string-ref for the (complete) I'th replacement string.
8588  5c. Otherwise, do nothing.
8589  6. Concatenate all string refs into a single result string.
8590 */
8591 
8592 namespace {
8593 struct Part
8594 {
8595  Part() = default; // for QVarLengthArray; do not use
8596  constexpr Part(QStringView s, int num = -1)
8597  : tag{QtPrivate::ArgBase::U16}, number{num}, data{s.utf16()}, size{s.size()} {}
8598  constexpr Part(QLatin1String s, int num = -1)
8599  : tag{QtPrivate::ArgBase::L1}, number{num}, data{s.data()}, size{s.size()} {}
8600 
8601  void reset(QStringView s) noexcept { *this = {s, number}; }
8602  void reset(QLatin1String s) noexcept { *this = {s, number}; }
8603 
8605  int number;
8606  const void *data;
8607  qsizetype size;
8608 };
8609 } // unnamed namespace
8610 
8612 
8613 namespace {
8614 
8615 enum { ExpectedParts = 32 };
8616 
8617 typedef QVarLengthArray<Part, ExpectedParts> ParseResult;
8618 typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap;
8619 
8620 template <typename StringView>
8621 static ParseResult parseMultiArgFormatString(StringView s)
8622 {
8623  ParseResult result;
8624 
8625  const auto uc = s.data();
8626  const auto len = s.size();
8627  const auto end = len - 1;
8628  qsizetype i = 0;
8629  qsizetype last = 0;
8630 
8631  while (i < end) {
8632  if (uc[i] == QLatin1Char('%')) {
8633  qsizetype percent = i;
8634  int number = getEscape(uc, &i, len);
8635  if (number != -1) {
8636  if (last != percent)
8637  result.push_back(Part{s.sliced(last, percent - last)}); // literal text (incl. failed placeholders)
8638  result.push_back(Part{s.sliced(percent, i - percent), number}); // parsed placeholder
8639  last = i;
8640  continue;
8641  }
8642  }
8643  ++i;
8644  }
8645 
8646  if (last < len)
8647  result.push_back(Part{s.sliced(last, len - last)}); // trailing literal text
8648 
8649  return result;
8650 }
8651 
8652 static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult &parts)
8653 {
8654  ArgIndexToPlaceholderMap result;
8655 
8656  for (Part part : parts) {
8657  if (part.number >= 0)
8658  result.push_back(part.number);
8659  }
8660 
8661  std::sort(result.begin(), result.end());
8662  result.erase(std::unique(result.begin(), result.end()),
8663  result.end());
8664 
8665  return result;
8666 }
8667 
8668 static qsizetype resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QtPrivate::ArgBase *args[])
8669 {
8670  using namespace QtPrivate;
8671  qsizetype totalSize = 0;
8672  for (Part &part : parts) {
8673  if (part.number != -1) {
8674  const auto it = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), part.number);
8675  if (it != argIndexToPlaceholderMap.end()) {
8676  const auto &arg = *args[it - argIndexToPlaceholderMap.begin()];
8677  switch (arg.tag) {
8678  case ArgBase::L1:
8679  part.reset(static_cast<const QLatin1StringArg&>(arg).string);
8680  break;
8681  case ArgBase::U8:
8682  Q_UNREACHABLE(); // waiting for QUtf8String...
8683  break;
8684  case ArgBase::U16:
8685  part.reset(static_cast<const QStringViewArg&>(arg).string);
8686  break;
8687  }
8688  }
8689  }
8690  totalSize += part.size;
8691  }
8692  return totalSize;
8693 }
8694 
8695 } // unnamed namespace
8696 
8697 Q_ALWAYS_INLINE QString to_string(QLatin1String s) noexcept { return s; }
8698 Q_ALWAYS_INLINE QString to_string(QStringView s) noexcept { return s.toString(); }
8699 
8700 template <typename StringView>
8701 static QString argToQStringImpl(StringView pattern, size_t numArgs, const QtPrivate::ArgBase **args)
8702 {
8703  // Step 1-2 above
8704  ParseResult parts = parseMultiArgFormatString(pattern);
8705 
8706  // 3-4
8707  ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);
8708 
8709  if (static_cast<size_t>(argIndexToPlaceholderMap.size()) > numArgs) // 3a
8710  argIndexToPlaceholderMap.resize(qsizetype(numArgs));
8711  else if (Q_UNLIKELY(static_cast<size_t>(argIndexToPlaceholderMap.size()) < numArgs)) // 3b
8712  qWarning("QString::arg: %d argument(s) missing in %ls",
8713  int(numArgs - argIndexToPlaceholderMap.size()), qUtf16Printable(to_string(pattern)));
8714 
8715  // 5
8716  const qsizetype totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args);
8717 
8718  // 6:
8719  QString result(totalSize, Qt::Uninitialized);
8720  auto out = const_cast<QChar*>(result.constData());
8721 
8722  for (Part part : parts) {
8723  switch (part.tag) {
8725  if (part.size) {
8726  qt_from_latin1(reinterpret_cast<char16_t*>(out),
8727  reinterpret_cast<const char*>(part.data), part.size);
8728  }
8729  break;
8731  Q_UNREACHABLE(); // waiting for QUtf8String
8732  break;
8734  if (part.size)
8735  memcpy(out, part.data, part.size * sizeof(QChar));
8736  break;
8737  }
8738  out += part.size;
8739  }
8740 
8741  return result;
8742 }
8743 
8745 {
8746  return argToQStringImpl(pattern, n, args);
8747 }
8748 
8750 {
8751  return argToQStringImpl(pattern, n, args);
8752 }
8753 
8759 {
8760  const char16_t *p = d.data();
8761  const char16_t * const end = p + d.size;
8762  while (p < end) {
8763  char16_t uc = *p;
8764  // sort out regions of complex text formatting
8765  if (uc > 0x058f && (uc < 0x1100 || uc > 0xfb0f)) {
8766  return false;
8767  }
8768  p++;
8769  }
8770 
8771  return true;
8772 }
8773 
8781 {
8782  return QtPrivate::isRightToLeft(QStringView(*this));
8783 }
8784 
8884 {
8885  const auto start = std::distance(cbegin(), first);
8886  const auto len = std::distance(first, last);
8887  remove(start, len);
8888  return begin() + start;
8889 }
8890 
8939 {
8940  return QString(DataPointer::fromRawData(const_cast<char16_t *>(reinterpret_cast<const char16_t *>(unicode)), size));
8941 }
8942 
8958 {
8959  if (!unicode || !size) {
8960  clear();
8961  }
8962  *this = fromRawData(unicode, size);
8963  return *this;
8964 }
8965 
10074 #if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
10085 {
10086  if (out.version() == 1) {
10087  out << str.toLatin1();
10088  } else {
10089  if (!str.isNull() || out.version() < 3) {
10090  if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
10091  out.writeBytes(reinterpret_cast<const char *>(str.unicode()),
10092  static_cast<uint>(sizeof(QChar) * str.length()));
10093  } else {
10095  qbswap<sizeof(char16_t)>(str.constData(), str.length(), buffer.data());
10096  out.writeBytes(reinterpret_cast<const char *>(buffer.data()),
10097  static_cast<uint>(sizeof(char16_t) * buffer.size()));
10098  }
10099  } else {
10100  // write null marker
10101  out << (quint32)0xffffffff;
10102  }
10103  }
10104  return out;
10105 }
10106 
10117 {
10118  if (in.version() == 1) {
10119  QByteArray l;
10120  in >> l;
10122  } else {
10123  quint32 bytes = 0;
10124  in >> bytes; // read size of string
10125  if (bytes == 0xffffffff) { // null string
10126  str.clear();
10127  } else if (bytes > 0) { // not empty
10128  if (bytes & 0x1) {
10129  str.clear();
10130  in.setStatus(QDataStream::ReadCorruptData);
10131  return in;
10132  }
10133 
10134  const quint32 Step = 1024 * 1024;
10135  quint32 len = bytes / 2;
10136  quint32 allocated = 0;
10137 
10138  while (allocated < len) {
10139  int blockSize = qMin(Step, len - allocated);
10140  str.resize(allocated + blockSize);
10141  if (in.readRawData(reinterpret_cast<char *>(str.data()) + allocated * 2,
10142  blockSize * 2) != blockSize * 2) {
10143  str.clear();
10144  in.setStatus(QDataStream::ReadPastEnd);
10145  return in;
10146  }
10147  allocated += blockSize;
10148  }
10149 
10150  if ((in.byteOrder() == QDataStream::BigEndian)
10152  char16_t *data = reinterpret_cast<char16_t *>(str.data());
10153  qbswap<sizeof(*data)>(data, len, data);
10154  }
10155  } else {
10156  str = QString(QLatin1String(""));
10157  }
10158  }
10159  return in;
10160 }
10161 #endif // QT_NO_DATASTREAM
10162 
10188 {
10189  int isolateLevel = 0;
10190 
10191  for (QStringIterator i(string); i.hasNext();) {
10192  const char32_t c = i.next();
10193 
10194  switch (QChar::direction(c)) {
10195  case QChar::DirRLI:
10196  case QChar::DirLRI:
10197  case QChar::DirFSI:
10198  ++isolateLevel;
10199  break;
10200  case QChar::DirPDI:
10201  if (isolateLevel)
10202  --isolateLevel;
10203  break;
10204  case QChar::DirL:
10205  if (isolateLevel)
10206  break;
10207  return false;
10208  case QChar::DirR:
10209  case QChar::DirAL:
10210  if (isolateLevel)
10211  break;
10212  return true;
10213  case QChar::DirEN:
10214  case QChar::DirES:
10215  case QChar::DirET:
10216  case QChar::DirAN:
10217  case QChar::DirCS:
10218  case QChar::DirB:
10219  case QChar::DirS:
10220  case QChar::DirWS:
10221  case QChar::DirON:
10222  case QChar::DirLRE:
10223  case QChar::DirLRO:
10224  case QChar::DirRLE:
10225  case QChar::DirRLO:
10226  case QChar::DirPDF:
10227  case QChar::DirNSM:
10228  case QChar::DirBN:
10229  break;
10230  }
10231  }
10232  return false;
10233 }
10234 
10236 {
10237  qsizetype num = 0;
10238  qsizetype i = -1;
10239  if (haystack.size() > 500 && needle.size() > 5) {
10240  QStringMatcher matcher(needle, cs);
10241  while ((i = matcher.indexIn(haystack, i + 1)) != -1)
10242  ++num;
10243  } else {
10244  while ((i = QtPrivate::findString(haystack, i + 1, needle, cs)) != -1)
10245  ++num;
10246  }
10247  return num;
10248 }
10249 
10251 {
10252  qsizetype num = 0;
10253  if (cs == Qt::CaseSensitive) {
10254  for (QChar c : haystack) {
10255  if (c == ch)
10256  ++num;
10257  }
10258  } else {
10259  ch = foldCase(ch);
10260  for (QChar c : haystack) {
10261  if (foldCase(c) == ch)
10262  ++num;
10263  }
10264  }
10265  return num;
10266 }
10267 
10268 template <typename Haystack, typename Needle>
10269 bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
10270 {
10271  if (haystack.isNull())
10272  return needle.isNull();
10273  const auto haystackLen = haystack.size();
10274  const auto needleLen = needle.size();
10275  if (haystackLen == 0)
10276  return needleLen == 0;
10277  if (needleLen > haystackLen)
10278  return false;
10279 
10280  return QtPrivate::compareStrings(haystack.left(needleLen), needle, cs) == 0;
10281 }
10282 
10283 static inline bool qt_starts_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
10284 {
10285  return qt_starts_with_impl(haystack, needle, cs);
10286 }
10287 
10288 static inline bool qt_starts_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
10289 {
10290  return qt_starts_with_impl(haystack, needle, cs);
10291 }
10292 
10293 static inline bool qt_starts_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs)
10294 {
10295  return haystack.size()
10296  && (cs == Qt::CaseSensitive ? haystack.front() == needle
10297  : foldCase(haystack.front()) == foldCase(needle));
10298 }
10299 
10322 {
10323  return qt_starts_with_impl(haystack, needle, cs);
10324 }
10325 
10327 {
10328  return qt_starts_with_impl(haystack, needle, cs);
10329 }
10330 
10332 {
10333  return qt_starts_with_impl(haystack, needle, cs);
10334 }
10335 
10337 {
10338  return qt_starts_with_impl(haystack, needle, cs);
10339 }
10340 
10341 template <typename Haystack, typename Needle>
10342 bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
10343 {
10344  if (haystack.isNull())
10345  return needle.isNull();
10346  const auto haystackLen = haystack.size();
10347  const auto needleLen = needle.size();
10348  if (haystackLen == 0)
10349  return needleLen == 0;
10350  if (haystackLen < needleLen)
10351  return false;
10352 
10353  return QtPrivate::compareStrings(haystack.right(needleLen), needle, cs) == 0;
10354 }
10355 
10356 static inline bool qt_ends_with(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs)
10357 {
10358  return qt_ends_with_impl(haystack, needle, cs);
10359 }
10360 
10361 static inline bool qt_ends_with(QStringView haystack, QLatin1String needle, Qt::CaseSensitivity cs)
10362 {
10363  return qt_ends_with_impl(haystack, needle, cs);
10364 }
10365 
10366 static inline bool qt_ends_with(QStringView haystack, QChar needle, Qt::CaseSensitivity cs)
10367 {
10368  return haystack.size()
10369  && (cs == Qt::CaseSensitive ? haystack.back() == needle
10370  : foldCase(haystack.back()) == foldCase(needle));
10371 }
10372 
10395 {
10396  return qt_ends_with_impl(haystack, needle, cs);
10397 }
10398 
10400 {
10401  return qt_ends_with_impl(haystack, needle, cs);
10402 }
10403 
10405 {
10406  return qt_ends_with_impl(haystack, needle, cs);
10407 }
10408 
10410 {
10411  return qt_ends_with_impl(haystack, needle, cs);
10412 }
10413 
10415 {
10416  const qsizetype l = haystack0.size();
10417  const qsizetype sl = needle0.size();
10418  if (from < 0)
10419  from += l;
10420  if (std::size_t(sl + from) > std::size_t(l))
10421  return -1;
10422  if (!sl)
10423  return from;
10424  if (!l)
10425  return -1;
10426 
10427  if (sl == 1)
10428  return qFindChar(haystack0, needle0[0], from, cs);
10429 
10430  /*
10431  We use the Boyer-Moore algorithm in cases where the overhead
10432  for the skip table should pay off, otherwise we use a simple
10433  hash function.
10434  */
10435  if (l > 500 && sl > 5)
10436  return qFindStringBoyerMoore(haystack0, from, needle0, cs);
10437 
10438  auto sv = [sl](const char16_t *v) { return QStringView(v, sl); };
10439  /*
10440  We use some hashing for efficiency's sake. Instead of
10441  comparing strings, we compare the hash value of str with that
10442  of a part of this QString. Only if that matches, we call
10443  qt_string_compare().
10444  */
10445  const char16_t *needle = needle0.utf16();
10446  const char16_t *haystack = haystack0.utf16() + from;
10447  const char16_t *end = haystack0.utf16() + (l - sl);
10448  const std::size_t sl_minus_1 = sl - 1;
10449  std::size_t hashNeedle = 0, hashHaystack = 0;
10450  qsizetype idx;
10451 
10452  if (cs == Qt::CaseSensitive) {
10453  for (idx = 0; idx < sl; ++idx) {
10454  hashNeedle = ((hashNeedle<<1) + needle[idx]);
10455  hashHaystack = ((hashHaystack<<1) + haystack[idx]);
10456  }
10457  hashHaystack -= haystack[sl_minus_1];
10458 
10459  while (haystack <= end) {
10460  hashHaystack += haystack[sl_minus_1];
10461  if (hashHaystack == hashNeedle
10462  && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseSensitive) == 0)
10463  return haystack - haystack0.utf16();
10464 
10465  REHASH(*haystack);
10466  ++haystack;
10467  }
10468  } else {
10469  const char16_t *haystack_start = haystack0.utf16();
10470  for (idx = 0; idx < sl; ++idx) {
10471  hashNeedle = (hashNeedle<<1) + foldCase(needle + idx, needle);
10472  hashHaystack = (hashHaystack<<1) + foldCase(haystack + idx, haystack_start);
10473  }
10474  hashHaystack -= foldCase(haystack + sl_minus_1, haystack_start);
10475 
10476  while (haystack <= end) {
10477  hashHaystack += foldCase(haystack + sl_minus_1, haystack_start);
10478  if (hashHaystack == hashNeedle
10479  && QtPrivate::compareStrings(needle0, sv(haystack), Qt::CaseInsensitive) == 0)
10480  return haystack - haystack0.utf16();
10481 
10482  REHASH(foldCase(haystack, haystack_start));
10483  ++haystack;
10484  }
10485  }
10486  return -1;
10487 }
10488 
10490 {
10491  if (haystack.size() < needle.size())
10492  return -1;
10493 
10494  QVarLengthArray<char16_t> s(needle.size());
10495  qt_from_latin1(s.data(), needle.latin1(), needle.size());
10496  return QtPrivate::findString(haystack, from, QStringView(reinterpret_cast<const QChar*>(s.constData()), s.size()), cs);
10497 }
10498 
10500 {
10501  if (haystack.size() < needle.size())
10502  return -1;
10503 
10504  if (!QtPrivate::isLatin1(needle)) // won't find non-L1 UTF-16 needles in a L1 haystack!
10505  return -1;
10506 
10507  if (needle.size() == 1) {
10508  const char n = needle.front().toLatin1();
10509  return QtPrivate::findString(haystack, from, QLatin1String(&n, 1), cs);
10510  }
10511 
10512  QVarLengthArray<char> s(needle.size());
10513  qt_to_latin1_unchecked(reinterpret_cast<uchar *>(s.data()), needle.utf16(), needle.size());
10514  return QtPrivate::findString(haystack, from, QLatin1String(s.data(), s.size()), cs);
10515 }
10516 
10518 {
10519  if (from < 0)
10520  from += haystack.size();
10521  if (from < 0)
10522  return -1;
10523  qsizetype adjustedSize = haystack.size() - from;
10524  if (adjustedSize < needle.size())
10525  return -1;
10526  if (needle.size() == 0)
10527  return from;
10528 
10529  if (cs == Qt::CaseSensitive) {
10530 
10531  if (needle.size() == 1) {
10532  Q_ASSUME(haystack.data() != nullptr); // see size check above
10533  if (auto it = memchr(haystack.data() + from, needle.front().toLatin1(), adjustedSize))
10534  return static_cast<const char *>(it) - haystack.data();
10535  return -1;
10536  }
10537 
10538  const QByteArrayMatcher matcher(needle);
10539  return matcher.indexIn(haystack, from);
10540  }
10541 
10542  // If the needle is sufficiently small we simply iteratively search through
10543  // the haystack. When the needle is too long we use a boyer-moore searcher
10544  // from the standard library, if available. If it is not available then the
10545  // QLatin1Strings are converted to QString and compared as such. Though
10546  // initialization is slower the boyer-moore search it employs still makes up
10547  // for it when haystack and needle are sufficiently long.
10548  // The needle size was chosen by testing various lengths using the
10549  // qstringtokenizer benchmark with the
10550  // "tokenize_qlatin1string_qlatin1string" test.
10551 #ifdef Q_CC_MSVC
10552  const qsizetype threshold = 1;
10553 #else
10554  const qsizetype threshold = 13;
10555 #endif
10556  if (needle.size() <= threshold) {
10557  const auto begin = haystack.begin();
10558  const auto end = haystack.end() - needle.size() + 1;
10559  const uchar needle1 = latin1Lower[uchar(needle[0].toLatin1())];
10560  auto ciMatch = [needle1](const char ch) {
10561  return latin1Lower[uchar(ch)] == needle1;
10562  };
10563  const qsizetype nlen1 = needle.size() - 1;
10564  for (auto it = std::find_if(begin + from, end, ciMatch); it < end;
10565  it = std::find_if(it + 1, end, ciMatch)) {
10566  // In this comparison we skip the first character because we know it's a match
10567  if (!nlen1 || QLatin1String(it + 1, nlen1).compare(needle.sliced(1), cs) == 0)
10568  return std::distance(begin, it);
10569  }
10570  return -1;
10571  }
10572 
10573 #ifdef __cpp_lib_boyer_moore_searcher
10574  const auto ciHasher = [](char a) { return latin1Lower[uchar(a)]; };
10575  const auto ciEqual = [](char a, char b) {
10576  return latin1Lower[uchar(a)] == latin1Lower[uchar(b)];
10577  };
10578  const auto it =
10579  std::search(haystack.begin() + from, haystack.end(),
10580  std::boyer_moore_searcher(needle.begin(), needle.end(), ciHasher, ciEqual));
10581  return it == haystack.end() ? -1 : std::distance(haystack.begin(), it);
10582 #else
10583  QVarLengthArray<char16_t> h(adjustedSize);
10584  const auto begin = haystack.end() - adjustedSize;
10585  qt_from_latin1(h.data(), begin, adjustedSize);
10586  QVarLengthArray<char16_t> n(needle.size());
10587  qt_from_latin1(n.data(), needle.latin1(), needle.size());
10588  qsizetype res = QtPrivate::findString(QStringView(h.constData(), h.size()), 0,
10589  QStringView(n.constData(), n.size()), cs);
10590  if (res == -1)
10591  return -1;
10592  return res + std::distance(haystack.begin(), begin);
10593 #endif
10594 }
10595 
10597 {
10598  return qLastIndexOf(haystack, from, needle, cs);
10599 }
10600 
10602 {
10603  return qLastIndexOf(haystack, from, needle, cs);
10604 }
10605 
10607 {
10608  return qLastIndexOf(haystack, from, needle, cs);
10609 }
10610 
10612 {
10613  return qLastIndexOf(haystack, from, needle, cs);
10614 }
10615 
10616 #if QT_CONFIG(regularexpression)
10618 {
10619  if (!re.isValid()) {
10620  qWarning("QString(View)::indexOf: invalid QRegularExpression object");
10621  return -1;
10622  }
10623 
10624  QRegularExpressionMatch match = re.match(haystack, from);
10625  if (match.hasMatch()) {
10626  const qsizetype ret = match.capturedStart();
10627  if (rmatch)
10628  *rmatch = std::move(match);
10629  return ret;
10630  }
10631 
10632  return -1;
10633 }
10634 
10636 {
10637  if (!re.isValid()) {
10638  qWarning("QString(View)::lastIndexOf: invalid QRegularExpression object");
10639  return -1;
10640  }
10641 
10642  qsizetype endpos = (from < 0) ? (haystack.size() + from + 1) : (from + 1);
10644  qsizetype lastIndex = -1;
10645  while (iterator.hasNext()) {
10646  QRegularExpressionMatch match = iterator.next();
10647  qsizetype start = match.capturedStart();
10648  if (start < endpos) {
10649  lastIndex = start;
10650  if (rmatch)
10651  *rmatch = std::move(match);
10652  } else {
10653  break;
10654  }
10655  }
10656 
10657  return lastIndex;
10658 }
10659 
10661 {
10662  if (!re.isValid()) {
10663  qWarning("QString(View)::contains: invalid QRegularExpression object");
10664  return false;
10665  }
10666  QRegularExpressionMatch m = re.match(haystack);
10667  bool hasMatch = m.hasMatch();
10668  if (hasMatch && rmatch)
10669  *rmatch = std::move(m);
10670  return hasMatch;
10671 }
10672 
10674 {
10675  if (!re.isValid()) {
10676  qWarning("QString(View)::count: invalid QRegularExpression object");
10677  return 0;
10678  }
10679  qsizetype count = 0;
10680  qsizetype index = -1;
10681  qsizetype len = haystack.length();
10682  while (index <= len - 1) {
10683  QRegularExpressionMatch match = re.match(haystack, index + 1);
10684  if (!match.hasMatch())
10685  break;
10686  index = match.capturedStart();
10687  count++;
10688  }
10689  return count;
10690 }
10691 
10692 #endif // QT_CONFIG(regularexpression)
10693 
10706 {
10707  QString rich;
10708  const int len = length();
10709  rich.reserve(qsizetype(len * 1.1));
10710  for (int i = 0; i < len; ++i) {
10711  if (at(i) == QLatin1Char('<'))
10712  rich += QLatin1String("&lt;");
10713  else if (at(i) == QLatin1Char('>'))
10714  rich += QLatin1String("&gt;");
10715  else if (at(i) == QLatin1Char('&'))
10716  rich += QLatin1String("&amp;");
10717  else if (at(i) == QLatin1Char('"'))
10718  rich += QLatin1String("&quot;");
10719  else
10720  rich += at(i);
10721  }
10722  rich.squeeze();
10723  return rich;
10724 }
10725 
10797 {
10798  qt_from_latin1(reinterpret_cast<char16_t *>(out), in.data(), size_t(in.size()));
10799 }
10800 
10801 double QStringView::toDouble(bool *ok) const
10802 {
10804 }
10805 
10806 float QStringView::toFloat(bool *ok) const
10807 {
10809 }
10810 
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
#define value
[5]
FT_UInt idx
Definition: cffcmap.c:135
static Q_CORE_EXPORT int compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Definition: qstring.cpp:1636
static Q_CORE_EXPORT bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
Definition: qstring.cpp:1476
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
char * data()
Definition: qbytearray.h:516
qsizetype size() const noexcept
Definition: qbytearray.h:470
char * data()
const char * constData() const noexcept
Definition: qbytearray.h:144
bool isEmpty() const noexcept
Definition: qbytearray.h:129
bool isNull() const noexcept
The QByteArrayMatcher class holds a sequence of bytes that can be quickly matched in a byte array.
Q_WEAK_OVERLOAD qsizetype indexIn(const QByteArray &ba, qsizetype from=0) const
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
static constexpr QChar fromUcs2(char16_t c) noexcept
Definition: qchar.h:134
@ ReplacementCharacter
Definition: qchar.h:95
static constexpr bool requiresSurrogates(char32_t ucs4) noexcept
Definition: qchar.h:535
int digitValue() const noexcept
Definition: qchar.h:478
Direction direction() const noexcept
Definition: qchar.h:468
constexpr char toLatin1() const noexcept
Definition: qchar.h:488
@ DirFSI
Definition: qchar.h:380
@ DirNSM
Definition: qchar.h:379
@ DirPDF
Definition: qchar.h:379
@ DirON
Definition: qchar.h:378
@ DirLRO
Definition: qchar.h:379
@ DirWS
Definition: qchar.h:378
@ DirL
Definition: qchar.h:378
@ DirEN
Definition: qchar.h:378
@ DirCS
Definition: qchar.h:378
@ DirRLO
Definition: qchar.h:379
@ DirAN
Definition: qchar.h:378
@ DirAL
Definition: qchar.h:379
@ DirB
Definition: qchar.h:378
@ DirRLI
Definition: qchar.h:380
@ DirS
Definition: qchar.h:378
@ DirPDI
Definition: qchar.h:380
@ DirLRE
Definition: qchar.h:379
@ DirLRI
Definition: qchar.h:380
@ DirBN
Definition: qchar.h:379
@ DirRLE
Definition: qchar.h:379
@ DirET
Definition: qchar.h:378
@ DirR
Definition: qchar.h:378
@ DirES
Definition: qchar.h:378
UnicodeVersion
Definition: qchar.h:439
@ Unicode_Unassigned
Definition: qchar.h:440
static constexpr char16_t highSurrogate(char32_t ucs4) noexcept
Definition: qchar.h:549
constexpr char16_t unicode() const noexcept
Definition: qchar.h:489
QChar toCaseFolded() const noexcept
Definition: qchar.h:482
static constexpr char16_t lowSurrogate(char32_t ucs4) noexcept
Definition: qchar.h:553
constexpr bool isNull() const noexcept
Definition: qchar.h:494
static UnicodeVersion QT_FASTCALL currentUnicodeVersion() noexcept Q_DECL_CONST_FUNCTION
Definition: qchar.cpp:1546
static int defaultCompare(QStringView s1, QStringView s2)
Definition: qcollator.cpp:380
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:66
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
constexpr const char * latin1() const noexcept
Definition: qstring.h:96
constexpr qsizetype size() const noexcept
Definition: qstring.h:97
int compare(QStringView other, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.h:113
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
qsizetype length() const noexcept
Definition: qlist.h:416
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
QList< T > mid(qsizetype pos, qsizetype len=-1) const
Definition: qlist.h:979
void append(parameter_type t)
Definition: qlist.h:469
@ OmitGroupSeparator
Definition: qlocale.h:897
@ IncludeTrailingZeroesAfterDot
Definition: qlocale.h:901
@ OmitLeadingZeroInExponent
Definition: qlocale.h:899
@ RejectGroupSeparator
Definition: qlocale.h:898
The QRegularExpression class provides pattern matching using regular expressions.
QRegularExpressionMatch match(const QString &subject, 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
The QRegularExpressionMatch class provides the results of a matching a QRegularExpression against a s...
qsizetype capturedEnd(int nth=0) const
qsizetype capturedStart(int nth=0) const
qsizetype capturedLength(int nth=0) const
The QRegularExpressionMatchIterator class provides an iterator on the results of a global match of a ...
The QStringDecoder class provides a state-based decoder for text. \reentrant.
The QStringEncoder class provides a state-based encoder for text. \reentrant.
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString right(qsizetype n) const
Definition: qstring.cpp:4970
bool isSimpleText() const
Definition: qstring.cpp:8758
iterator begin()
Definition: qstring.h:1331
QByteArray toLatin1() const &
Definition: qstring.h:745
bool isDetached() const
Definition: qstring.h:1238
QChar * iterator
Definition: qstring.h:1025
QString repeated(qsizetype times) const
Definition: qstring.cpp:7818
double toDouble(bool *ok=nullptr) const
Definition: qstring.cpp:7374
QString leftJustified(qsizetype width, QChar fill=QLatin1Char(' '), bool trunc=false) const
Definition: qstring.cpp:6518
QString last(qsizetype n) const
Definition: qstring.h:578
qsizetype count() const
Definition: qstring.h:414
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.h:514
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5092
QString & fill(QChar c, qsizetype size=-1)
Definition: qstring.cpp:5973
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition: qstring.cpp:3450
void reserve(qsizetype size)
Definition: qstring.h:1307
qlonglong toLongLong(bool *ok=nullptr, int base=10) const
Definition: qstring.cpp:7127
qulonglong toULongLong(bool *ok=nullptr, int base=10) const
Definition: qstring.cpp:7169
void chop(qsizetype n)
Definition: qstring.cpp:5955
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
const ushort * utf16() const
Definition: qstring.cpp:6491
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:7672
QDataStream & operator<<(QDataStream &stream, const QString &string)
Definition: qstring.cpp:10084
void truncate(qsizetype pos)
Definition: qstring.cpp:5934
static QString fromLocal8Bit(QByteArrayView ba)
Definition: qstring.cpp:5563
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition: qstring.cpp:5658
static QString fromUcs4(const char32_t *, qsizetype size=-1)
Definition: qstring.cpp:5690
void clear()
Definition: qstring.h:1240
const QChar * constData() const
Definition: qstring.h:1234
const_iterator cbegin() const
Definition: qstring.h:1335
QString & operator=(QChar c)
Definition: qstring.cpp:2886
bool isNull() const
Definition: qstring.h:1078
QString & setUnicode(const QChar *unicode, qsizetype size)
Definition: qstring.cpp:5713
qsizetype size() const
Definition: qstring.h:413
QList< uint > toUcs4() const
Definition: qstring.cpp:5440
QString rightJustified(qsizetype width, QChar fill=QLatin1Char(' '), bool trunc=false) const
Definition: qstring.cpp:6557
QStringPrivate DataPointer
Definition: qstring.h:391
static QString fromUtf8(QByteArrayView utf8)
Definition: qstring.cpp:5632
bool isLower() const
Definition: qstring.cpp:5220
QString mid(qsizetype position, qsizetype n=-1) const
Definition: qstring.cpp:4994
@ SectionCaseInsensitiveSeps
Definition: qstring.h:563
@ SectionIncludeLeadingSep
Definition: qstring.h:561
@ SectionSkipEmpty
Definition: qstring.h:560
@ SectionIncludeTrailingSep
Definition: qstring.h:562
QString section(QChar sep, qsizetype start, qsizetype end=-1, SectionFlags flags=SectionDefault) const
Definition: qstring.h:1272
static QString fromRawData(const QChar *, qsizetype size)
Definition: qstring.cpp:8938
constexpr QString() noexcept
Definition: qstring.h:1304
qsizetype capacity() const
Definition: qstring.h:1244
iterator end()
Definition: qstring.h:1339
void detach()
Definition: qstring.h:1236
bool isUpper() const
Definition: qstring.cpp:5194
localeAwareCompare
friend class QByteArray
Definition: qstring.h:1131
const QChar at(qsizetype i) const
Definition: qstring.h:1212
float toFloat(bool *ok=nullptr) const
Definition: qstring.cpp:7409
QChar front() const
Definition: qstring.h:442
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5143
bool isEmpty() const
Definition: qstring.h:1216
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.cpp:6263
QString & insert(qsizetype i, QChar c)
Definition: qstring.cpp:3043
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=QLatin1Char(' ')) const
Definition: qstring.cpp:8318
QByteArray toLocal8Bit() const &
Definition: qstring.h:753
QChar * data()
Definition: qstring.h:1228
static QString vasprintf(const char *format, va_list ap) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition: qstring.cpp:6853
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:1353
static QString number(int, int base=10)
Definition: qstring.cpp:7538
QString & append(QChar c)
Definition: qstring.cpp:3152
QString left(qsizetype n) const
Definition: qstring.cpp:4951
void squeeze()
Definition: qstring.h:1315
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:4197
QString & setUtf16(const ushort *utf16, qsizetype size)
Definition: qstring.h:1325
bool isRightToLeft() const
Definition: qstring.cpp:8780
QString & setNum(short, int base=10)
Definition: qstring.h:1245
QString & setRawData(const QChar *unicode, qsizetype size)
Definition: qstring.cpp:8957
QString & remove(qsizetype i, qsizetype len)
Definition: qstring.cpp:3252
friend class QStringView
Definition: qstring.h:1130
const_iterator constBegin() const
Definition: qstring.h:1337
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition: qstring.cpp:6759
QString toHtmlEscaped() const
Definition: qstring.cpp:10705
NormalizationForm
Definition: qstring.h:732
@ NormalizationForm_KD
Definition: qstring.h:735
@ NormalizationForm_C
Definition: qstring.h:734
@ NormalizationForm_D
Definition: qstring.h:733
qsizetype length() const
Definition: qstring.h:415
const QChar * unicode() const
Definition: qstring.h:1218
QString normalized(NormalizationForm mode, QChar::UnicodeVersion version=QChar::Unicode_Unassigned) const
Definition: qstring.cpp:7919
iterator erase(const_iterator first, const_iterator last)
Definition: qstring.cpp:8883
void resize(qsizetype size)
Definition: qstring.cpp:2670
QDataStream & operator>>(QDataStream &stream, QString &string)
Definition: qstring.cpp:10116
The QStringList class provides a list of strings.
The QStringMatcher class holds a sequence of characters that can be quickly matched in a Unicode stri...
qsizetype indexIn(const QString &str, qsizetype from=0) const
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
int compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs) noexcept
Definition: qstring.cpp:1503
Q_CORE_EXPORT double toDouble(bool *ok=nullptr) const
Definition: qstring.cpp:10801
Q_CORE_EXPORT float toFloat(bool *ok=nullptr) const
Definition: qstring.cpp:10806
constexpr const storage_type * utf16() const noexcept
Definition: qstringview.h:242
constexpr QChar front() const
Definition: qstringview.h:454
constexpr qsizetype length() const noexcept
Definition: qstringview.h:464
constexpr qsizetype size() const noexcept
Definition: qstringview.h:239
const_iterator begin() const noexcept
Definition: qstringview.h:444
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:7702
const_pointer data() const noexcept
Definition: qstringview.h:240
constexpr QChar back() const
Definition: qstringview.h:455
constexpr bool isNull() const noexcept
Definition: qstringview.h:462
constexpr QStringView right(qsizetype n) const noexcept
Definition: qstringview.h:273
constexpr QStringView sliced(qsizetype pos) const noexcept
Definition: qstringview.h:284
const_iterator end() const noexcept
Definition: qstringview.h:445
@ BigEndian
Definition: qsysinfo.h:61
@ ByteOrder
Definition: qsysinfo.h:66
Definition: base.h:37
msgBox exec()
QString str
[2]
double e
set contains("Julia")
part
Definition: enum_inc.h:2
int const char * version
Definition: zlib.h:814
#define NULL
Definition: ftobjs.h:61
va_end(ap)
static void const void const char bool unsigned int int const char va_start(ap, message)
#define Null(Type)
Definition: hb-null.hh:106
#define __attribute__(x)
Definition: hb.hh:256
int const JOCTET * dataptr
Definition: jpeglib.h:969
short next
Definition: keywords.cpp:454
GeneratorWrapper< std::vector< T > > chunk(size_t size, GeneratorWrapper< T > &&generator)
Definition: catch_p_p.h:4333
typename C::value_type value_type
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
@ Checked
Definition: qnamespace.h:1498
CaseSensitivity
Definition: qnamespace.h:1282
@ CaseInsensitive
Definition: qnamespace.h:1283
@ CaseSensitive
Definition: qnamespace.h:1284
constexpr Initialization Uninitialized
Definition: qnamespace.h:1613
@ KeepEmptyParts
Definition: qnamespace.h:152
Initialization
Definition: qnamespace.h:1610
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
constexpr bool isLatin1(QLatin1String s) noexcept
Definition: qstring.h:328
Q_CORE_EXPORT QList< uint > convertToUcs4(QStringView str)
Definition: qstring.cpp:5473
Q_CORE_EXPORT QByteArray convertToLocal8Bit(QStringView str)
Definition: qstring.cpp:5375
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrlen(const char16_t *str) noexcept
Definition: qstring.cpp:351
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isValidUtf16(QStringView s) noexcept
Definition: qstring.cpp:768
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 Q_DECL_PURE_FUNCTION bool equalStrings(QStringView lhs, QStringView rhs) noexcept
Definition: qstring.cpp:1430
Q_CORE_EXPORT QByteArray convertToUtf8(QStringView str)
Definition: qstring.cpp:5418
Q_CORE_EXPORT QString convertToQString(QAnyStringView s)
Definition: qstring.cpp:5250
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs=Qt::CaseSensitive) noexcept
Definition: qstring.cpp:10414
Q_CORE_EXPORT QString argToQString(QStringView pattern, size_t n, const ArgBase **args)
Definition: qstring.cpp:8744
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isAscii(QLatin1String s) noexcept
Definition: qstring.cpp:713
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 QByteArray convertToLatin1(QStringView str)
Definition: qstring.cpp:5267
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION const char16_t * qustrchr(QStringView str, char16_t ch) noexcept
Definition: qstring.cpp:448
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isRightToLeft(QStringView string) noexcept
Definition: qstring.cpp:10187
constexpr struct q20::ranges::@309 any_of
Definition: qfloat16.h:381
int distance(TestIterator &a, TestIterator &b)
#define QString()
Definition: parse-defines.h:51
void *PRIV() memmove(void *d, const void *s, size_t n)
PCRE2_SIZE PRIV() strlen(PCRE2_SPTR str)
QT_POPCOUNT_RELAXED_CONSTEXPR uint qCountLeadingZeroBits(quint32 v) noexcept
Definition: qalgorithms.h:411
constexpr uint qCountTrailingZeroBits(quint32 v) noexcept
Definition: qalgorithms.h:362
const int blockSize
size_t qstrlen(const char *str)
size_t qstrnlen(const char *str, size_t maxlen)
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
#define Q_ASSUME(Expr)
#define Q_UNREACHABLE()
EGLOutputLayerEXT EGLint EGLAttrib value
QT_BEGIN_NAMESPACE Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest)
Definition: qendian.h:66
bool qIsFinite(qfloat16 f) noexcept
Definition: qfloat16.h:222
unsigned int quint32
Definition: qglobal.h:288
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
unsigned short quint16
Definition: qglobal.h:286
size_t quintptr
Definition: qglobal.h:310
unsigned long ulong
Definition: qglobal.h:335
ptrdiff_t qptrdiff
Definition: qglobal.h:307
quint64 qulonglong
Definition: qglobal.h:302
unsigned long long quint64
Definition: qglobal.h:299
ptrdiff_t qsizetype
Definition: qglobal.h:308
unsigned int uint
Definition: qglobal.h:334
long long qint64
Definition: qglobal.h:298
unsigned short ushort
Definition: qglobal.h:333
unsigned char quint8
Definition: qglobal.h:284
qint64 qlonglong
Definition: qglobal.h:301
QString qdtoBasicLatin(double d, QLocaleData::DoubleForm form, int precision, bool uppercase)
unsigned long long qstrntoull(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
QString qulltoBasicLatin(qulonglong number, int base, bool negative)
#define qWarning
Definition: qlogging.h:179
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLboolean r
[2]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLenum src
GLenum GLuint buffer
GLint GLsizei width
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
Definition: qopenglext.h:2748
GLuint res
Definition: qopenglext.h:8867
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLsizei len
Definition: qopenglext.h:3292
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLuint in
Definition: qopenglext.h:8870
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLuint GLenum option
Definition: qopenglext.h:5929
GLuint num
Definition: qopenglext.h:5654
GLubyte * pattern
Definition: qopenglext.h:2744
GLenum GLint GLint * precision
Definition: qopenglext.h:1890
GLsizei const GLchar *const * string
[0]
Definition: qopenglext.h:694
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
bool qt_is_ascii(const char *&ptr, const char *end) noexcept
Definition: qstring.cpp:649
Q_DECLARE_TYPEINFO(Part, Q_PRIMITIVE_TYPE)
Q_ALWAYS_INLINE QString to_string(QLatin1String s) noexcept
Definition: qstring.cpp:8697
#define REHASH(a)
Definition: qstring.cpp:105
qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs)
LengthMod
Definition: qstring.cpp:6813
@ lm_none
Definition: qstring.cpp:6813
@ lm_l
Definition: qstring.cpp:6813
@ lm_hh
Definition: qstring.cpp:6813
@ lm_j
Definition: qstring.cpp:6813
@ lm_L
Definition: qstring.cpp:6813
@ lm_h
Definition: qstring.cpp:6813
@ lm_z
Definition: qstring.cpp:6813
@ lm_ll
Definition: qstring.cpp:6813
@ lm_t
Definition: qstring.cpp:6813
bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
Definition: qstring.cpp:10269
void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, qsizetype from)
Definition: qstring.cpp:7853
#define CSTR_LESS_THAN
Definition: qstring.cpp:6383
constexpr int lencmp(qsizetype lhs, qsizetype rhs) noexcept
Definition: qstring.cpp:1368
#define CSTR_GREATER_THAN
Definition: qstring.cpp:6385
void qt_to_latin1_unchecked(uchar *dst, const char16_t *src, qsizetype length)
Definition: qstring.cpp:1003
Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept
Definition: qstring.cpp:783
bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs) noexcept
Definition: qstring.cpp:10342
QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
Definition: qstringview.h:480
#define s2
QT_BEGIN_NAMESPACE typedef char Char
@ Q_PRIMITIVE_TYPE
Definition: qtypeinfo.h:155
@ Q_RELOCATABLE_TYPE
Definition: qtypeinfo.h:156
QBasicUtf8StringView< false > QUtf8StringView
QVarLengthArray(InputIterator, InputIterator) -> QVarLengthArray< ValueType >
double accumulate
Definition: outofline.cpp:34
#define U8(v)
Q_UNUSED(salary)
[21]
Q_CHECK_PTR(a=new int[80])
QByteArray ba
[0]
QString base
settings remove("monkey")
QTextStream out(stdout)
[7]
QMimeDatabase db
[0]
QSharedPointer< T > other(t)
[5]
QGraphicsWidget * form
QStringList::Iterator it
QStringList list
[0]
int locale_occurrences
Definition: qstring.cpp:7959
static void appendLatin1To(QLatin1String in, QChar *out) noexcept
Definition: qstring.cpp:10796
void detachAndGrow(QArrayData::GrowthPosition where, qsizetype n, const T **data, QArrayDataPointer *old)
bool isNull() const noexcept
qsizetype freeSpaceAtBegin() const noexcept
T * data() noexcept
bool needsDetach() const noexcept
qsizetype allocatedCapacity() noexcept
qsizetype constAllocatedCapacity() const noexcept
void clear() noexcept(std::is_nothrow_destructible< T >::value)
T * begin() noexcept
static QArrayDataPointer fromRawData(const char16_t *rawData, qsizetype length) noexcept
static QArrayDataPointer allocateGrow(const QArrayDataPointer &from, qsizetype n, QArrayData::GrowthPosition position)
bool isMutable() const noexcept
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
constexpr char16_t unicode() const noexcept
Definition: qchar.h:57
static float convertDoubleToFloat(double d, bool *ok)
Definition: qlocale_p.h:262
QString doubleToString(double d, int precision=-1, DoubleForm form=DFSignificantDigits, int width=-1, unsigned flags=NoFlags) const
Definition: qlocale.cpp:3556
static const QLocaleData * c()
Definition: qlocale.cpp:828
quint64 stringToUnsLongLong(QStringView str, int base, bool *ok, QLocale::NumberOptions options) const
Definition: qlocale.cpp:4136
qint64 stringToLongLong(QStringView str, int base, bool *ok, QLocale::NumberOptions options) const
Definition: qlocale.cpp:4123
@ ZeroPadExponent
Definition: qlocale_p.h:221
@ BlankBeforePositive
Definition: qlocale_p.h:214
@ AddTrailingZeroes
Definition: qlocale_p.h:211
@ AlwaysShowSign
Definition: qlocale_p.h:215
double stringToDouble(QStringView str, bool *ok, QLocale::NumberOptions options) const
Definition: qlocale.cpp:4106
QString longLongToString(qint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition: qlocale.cpp:3799
@ DFSignificantDigits
Definition: qlocale_p.h:205
QString unsLongLongToString(quint64 l, int precision=-1, int base=10, int width=-1, unsigned flags=NoFlags) const
Definition: qlocale.cpp:3814
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 *, T * > allocate(qsizetype capacity, AllocationOption option=QArrayData::KeepSize)
Definition: qarraydata.h:137
static Q_CORE_EXPORT QByteArray convertFromUnicode(QStringView in)
static Q_CORE_EXPORT QChar * convertToUnicode(QChar *buffer, QByteArrayView in) noexcept
static int compareUtf8(QByteArrayView utf8, QStringView utf16) noexcept
void growAppend(const T *b, const T *e)
void copyAppend(const T *b, const T *e)
void erase(T *b, qsizetype n)
void insert(qsizetype i, const T *data, qsizetype n)
Definition: main.cpp:38
Definition: inftrees.h:24
QString escape(const QString &s)
ByteArray detached(ByteArray b)
#define rhs
QDomElement find(const QString &tagName, const QDomElement &e)
Definition: main.cpp:39
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154