qxLib
string.inl
Go to the documentation of this file.
1 /**
2 
3  @file string.inl
4  @author Khrapov
5  @date 4.09.2019
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 template<class char_t, class traits_t>
14 inline basic_string<char_t, traits_t>::basic_string(size_type nSymbols, value_type chSymbol) noexcept
15 {
16  assign(nSymbols, chSymbol);
17 }
18 
19 template<class char_t, class traits_t>
20 inline basic_string<char_t, traits_t>::basic_string(const_pointer pszSource, size_type nSymbols) noexcept
21 {
22  assign(pszSource, nSymbols);
23 }
24 
25 template<class char_t, class traits_t>
26 inline basic_string<char_t, traits_t>::basic_string(const_pointer pszSource) noexcept
27 {
28  assign(pszSource);
29 }
30 
31 template<class char_t, class traits_t>
33 {
34  assign(std::move(sAnother));
35 }
36 
37 template<class char_t, class traits_t>
39 {
40  assign(sAnother);
41 }
42 
43 template<class char_t, class traits_t>
44 template<class fwd_it_t>
45 inline basic_string<char_t, traits_t>::basic_string(fwd_it_t itFirst, fwd_it_t itLast) noexcept
46 {
47  assign(itFirst, itLast);
48 }
49 
50 template<class char_t, class traits_t>
51 template<range_of_t_c<char_t> string_t>
52 inline basic_string<char_t, traits_t>::basic_string(const string_t& sAnother) noexcept
53 {
54  assign(sAnother);
55 }
56 
57 template<class char_t, class traits_t>
58 inline void basic_string<char_t, traits_t>::assign(size_type nSymbols, value_type chSymbol) noexcept
59 {
60  if (_resize(nSymbols))
61  std::fill(begin(), end(), chSymbol);
62 }
63 
64 template<class char_t, class traits_t>
65 inline void basic_string<char_t, traits_t>::assign(const_pointer pszSource, size_type nSymbols) noexcept
66 {
67  if (pszSource && _resize(nSymbols))
68  std::memmove(data(), pszSource, nSymbols * sizeof(value_type));
69 }
70 
71 template<class char_t, class traits_t>
72 inline void basic_string<char_t, traits_t>::assign(const_pointer pszSource) noexcept
73 {
74  if (pszSource != data())
75  assign(pszSource, traits_t::length(pszSource));
76 }
77 
78 template<class char_t, class traits_t>
79 inline void basic_string<char_t, traits_t>::assign(basic_string&& sAnother) noexcept
80 {
81  swap(sAnother);
82 }
83 
84 template<class char_t, class traits_t>
85 inline void basic_string<char_t, traits_t>::assign(const basic_string& sAnother) noexcept
86 {
87  if (sAnother.data() != data())
88  assign(sAnother.data());
89 }
90 
91 template<class char_t, class traits_t>
92 template<class fwd_it_t>
93 inline void basic_string<char_t, traits_t>::assign(fwd_it_t itFirst, fwd_it_t itLast) noexcept
94 {
95  // some iterators may be one-pass only, so we can't calculate distance first
96  size_t nPos = 0;
97  for (fwd_it_t it = itFirst; it != itLast; ++it)
98  {
99  _resize(nPos + 1, sbo_resize_type::reserve);
100  (*this)[nPos] = *it;
101  ++nPos;
102  }
103 
104  _resize(nPos, sbo_resize_type::common);
105 }
106 
107 template<class char_t, class traits_t>
108 template<range_of_t_c<char_t> string_t>
109 inline void basic_string<char_t, traits_t>::assign(const string_t& sAnother) noexcept
110 {
111  assign(sAnother.cbegin(), sAnother.cend());
112 }
113 
114 template<class char_t, class traits_t>
115 template<class... args_t>
116  requires format_acceptable_args_c<char_t, args_t...>
118  const format_string_type<std::type_identity_t<args_t>...> sFormat,
119  args_t&&... args)
120 {
121  vformat(sFormat.get(), std::forward<args_t>(args)...);
122 }
123 
124 template<class char_t, class traits_t>
125 template<class... args_t>
126  requires format_acceptable_args_c<char_t, args_t...>
128  const format_string_type<std::type_identity_t<args_t>...> sFormat,
129  args_t&&... args)
130 {
131  return static_vformat(sFormat.get(), std::forward<args_t>(args)...);
132 }
133 
134 template<class char_t, class traits_t>
135 template<class... args_t>
136  requires format_acceptable_args_c<char_t, args_t...>
138  const format_string_type<std::type_identity_t<args_t>...> sFormat,
139  args_t&&... args)
140 {
141  append_vformat(sFormat.get(), std::forward<args_t>(args)...);
142 }
143 
144 template<class char_t, class traits_t>
145 template<class... args_t>
146  requires format_acceptable_args_c<char_t, args_t...>
147 void basic_string<char_t, traits_t>::vformat(string_view svFormat, args_t&&... args)
148 {
149  clear();
150  append_vformat(svFormat, std::forward<args_t>(args)...);
151 }
152 
153 template<class char_t, class traits_t>
154 template<class... args_t>
155  requires format_acceptable_args_c<char_t, args_t...>
157  string_view svFormat,
158  args_t&&... args)
159 {
160  basic_string sTemp;
161  sTemp.vformat(svFormat, std::forward<args_t>(args)...);
162  return sTemp;
163 }
164 
165 template<class char_t, class traits_t>
166 template<class... args_t>
167  requires format_acceptable_args_c<char_t, args_t...>
168 inline void basic_string<char_t, traits_t>::append_vformat(string_view svFormat, args_t&&... args)
169 {
170  if (!svFormat.empty())
171  traits_t::format_to(std::back_inserter(*this), svFormat, std::forward<args_t>(args)...);
172 }
173 
174 template<class char_t, class traits_t>
176 {
177  std::swap(m_Data, sOther.m_Data);
178 }
179 
180 template<class char_t, class traits_t>
181 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::reserve(
182  size_type nCapacity) noexcept
183 {
184  if (nCapacity > capacity())
185  _resize(nCapacity, sbo_resize_type::reserve);
186 
187  return capacity();
188 }
189 
190 template<class char_t, class traits_t>
192 {
193  if (!m_Data.is_small() && capacity() > size())
194  _resize(size(), sbo_resize_type::shrink_to_fit);
195 }
196 
197 template<class char_t, class traits_t>
199 {
200  m_Data.free();
201 }
202 
203 template<class char_t, class traits_t>
204 inline typename basic_string<char_t, traits_t>::string_view basic_string<char_t, traits_t>::substr(
205  size_type nPos,
206  size_type nSymbols) const noexcept
207 {
208  return string_view(data() + nPos, nSymbols != npos ? nSymbols : size() - nPos);
209 }
210 
211 template<class char_t, class traits_t>
213 {
214  for (value_type& ch : *this)
215  ch = traits_t::to_lower(ch);
216 }
217 
218 template<class char_t, class traits_t>
220 {
221  for (value_type& ch : *this)
222  ch = traits_t::to_upper(ch);
223 }
224 
225 template<class char_t, class traits_t>
226 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::front() const noexcept
227 {
228  return at(0);
229 }
230 
231 template<class char_t, class traits_t>
232 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::back() const noexcept
233 {
234  return at(size() - 1);
235 }
236 
237 template<class char_t, class traits_t>
238 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::length() const noexcept
239 {
240  return size();
241 }
242 
243 template<class char_t, class traits_t>
244 inline typename basic_string<char_t, traits_t>::const_pointer basic_string<char_t, traits_t>::c_str() const noexcept
245 {
246  return data();
247 }
248 
249 template<class char_t, class traits_t>
250 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::capacity() const noexcept
251 {
252  return m_Data.capacity() / sizeof(value_type) - 1; // - null terminator
253 }
254 
255 template<class char_t, class traits_t>
256 constexpr typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::max_size() noexcept
257 {
258  return std::numeric_limits<size_type>::max() - 1 // npos reserved
259  - 1; // null terminator
260 }
261 
262 template<class char_t, class traits_t>
263 template<class to_t>
264 inline std::optional<to_t> basic_string<char_t, traits_t>::to(const_pointer pszFormat) const noexcept
265 {
266  std::optional<to_t> optResult = std::nullopt;
267 
268  if constexpr (
269  std::is_trivial_v<to_t> && std::is_standard_layout_v<to_t> || std::is_pointer_v<to_t>
270  || std::is_same_v<to_t, std::nullptr_t>)
271  {
272  if constexpr (std::is_same_v<to_t, std::nullptr_t>)
273  {
274  if (compare(QX_STR_PREFIX(typename traits_t::value_type, "nullptr")) == 0)
275  {
276  optResult = nullptr;
277  }
278  }
279  else if constexpr (std::is_same_v<to_t, bool>)
280  {
281  if (compare(QX_STR_PREFIX(typename traits_t::value_type, "true")) == 0)
282  {
283  optResult = true;
284  }
285  else if (compare(QX_STR_PREFIX(typename traits_t::value_type, "false")) == 0)
286  {
287  optResult = false;
288  }
289  }
290  else if (const auto pszSelectedFormat = pszFormat ? pszFormat : get_format_specifier<value_type, to_t>())
291  {
292  constexpr string_view svNSpecifier(QX_STR_PREFIX(value_type, "%n"));
293  constexpr size_t nBufferSize = 256;
294 
295  const size_t nFormatSpecifierLength = traits_t::length(pszSelectedFormat);
296  if (nFormatSpecifierLength <= nBufferSize - svNSpecifier.size() - 1)
297  {
298  value_type formatBuffer[nBufferSize];
299  std::memcpy(formatBuffer, pszSelectedFormat, nFormatSpecifierLength * sizeof(value_type));
300  std::memcpy(
301  formatBuffer + nFormatSpecifierLength,
302  svNSpecifier.data(),
303  svNSpecifier.size() * sizeof(value_type));
304  formatBuffer[nFormatSpecifierLength + svNSpecifier.size()] = QX_CHAR_PREFIX(value_type, '\0');
305 
306  to_t result;
307  int nSymbolsRead;
308  const int nConvertedArgs = traits_t::sscanf(data(), formatBuffer, &result, &nSymbolsRead);
309 
310  if (static_cast<size_type>(nSymbolsRead) == size() && nConvertedArgs == 1)
311  optResult = result;
312  }
313  }
314  }
315  else
316  {
317  to_t result;
318  sstream_type ss(data());
319  ss >> result;
320  optResult = result;
321  }
322 
323  return optResult;
324 }
325 
326 template<class char_t, class traits_t>
327 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::copy(
328  pointer pDest,
329  size_type nCount,
330  size_type nPos) const noexcept
331 {
332  size_type nCharsToCopy = 0;
333 
334  if (pDest && nCount > 0 && nPos < size())
335  {
336  nCharsToCopy = std::min(nPos + nCount, size()) - nPos;
337  std::memcpy(pDest, data() + nPos, nCharsToCopy * sizeof(value_type));
338  }
339 
340  return nCharsToCopy;
341 }
342 
343 template<class char_t, class traits_t>
344 template<class from_t>
345 inline void basic_string<char_t, traits_t>::from(const from_t& data)
346 {
347  if constexpr (
348  std::is_trivial_v<from_t> && std::is_standard_layout_v<from_t> || std::is_pointer_v<from_t>
349  || std::is_same_v<from_t, std::nullptr_t>)
350  {
351  if constexpr (std::is_same_v<from_t, std::nullptr_t>)
352  {
353  assign(QX_STR_PREFIX(typename traits_t::value_type, "nullptr"));
354  }
355  else if constexpr (std::is_same_v<from_t, bool>)
356  {
357  assign(
358  data ? QX_STR_PREFIX(typename traits_t::value_type, "true")
359  : QX_STR_PREFIX(typename traits_t::value_type, "false"));
360  }
361  else
362  {
363  format(QX_STR_PREFIX(typename traits_t::value_type, "{}"), data);
364  }
365  }
366  else
367  {
368  sstream_type ss;
369  ss << data;
370  assign(ss.str());
371  }
372 }
373 
374 template<class char_t, class traits_t>
375 template<class from_t>
377 {
378  basic_string sTemp;
379  sTemp.from(data);
380  return std::move(sTemp);
381 }
382 
383 template<class char_t, class traits_t>
384 inline void basic_string<char_t, traits_t>::append(value_type chSymbol) noexcept
385 {
386  append(&chSymbol, 1);
387 }
388 
389 template<class char_t, class traits_t>
390 inline void basic_string<char_t, traits_t>::append(const_pointer pszStr, size_type nSymbols) noexcept
391 {
392  if (pszStr)
393  {
394  const size_type nSize = size();
395  const size_type nSizeSource = nSymbols == npos ? traits_t::length(pszStr) : nSymbols;
396 
397  if (_resize(nSize + nSizeSource))
398  std::memcpy(data() + nSize, pszStr, nSizeSource * sizeof(value_type));
399  }
400 }
401 
402 template<class char_t, class traits_t>
403 inline void basic_string<char_t, traits_t>::append(const basic_string& sStr) noexcept
404 {
405  append(sStr.data(), sStr.size());
406 }
407 
408 template<class char_t, class traits_t>
409 template<class fwd_it_t>
410 inline void basic_string<char_t, traits_t>::append(fwd_it_t itBegin, fwd_it_t itEnd) noexcept
411 {
412  for (auto it = itBegin; it != itEnd; ++it)
413  push_back(*it);
414 }
415 
416 template<class char_t, class traits_t>
417 template<range_of_t_c<char_t> string_t>
418 inline void basic_string<char_t, traits_t>::append(const string_t& sStr) noexcept
419 {
420  append(sStr.cbegin(), sStr.cend());
421 }
422 
423 template<class char_t, class traits_t>
424 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
425  size_type nPos,
426  value_type chSymbol) noexcept
427 {
428  return insert(nPos, &chSymbol, 1);
429 }
430 
431 template<class char_t, class traits_t>
432 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
433  size_type nPos,
434  const_pointer pszWhat,
435  size_type nSymbols) noexcept
436 {
437  if (pszWhat)
438  {
439  const size_type nSize = size();
440  const size_type nSizeSource = nSymbols == npos ? traits_t::length(pszWhat) : nSymbols;
441 
442  if (nSizeSource > 0 && _resize(nSize + nSizeSource))
443  {
444  std::memmove(data() + nPos + nSizeSource, data() + nPos, (nSize - nPos) * sizeof(value_type));
445  std::memcpy(data() + nPos, pszWhat, nSizeSource * sizeof(value_type));
446  return nPos + nSizeSource;
447  }
448  }
449 
450  return npos;
451 }
452 
453 template<class char_t, class traits_t>
454 template<class fwd_it_t>
455 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
456  size_type nPos,
457  fwd_it_t itWhatBegin,
458  fwd_it_t itWhatEnd) noexcept
459 {
460  if constexpr (is_random_access_iterator<fwd_it_t>)
461  {
462  return insert(nPos, itWhatBegin.operator->(), static_cast<size_type>(itWhatEnd - itWhatBegin));
463  }
464  else
465  {
466  size_type nWhatSize = 0;
467  for (auto it = itWhatBegin; it != itWhatEnd; ++it)
468  ++nWhatSize;
469 
470  size_type nStartSymbols = size();
471  if (nWhatSize > 0 && _resize(nStartSymbols + nWhatSize))
472  {
473  std::memmove(data() + nPos + nWhatSize, data() + nPos, (nStartSymbols - nPos) * sizeof(value_type));
474 
475  size_type nWhatPos = 0;
476  for (auto it = itWhatBegin; it != itWhatEnd; ++it)
477  {
478  at(nPos + nWhatPos) = *it;
479  ++nWhatPos;
480  }
481 
482  return nPos + nWhatSize;
483  }
484  else
485  {
486  return npos;
487  }
488  }
489 }
490 
491 template<class char_t, class traits_t>
492 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
493  size_type nPos,
494  const basic_string& sWhat) noexcept
495 {
496  return insert(nPos, sWhat.data(), sWhat.size());
497 }
498 
499 template<class char_t, class traits_t>
500 template<range_of_t_c<char_t> string_t>
501 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
502  size_type nPos,
503  string_t sWhat) noexcept
504 {
505  return insert(static_cast<size_type>(nPos), sWhat.cbegin(), sWhat.cend());
506 }
507 
508 template<class char_t, class traits_t>
509 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
510  const_iterator itPos,
511  value_type chSymbol) noexcept
512 {
513  return insert(static_cast<size_type>(itPos - cbegin()), chSymbol);
514 }
515 
516 template<class char_t, class traits_t>
517 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
518  const_iterator itPos,
519  const_pointer pszWhat,
520  size_type nSymbols) noexcept
521 {
522  return insert(static_cast<size_type>(itPos - cbegin()), pszWhat, nSymbols);
523 }
524 
525 template<class char_t, class traits_t>
526 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
527  const_iterator itPos,
528  const basic_string& sWhat) noexcept
529 {
530  return insert(static_cast<size_type>(itPos - cbegin()), sWhat.data(), sWhat.size());
531 }
532 
533 template<class char_t, class traits_t>
534 template<class fwd_it_t>
535 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
537  fwd_it_t itWhatBegin,
538  fwd_it_t itWhatEnd) noexcept
539 {
540  return insert(static_cast<size_type>(itPos - begin()), itWhatBegin, itWhatEnd);
541 }
542 
543 template<class char_t, class traits_t>
544 template<range_of_t_c<char_t> string_t>
545 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
546  const_iterator itPos,
547  string_t sWhat) noexcept
548 {
549  return insert(static_cast<size_type>(itPos - begin()), sWhat.cbegin(), sWhat.cend());
550 }
551 
552 template<class char_t, class traits_t>
553 inline void basic_string<char_t, traits_t>::push_back(value_type chSymbol) noexcept
554 {
555  insert(size(), &chSymbol, 1);
556 }
557 
558 template<class char_t, class traits_t>
559 inline void basic_string<char_t, traits_t>::push_front(value_type chSymbol) noexcept
560 {
561  insert(0, &chSymbol, 1);
562 }
563 
564 template<class char_t, class traits_t>
565 inline void basic_string<char_t, traits_t>::erase(iterator itFirst, iterator itLast) noexcept
566 {
567  if (const typename iterator::difference_type nCharsToErase = itLast - itFirst; nCharsToErase > 0)
568  {
569  const size_type nStartSize = size();
570  const size_type nSymbolsToCopy = itLast != end() ? traits_t::length(itLast.operator->()) : 0;
571 
572  if (nSymbolsToCopy > 0)
573  {
574  std::memmove(itFirst.operator->(), itLast.operator->(), nSymbolsToCopy * sizeof(value_type));
575  }
576 
577  if (static_cast<typename iterator::difference_type>(nStartSize) >= nCharsToErase)
578  {
579  _resize(nStartSize - nCharsToErase);
580  }
581  }
582 }
583 
584 template<class char_t, class traits_t>
586 {
587  erase(itPos, itPos + 1);
588 }
589 
590 template<class char_t, class traits_t>
591 inline void basic_string<char_t, traits_t>::erase(size_type nPos) noexcept
592 {
593  erase(iterator(this, nPos), iterator(this, nPos + 1));
594 }
595 
596 template<class char_t, class traits_t>
597 inline void basic_string<char_t, traits_t>::erase(size_type nPos, size_type nSymbols) noexcept
598 {
599  erase(iterator(this, nPos), iterator(this, nPos + nSymbols));
600 }
601 
602 template<class char_t, class traits_t>
603 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::pop_back() noexcept
604 {
605  value_type chRet = back();
606  erase(size() - 1);
607  return chRet;
608 }
609 
610 template<class char_t, class traits_t>
611 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::pop_front() noexcept
612 {
613  value_type chRet = front();
614  erase(0);
615  return chRet;
616 }
617 
618 template<class char_t, class traits_t>
619 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left() noexcept
620 {
621  return _trim_left(
622  [](value_type ch)
623  {
624  return traits_t::is_space(ch);
625  });
626 }
627 
628 template<class char_t, class traits_t>
629 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
630  value_type chSymbol) noexcept
631 {
632  return _trim_left(
633  [chSymbol](value_type ch)
634  {
635  return ch == chSymbol;
636  });
637 }
638 
639 template<class char_t, class traits_t>
640 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
641  const_pointer pszStr) noexcept
642 {
643  if (pszStr)
644  {
645  return _trim_left(
646  [pszStr](value_type ch)
647  {
648  for (size_type j = 0; pszStr[j] != QX_CHAR_PREFIX(value_type, '\0'); ++j)
649  {
650  if (pszStr[j] == ch)
651  return true;
652  }
653 
654  return false;
655  });
656  }
657  else
658  {
659  return 0;
660  }
661 }
662 
663 template<class char_t, class traits_t>
664 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
665  const_pointer pszStr,
666  size_type nStrSize) noexcept
667 {
668  if (pszStr)
669  {
670  return _trim_left(
671  [pszStr, nStrSize](value_type ch)
672  {
673  for (size_type j = 0; j < nStrSize; ++j)
674  if (pszStr[j] == ch)
675  return true;
676 
677  return false;
678  });
679  }
680  else
681  {
682  return 0;
683  }
684 }
685 
686 template<class char_t, class traits_t>
687 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
688  const basic_string& sStr) noexcept
689 {
690  return trim_left(sStr.data(), sStr.size());
691 }
692 
693 template<class char_t, class traits_t>
694 template<class fwd_it_t>
695 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
696  fwd_it_t itBegin,
697  fwd_it_t itEnd) noexcept
698 {
699  return _trim_left(
700  [itBegin, itEnd](auto ch)
701  {
702  for (auto it = itBegin; it != itEnd; ++it)
703  if (*it == ch)
704  return true;
705 
706  return false;
707  });
708 }
709 
710 template<class char_t, class traits_t>
711 template<range_of_t_c<char_t> string_t>
712 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
713  const string_t& sStr) noexcept
714 {
715  return trim_left(sStr.cbegin(), sStr.cend());
716 }
717 
718 template<class char_t, class traits_t>
719 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right() noexcept
720 {
721  return _trim_right(
722  [](value_type ch)
723  {
724  return traits_t::is_space(ch);
725  });
726 }
727 
728 template<class char_t, class traits_t>
729 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
730  value_type chSymbol) noexcept
731 {
732  return _trim_right(
733  [chSymbol](value_type ch)
734  {
735  return ch == chSymbol;
736  });
737 }
738 
739 template<class char_t, class traits_t>
740 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
741  const_pointer pszStr) noexcept
742 {
743  if (pszStr)
744  {
745  return _trim_right(
746  [pszStr](value_type ch)
747  {
748  for (size_type j = 0; pszStr[j] != QX_CHAR_PREFIX(value_type, '\0'); ++j)
749  {
750  if (pszStr[j] == ch)
751  return true;
752  }
753 
754  return false;
755  });
756  }
757  else
758  {
759  return 0;
760  }
761 }
762 
763 template<class char_t, class traits_t>
764 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
765  const_pointer pszStr,
766  size_type nStrSize) noexcept
767 {
768  if (pszStr)
769  {
770  return _trim_right(
771  [pszStr, nStrSize](value_type ch)
772  {
773  for (size_type j = 0; j < nStrSize; ++j)
774  if (pszStr[j] == ch)
775  return true;
776 
777  return false;
778  });
779  }
780  else
781  {
782  return 0;
783  }
784 }
785 
786 template<class char_t, class traits_t>
787 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
788  const basic_string& sStr) noexcept
789 {
790  return trim_right(sStr.data(), sStr.size());
791 }
792 
793 template<class char_t, class traits_t>
794 template<class fwd_it_t>
795 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
796  fwd_it_t itBegin,
797  fwd_it_t itEnd) noexcept
798 {
799  return _trim_right(
800  [itBegin, itEnd](auto ch)
801  {
802  for (auto it = itBegin; it != itEnd; ++it)
803  if (*it == ch)
804  return true;
805 
806  return false;
807  });
808 }
809 
810 template<class char_t, class traits_t>
811 template<range_of_t_c<char_t> string_t>
812 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
813  const string_t& sStr) noexcept
814 {
815  return trim_right(sStr.cbegin(), sStr.cend());
816 }
817 
818 template<class char_t, class traits_t>
819 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim() noexcept
820 {
821  return _trim(
822  [](value_type ch)
823  {
824  return traits_t::is_space(ch);
825  });
826 }
827 
828 template<class char_t, class traits_t>
829 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
830  value_type chSymbol) noexcept
831 {
832  return _trim(
833  [chSymbol](value_type ch)
834  {
835  return ch == chSymbol;
836  });
837 }
838 
839 template<class char_t, class traits_t>
840 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
841  const_pointer pszStr) noexcept
842 {
843  if (pszStr)
844  {
845  return _trim(
846  [pszStr](value_type ch)
847  {
848  for (size_type j = 0; pszStr[j] != QX_CHAR_PREFIX(value_type, '\0'); ++j)
849  {
850  if (pszStr[j] == ch)
851  return true;
852  }
853 
854  return false;
855  });
856  }
857  else
858  {
859  return 0;
860  }
861 }
862 
863 template<class char_t, class traits_t>
864 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
865  const_pointer pszStr,
866  size_type nStrSize) noexcept
867 {
868  if (pszStr)
869  {
870  return _trim(
871  [pszStr, nStrSize](value_type ch)
872  {
873  for (size_type j = 0; j < nStrSize; ++j)
874  if (pszStr[j] == ch)
875  return true;
876 
877  return false;
878  });
879  }
880  else
881  {
882  return 0;
883  }
884 }
885 
886 template<class char_t, class traits_t>
887 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
888  const basic_string& sStr) noexcept
889 {
890  return trim(sStr.data(), sStr.size());
891 }
892 
893 template<class char_t, class traits_t>
894 template<class fwd_it_t>
895 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
896  fwd_it_t itBegin,
897  fwd_it_t itEnd) noexcept
898 {
899  return _trim(
900  [itBegin, itEnd](auto ch)
901  {
902  for (auto it = itBegin; it != itEnd; ++it)
903  if (*it == ch)
904  return true;
905 
906  return false;
907  });
908 }
909 
910 template<class char_t, class traits_t>
911 template<range_of_t_c<char_t> string_t>
912 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
913  const string_t& sStr) noexcept
914 {
915  return trim(sStr.cbegin(), sStr.cend());
916 }
917 
918 template<class char_t, class traits_t>
919 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
920  value_type chSymbol,
921  size_type nBegin,
922  size_type nEnd) noexcept
923 {
924  size_type nPos = find(chSymbol, nBegin, nEnd);
925 
926  if (nPos != npos)
927  erase(nPos, 1);
928 
929  return nPos;
930 }
931 
932 template<class char_t, class traits_t>
933 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
934  const_pointer pszStr,
935  size_type nBegin,
936  size_type nEnd,
937  size_type nStrSize) noexcept
938 {
939  if (pszStr)
940  {
941  const size_type nLocalStrSize = nStrSize != npos ? nStrSize : traits_t::length(pszStr);
942  const size_type nPos = find(pszStr, nBegin, nLocalStrSize, nEnd);
943 
944  if (nPos != npos)
945  erase(nPos, nLocalStrSize);
946 
947  return nPos;
948  }
949  else
950  {
951  return npos;
952  }
953 }
954 
955 template<class char_t, class traits_t>
956 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
957  const basic_string& sStr,
958  size_type nBegin,
959  size_type nEnd) noexcept
960 {
961  const size_type nPos = find(sStr, nBegin, nEnd);
962 
963  if (nPos != npos)
964  erase(nPos, sStr.size());
965 
966  return nPos;
967 }
968 
969 template<class char_t, class traits_t>
970 template<class fwd_it_t>
971 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
972  fwd_it_t itBegin,
973  fwd_it_t itEnd,
974  size_type nBegin,
975  size_type nEnd) noexcept
976 {
977  const size_type nPos = find(itBegin, itEnd, nBegin, nEnd);
978 
979  if (nPos != npos)
980  erase(nPos, static_cast<size_type>(std::distance(itBegin, itEnd)));
981 
982  return nPos;
983 }
984 
985 template<class char_t, class traits_t>
986 template<range_of_t_c<char_t> string_t>
987 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
988  const string_t& sStr,
989  size_type nBegin,
990  size_type nEnd) noexcept
991 {
992  return remove(sStr.cbegin(), sStr.cend(), nBegin, nEnd);
993 }
994 
995 template<class char_t, class traits_t>
996 inline bool basic_string<char_t, traits_t>::remove_prefix(value_type chSymbol) noexcept
997 {
998  return remove(chSymbol, static_cast<size_type>(0), static_cast<size_type>(1)) != npos;
999 }
1001 template<class char_t, class traits_t>
1002 inline bool basic_string<char_t, traits_t>::remove_prefix(const_pointer pszStr, size_type nStrSize) noexcept
1003 {
1004  return remove(pszStr, static_cast<size_type>(0), nStrSize, nStrSize) != npos;
1005 }
1006 
1007 template<class char_t, class traits_t>
1009 {
1010  return remove(sStr, static_cast<size_type>(0), sStr.size()) != npos;
1011 }
1013 template<class char_t, class traits_t>
1014 template<class fwd_it_t>
1015 inline bool basic_string<char_t, traits_t>::remove_prefix(fwd_it_t itBegin, fwd_it_t itEnd) noexcept
1016 {
1017  return remove(itBegin, itEnd, static_cast<size_type>(0), static_cast<size_type>(std::distance(itBegin, itEnd)))
1018  != npos;
1019 }
1020 
1021 template<class char_t, class traits_t>
1022 template<range_of_t_c<char_t> string_t>
1023 inline bool basic_string<char_t, traits_t>::remove_prefix(const string_t& sStr) noexcept
1024 {
1025  return remove_prefix(sStr.cbegin(), sStr.cend());
1026 }
1027 
1028 template<class char_t, class traits_t>
1029 inline bool basic_string<char_t, traits_t>::remove_suffix(value_type chSymbol) noexcept
1030 {
1031  const size_type nSize = size();
1032  return remove(chSymbol, nSize - 1, nSize) != npos;
1033 }
1034 
1035 template<class char_t, class traits_t>
1036 inline bool basic_string<char_t, traits_t>::remove_suffix(const_pointer pszStr, size_type nStrSize) noexcept
1038  if (pszStr)
1039  {
1040  const size_type nSize = size();
1041  const size_type nLocalStrSize = nStrSize != npos ? nStrSize : traits_t::length(pszStr);
1042 
1043  return remove(pszStr, nSize - nLocalStrSize, nSize, nLocalStrSize) != npos;
1044  }
1045  else
1046  {
1047  return false;
1048  }
1049 }
1051 template<class char_t, class traits_t>
1053 {
1054  return remove_suffix(sStr.data(), sStr.size());
1055 }
1056 
1057 template<class char_t, class traits_t>
1058 template<class fwd_it_t>
1059 inline bool basic_string<char_t, traits_t>::remove_suffix(fwd_it_t itBegin, fwd_it_t itEnd) noexcept
1060 {
1061  const size_type nSize = size();
1062  return remove(itBegin, itEnd, nSize - static_cast<size_type>(std::distance(itBegin, itEnd)), nSize) != npos;
1063 }
1064 
1065 template<class char_t, class traits_t>
1066 template<range_of_t_c<char_t> string_t>
1067 inline bool basic_string<char_t, traits_t>::remove_suffix(const string_t& sStr) noexcept
1068 {
1069  return remove_suffix(sStr.cbegin(), sStr.cend());
1070 }
1071 
1072 template<class char_t, class traits_t>
1073 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1074  value_type chSymbol,
1075  size_type nBegin,
1076  size_type nEnd) noexcept
1077 {
1078  size_type nOccurrences = 0;
1079  size_type nLastOccurrencePos = nBegin;
1080 
1081  do
1082  {
1083  ++nOccurrences;
1084  nLastOccurrencePos = remove(chSymbol, nLastOccurrencePos, nEnd);
1085  } while (nLastOccurrencePos != npos);
1086 
1087  return nOccurrences - 1;
1088 }
1089 
1090 template<class char_t, class traits_t>
1091 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1092  const_pointer pszStr,
1093  size_type nBegin,
1094  size_type nEnd,
1095  size_type nStrSize) noexcept
1096 {
1097  if (pszStr)
1098  {
1099  size_type nOccurrences = 0;
1100  size_type nLastOccurrencePos = nBegin;
1101 
1102  do
1103  {
1104  ++nOccurrences;
1105  nLastOccurrencePos = remove(pszStr, nLastOccurrencePos, nEnd, nStrSize);
1106  } while (nLastOccurrencePos != npos);
1107 
1108  return nOccurrences - 1;
1109  }
1110  else
1111  {
1112  return 0;
1113  }
1114 }
1115 
1116 template<class char_t, class traits_t>
1117 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1118  const basic_string& sStr,
1119  size_type nBegin,
1120  size_type nEnd) noexcept
1121 {
1122  return remove_all(sStr.data(), nBegin, nEnd, sStr.size());
1123 }
1125 template<class char_t, class traits_t>
1126 template<class fwd_it_t>
1127 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1128  fwd_it_t itFirst,
1129  fwd_it_t itLast,
1130  size_type nBegin,
1131  size_type nEnd) noexcept
1132 {
1133  size_type nOccurrences = 0;
1134  size_type nLastOccurrencePos = nBegin;
1136  do
1137  {
1138  ++nOccurrences;
1139  nLastOccurrencePos = remove(itFirst, itLast, nLastOccurrencePos, nEnd);
1140  } while (nLastOccurrencePos != npos);
1141 
1142  return nOccurrences - 1;
1143 }
1144 
1145 template<class char_t, class traits_t>
1146 template<range_of_t_c<char_t> string_t>
1147 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1148  const string_t& sStr,
1149  size_type nBegin,
1150  size_type nEnd) noexcept
1151 {
1152  return remove_all(sStr.cbegin(), sStr.cend(), nBegin, nEnd);
1153 }
1154 
1155 template<class char_t, class traits_t>
1156 typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace(
1157  size_type nBegin,
1158  size_type nSize,
1159  const_pointer pszReplace,
1160  size_t nReplaceSize) noexcept
1162  const size_type nStartSize = size();
1163  const size_type nNewSize = nStartSize - nSize + nReplaceSize;
1164 
1165  _resize(nNewSize, sbo_resize_type::reserve);
1166 
1167  std::memmove(
1168  data() + nBegin + nReplaceSize,
1169  data() + nBegin + nSize,
1170  (nStartSize - nBegin - nSize) * sizeof(value_type));
1171 
1172  std::memcpy(data() + nBegin, pszReplace, nReplaceSize * sizeof(value_type));
1173 
1174  _resize(nNewSize);
1175 
1176  return nBegin + nReplaceSize;
1177 }
1179 template<class char_t, class traits_t>
1180 template<class replace_string_t>
1181 typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace(
1182  size_type nBegin,
1183  size_type nSize,
1184  const replace_string_t& sReplace) noexcept
1185 {
1186  return replace(nBegin, nSize, _get_string_view_like_data(sReplace), _get_string_view_like_size(sReplace));
1187 }
1188 
1189 template<class char_t, class traits_t>
1190 template<class find_string_t, class replace_string_t>
1191 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace(
1192  const find_string_t& sFind,
1193  const replace_string_t& sReplace,
1194  size_type nBegin,
1195  size_type nEnd) noexcept
1196 {
1197  if (size_type nPos = find(sFind, nBegin, nEnd); nPos != npos)
1198  {
1199  return replace(
1200  nPos,
1201  _get_string_view_like_size(sFind),
1202  _get_string_view_like_data(sReplace),
1203  _get_string_view_like_size(sReplace));
1204  }
1205  else
1206  {
1207  return npos;
1208  }
1209 }
1210 
1211 template<class char_t, class traits_t>
1212 template<class find_string_t, class replace_string_t>
1213 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace_all(
1214  const find_string_t& sFind,
1215  const replace_string_t& sReplace,
1216  size_type nBegin,
1217  size_type nEnd) noexcept
1218 {
1219  size_type nOccurrences = 0;
1220  size_type nPos = nBegin;
1221 
1222  do
1223  {
1224  nPos = replace(sFind, sReplace, nPos, nEnd);
1225  if (nPos != npos)
1226  ++nOccurrences;
1227  } while (nPos != npos);
1228 
1229  return nOccurrences;
1230 }
1231 
1232 template<class char_t, class traits_t>
1233 inline int basic_string<char_t, traits_t>::compare(value_type chSymbol) const noexcept
1234 {
1235  return compare(&chSymbol, 1);
1236 }
1237 
1238 template<class char_t, class traits_t>
1239 inline int basic_string<char_t, traits_t>::compare(const_pointer pszStr) const noexcept
1241  return traits_t::compare(data(), pszStr);
1242 }
1243 
1244 template<class char_t, class traits_t>
1245 inline int basic_string<char_t, traits_t>::compare(const_pointer pStr, size_type nSymbols) const noexcept
1246 {
1247  return traits_t::compare_n(data(), pStr, nSymbols);
1249 
1250 template<class char_t, class traits_t>
1251 inline int basic_string<char_t, traits_t>::compare(const basic_string& sStr) const noexcept
1252 {
1253  return compare(sStr.data(), sStr.size());
1254 }
1255 
1256 template<class char_t, class traits_t>
1257 template<class fwd_it_t>
1258 inline int basic_string<char_t, traits_t>::compare(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1260  return iter_strcmp(cbegin(), cend(), itBegin, itEnd);
1261 }
1262 
1263 template<class char_t, class traits_t>
1264 template<range_of_t_c<char_t> string_t>
1265 inline int basic_string<char_t, traits_t>::compare(const string_t& sStr) const noexcept
1266 {
1267  return compare(sStr.cbegin(), sStr.cend());
1268 }
1270 template<class char_t, class traits_t>
1271 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1272  value_type chSymbol,
1273  size_type nBegin,
1274  size_type nEnd) const noexcept
1275 {
1276  return _find(
1277  nBegin,
1278  nEnd,
1279  [chSymbol](const_pointer pCurrentChar)
1280  {
1281  return *pCurrentChar == chSymbol;
1282  });
1283 }
1284 
1285 template<class char_t, class traits_t>
1286 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1287  const_pointer pszWhat,
1288  size_type nBegin,
1289  size_type nWhatSize,
1290  size_type nEnd) const noexcept
1291 {
1292  if (pszWhat)
1293  {
1294  const size_type nLocalWhatSize = nWhatSize != npos ? nWhatSize : traits_t::length(pszWhat);
1295 
1296  return _find(
1297  nBegin,
1298  nEnd,
1299  [pszWhat, nLocalWhatSize](const_pointer pCurrentChar)
1300  {
1301  return !traits_t::compare_n(pszWhat, pCurrentChar, nLocalWhatSize);
1302  });
1303  }
1304  else
1305  {
1306  return npos;
1307  }
1308 }
1309 
1310 template<class char_t, class traits_t>
1311 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1312  const basic_string& sWhat,
1313  size_type nBegin,
1314  size_type nEnd) const noexcept
1315 {
1316  return find(sWhat.data(), nBegin, sWhat.size(), nEnd);
1317 }
1318 
1319 template<class char_t, class traits_t>
1320 template<class fwd_it_t>
1321 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1322  fwd_it_t itWhatBegin,
1323  fwd_it_t itWhatEnd,
1324  size_type nBegin,
1325  size_type nEnd) const noexcept
1326 {
1327  const size_t nWhatSize = itWhatEnd - itWhatBegin;
1328  return _find(
1329  nBegin,
1330  nEnd,
1331  [this, itWhatBegin, itWhatEnd, nWhatSize](const_pointer pCurrentChar)
1332  {
1333  const size_t nStart = static_cast<size_type>(pCurrentChar - data());
1334  return !iter_strcmp(
1335  const_iterator(this, nStart),
1336  const_iterator(this, nStart + nWhatSize),
1337  itWhatBegin,
1338  itWhatEnd);
1339  });
1341 
1342 template<class char_t, class traits_t>
1343 template<range_of_t_c<char_t> string_t>
1344 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1345  string_t sWhat,
1346  size_type nBegin,
1347  size_type nEnd) const noexcept
1349  return find(sWhat.cbegin(), sWhat.cend(), nBegin, nEnd);
1350 }
1351 
1352 template<class char_t, class traits_t>
1353 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1354  value_type chSymbol,
1355  size_type nBegin,
1356  size_type nEnd) const noexcept
1357 {
1358  return _rfind(
1359  nBegin,
1360  nEnd,
1361  [chSymbol](const_pointer pCurrentChar)
1362  {
1363  return *pCurrentChar == chSymbol;
1364  });
1365 }
1366 
1367 template<class char_t, class traits_t>
1368 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1369  const_pointer pszWhat,
1370  size_type nBegin,
1371  size_type nWhatSize,
1372  size_type nEnd) const noexcept
1373 {
1374  if (pszWhat)
1375  {
1376  const size_type nLocalWhatSize = nWhatSize != npos ? nWhatSize : traits_t::length(pszWhat);
1378  return _rfind(
1379  nBegin,
1380  nEnd,
1381  [pszWhat, nLocalWhatSize](const_pointer pCurrentChar)
1382  {
1383  return !traits_t::compare_n(pszWhat, pCurrentChar, nLocalWhatSize);
1384  });
1385  }
1386  else
1387  {
1388  return npos;
1389  }
1390 }
1391 
1392 template<class char_t, class traits_t>
1393 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1394  const basic_string& sWhat,
1395  size_type nBegin,
1396  size_type nEnd) const noexcept
1397 {
1398  return rfind(sWhat.data(), nBegin, sWhat.size(), nEnd);
1400 
1401 template<class char_t, class traits_t>
1402 template<class fwd_it_t>
1403 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1404  fwd_it_t itWhatBegin,
1405  fwd_it_t itWhatEnd,
1406  size_type nBegin,
1407  size_type nEnd) const noexcept
1408 {
1409  const size_t nWhatSize = itWhatEnd - itWhatBegin;
1410  return _rfind(
1411  nBegin,
1412  nEnd,
1413  [this, itWhatBegin, itWhatEnd, nWhatSize](const_pointer pCurrentChar)
1414  {
1415  const size_t nStart = static_cast<size_type>(pCurrentChar - data());
1416  return !iter_strcmp(
1417  const_iterator(this, nStart),
1418  const_iterator(this, nStart + nWhatSize),
1419  itWhatBegin,
1420  itWhatEnd);
1421  });
1422 }
1423 
1424 template<class char_t, class traits_t>
1425 template<range_of_t_c<char_t> string_t>
1426 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1427  string_t sWhat,
1428  size_type nBegin,
1429  size_type nEnd) const noexcept
1430 {
1431  return rfind(sWhat.cbegin(), sWhat.cend(), nBegin, nEnd);
1432 }
1434 template<class char_t, class traits_t>
1435 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1436  value_type chSymbol,
1437  size_type nBegin) const noexcept
1438 {
1439  return find(chSymbol, nBegin);
1441 
1442 template<class char_t, class traits_t>
1443 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1444  const_pointer pszWhat,
1445  size_type nBegin,
1446  size_type nWhatSize) const noexcept
1447 {
1448  if (pszWhat)
1449  {
1450  return _find_first_of(
1451  pszWhat,
1452  pszWhat + nWhatSize,
1453  nBegin,
1454  [](const_pointer pChar)
1455  {
1456  return pChar + 1;
1457  });
1458  }
1459  else
1460  {
1461  return npos;
1462  }
1463 }
1464 
1465 template<class char_t, class traits_t>
1466 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1467  const_pointer pszWhat,
1468  size_type nBegin) const noexcept
1469 {
1470  if (pszWhat)
1471  {
1472  return _find_first_of(
1473  pszWhat,
1474  static_cast<const_pointer>(nullptr),
1475  nBegin,
1476  [](const_pointer pChar)
1477  {
1478  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1479  });
1480  }
1481  else
1482  {
1483  return npos;
1484  }
1485 }
1486 
1487 template<class char_t, class traits_t>
1488 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1489  const basic_string& sWhat,
1490  size_type nBegin) const noexcept
1492  return find_first_of(sWhat.data(), nBegin, sWhat.size());
1493 }
1494 
1495 template<class char_t, class traits_t>
1496 template<class fwd_it_t>
1497 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1498  fwd_it_t itWhatBegin,
1499  fwd_it_t itWhatEnd,
1500  size_type nBegin) const noexcept
1501 {
1502  return _find_first_of(
1503  itWhatBegin,
1504  itWhatEnd,
1505  nBegin,
1506  [](fwd_it_t itChar)
1507  {
1508  return ++itChar;
1509  });
1510 }
1511 
1512 template<class char_t, class traits_t>
1513 template<range_of_t_c<char_t> string_t>
1514 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1515  string_t sWhat,
1516  size_type nBegin) const noexcept
1518  return find_first_of(sWhat.cbegin(), sWhat.cend(), nBegin);
1519 }
1520 
1521 template<class char_t, class traits_t>
1522 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1523  value_type chSymbol,
1524  size_type nEnd) const noexcept
1526  return rfind(chSymbol, npos, nEnd);
1527 }
1528 
1529 template<class char_t, class traits_t>
1530 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1531  const_pointer pszWhat,
1532  size_type nEnd,
1533  size_type nWhatSize) const noexcept
1534 {
1535  if (pszWhat)
1536  {
1537  return _find_last_of(
1538  pszWhat,
1539  pszWhat + nWhatSize,
1540  nEnd,
1541  [](const_pointer pChar)
1542  {
1543  return pChar + 1;
1544  });
1545  }
1546  else
1547  {
1548  return npos;
1549  }
1550 }
1551 
1552 template<class char_t, class traits_t>
1553 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1554  const_pointer pszWhat,
1555  size_type nEnd) const noexcept
1556 {
1557  if (pszWhat)
1558  {
1559  return _find_last_of(
1560  pszWhat,
1561  static_cast<const_pointer>(nullptr),
1562  nEnd,
1563  [](const_pointer pChar)
1564  {
1565  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1566  });
1567  }
1568  else
1569  {
1570  return npos;
1571  }
1572 }
1573 
1574 template<class char_t, class traits_t>
1575 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1576  const basic_string& sWhat,
1577  size_type nEnd) const noexcept
1578 {
1579  return find_last_of(sWhat.data(), nEnd, sWhat.size());
1580 }
1581 
1582 template<class char_t, class traits_t>
1583 template<class fwd_it_t>
1584 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1585  fwd_it_t itWhatBegin,
1586  fwd_it_t itWhatEnd,
1587  size_type nEnd) const noexcept
1588 {
1589  return _find_last_of(
1590  itWhatBegin,
1591  itWhatEnd,
1592  nEnd,
1593  [](fwd_it_t itChar)
1594  {
1595  return ++itChar;
1596  });
1597 }
1598 
1599 template<class char_t, class traits_t>
1600 template<range_of_t_c<char_t> string_t>
1601 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1602  string_t sWhat,
1603  size_type nEnd) const noexcept
1604 {
1605  return find_last_of(sWhat.cbegin(), sWhat.cend(), nEnd);
1606 }
1607 
1608 template<class char_t, class traits_t>
1609 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1610  value_type chSymbol,
1611  size_type nBegin) const noexcept
1612 {
1613  return _find(
1614  nBegin,
1615  npos,
1616  [chSymbol](const_pointer pCurrentChar)
1617  {
1618  return *pCurrentChar != chSymbol;
1619  });
1620 }
1621 
1622 template<class char_t, class traits_t>
1623 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1624  const_pointer pszWhat,
1625  size_type nBegin,
1626  size_type nWhatSize) const noexcept
1627 {
1628  if (pszWhat)
1629  {
1630  return _find_first_not_of(
1631  pszWhat,
1632  pszWhat + nWhatSize,
1633  nBegin,
1634  [](const_pointer pChar)
1635  {
1636  return pChar + 1;
1637  });
1638  }
1639  else
1640  {
1641  return npos;
1642  }
1643 }
1644 
1645 template<class char_t, class traits_t>
1646 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1647  const_pointer pszWhat,
1648  size_type nBegin) const noexcept
1649 {
1650  if (pszWhat)
1651  {
1652  return _find_first_not_of(
1653  pszWhat,
1654  static_cast<const_pointer>(nullptr),
1655  nBegin,
1656  [](const_pointer pChar)
1657  {
1658  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1659  });
1660  }
1661  else
1662  {
1663  return npos;
1664  }
1665 }
1666 
1667 template<class char_t, class traits_t>
1668 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1669  const basic_string& sWhat,
1670  size_type nBegin) const noexcept
1671 {
1672  return find_first_not_of(sWhat.data(), nBegin, sWhat.size());
1673 }
1674 
1675 template<class char_t, class traits_t>
1676 template<class fwd_it_t>
1677 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1678  fwd_it_t itWhatBegin,
1679  fwd_it_t itWhatEnd,
1680  size_type nBegin) const noexcept
1681 {
1682  return _find_first_not_of(
1683  itWhatBegin,
1684  itWhatEnd,
1685  nBegin,
1686  [](fwd_it_t itChar)
1687  {
1688  return ++itChar;
1689  });
1690 }
1691 
1692 template<class char_t, class traits_t>
1693 template<range_of_t_c<char_t> string_t>
1694 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1695  string_t sWhat,
1696  size_type nBegin) const noexcept
1697 {
1698  return find_first_not_of(sWhat.cbegin(), sWhat.cend(), nBegin);
1699 }
1700 
1701 template<class char_t, class traits_t>
1702 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1703  value_type chSymbol,
1704  size_type nEnd) const noexcept
1705 {
1706  return _rfind(
1707  npos,
1708  nEnd,
1709  [chSymbol](const_pointer pCurrentChar)
1710  {
1711  return *pCurrentChar != chSymbol;
1712  });
1713 }
1714 
1715 template<class char_t, class traits_t>
1716 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1717  const_pointer pszWhat,
1718  size_type nEnd,
1719  size_type nWhatSize) const noexcept
1720 {
1721  if (pszWhat)
1722  {
1723  return _find_last_not_of(
1724  pszWhat,
1725  pszWhat + nWhatSize,
1726  nEnd,
1727  [](const_pointer pChar)
1728  {
1729  return pChar + 1;
1730  });
1731  }
1732  else
1733  {
1734  return npos;
1735  }
1736 }
1737 
1738 template<class char_t, class traits_t>
1739 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1740  const_pointer pszWhat,
1741  size_type nEnd) const noexcept
1742 {
1743  if (pszWhat)
1744  {
1745  return _find_last_not_of(
1746  pszWhat,
1747  static_cast<const_pointer>(nullptr),
1748  nEnd,
1749  [](const_pointer pChar)
1750  {
1751  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1752  });
1753  }
1754  else
1755  {
1756  return npos;
1757  }
1758 }
1759 
1760 template<class char_t, class traits_t>
1761 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1762  const basic_string& sWhat,
1763  size_type nEnd) const noexcept
1764 {
1765  return find_last_not_of(sWhat.data(), nEnd, sWhat.size());
1766 }
1767 
1768 template<class char_t, class traits_t>
1769 template<class fwd_it_t>
1770 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1771  fwd_it_t itWhatBegin,
1772  fwd_it_t itWhatEnd,
1773  size_type nEnd) const noexcept
1774 {
1775  return _find_last_not_of(
1776  itWhatBegin,
1777  itWhatEnd,
1778  nEnd,
1779  [](fwd_it_t itChar)
1780  {
1781  return ++itChar;
1782  });
1783 }
1784 
1785 template<class char_t, class traits_t>
1786 template<range_of_t_c<char_t> string_t>
1787 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1788  string_t sWhat,
1789  size_type nEnd) const noexcept
1790 {
1791  return find_last_not_of(sWhat.cbegin(), sWhat.cend(), nEnd);
1792 }
1793 
1794 template<class char_t, class traits_t>
1795 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1796  const value_type chSeparator) const noexcept
1797 {
1798  views tokens;
1799 
1800  size_type nStart = 0;
1801  size_type nEnd = 0;
1802  while ((nEnd = find(chSeparator, nStart)) != npos)
1803  {
1804  tokens.emplace_back(substr(nStart, nEnd - nStart));
1805  nStart = nEnd;
1806  while (traits_t::compare_n(data() + nStart, &chSeparator, 1) == 0)
1807  ++nStart;
1808  }
1809 
1810  if (nStart != size())
1811  tokens.emplace_back(substr(nStart));
1812 
1813  return std::move(tokens);
1814 }
1815 
1816 template<class char_t, class traits_t>
1817 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1818  const_pointer pszSeparator,
1819  size_type nSepLen) const noexcept
1820 {
1821  views tokens;
1822 
1823  if (!pszSeparator)
1824  return tokens;
1825 
1826  if (nSepLen == npos)
1827  nSepLen = traits_t::length(pszSeparator);
1828 
1829  size_type nStart = 0;
1830  size_type nEnd = 0;
1831  while ((nEnd = find(pszSeparator, nStart, nSepLen, npos)) != npos)
1832  {
1833  tokens.emplace_back(substr(nStart, nEnd - nStart));
1834  nStart = nEnd;
1835  while (traits_t::compare_n(data() + nStart, pszSeparator, nSepLen) == 0)
1836  nStart += nSepLen;
1837  }
1838 
1839  if (nStart != size())
1840  tokens.emplace_back(substr(nStart));
1841 
1842  return tokens;
1843 }
1844 
1845 template<class char_t, class traits_t>
1846 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1847  const basic_string& sSeparator) const noexcept
1848 {
1849  return split(sSeparator.data(), sSeparator.size());
1850 }
1851 
1852 template<class char_t, class traits_t>
1853 template<class fwd_it_t>
1854 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1855  fwd_it_t itSepFirst,
1856  fwd_it_t itSepLast) const noexcept
1857 {
1858  views tokens;
1859 
1860  const size_type nSepLen = static_cast<size_type>(std::distance(itSepFirst, itSepLast));
1861 
1862  size_type nStart = 0;
1863  size_type nEnd = 0;
1864  while ((nEnd = find(itSepFirst, itSepLast, nStart)) != npos)
1865  {
1866  tokens.emplace_back(substr(nStart, nEnd - nStart));
1867  nStart = nEnd + nSepLen;
1868  }
1869  tokens.emplace_back(substr(nStart));
1870 
1871  return tokens;
1872 }
1873 
1874 template<class char_t, class traits_t>
1875 template<range_of_t_c<char_t> string_t>
1876 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1877  const string_t& sSeparator) const noexcept
1878 {
1879  return split(sSeparator.cbegin(), sSeparator.cend());
1880 }
1881 
1882 template<class char_t, class traits_t>
1883 inline bool basic_string<char_t, traits_t>::starts_with(value_type chSymbol) const noexcept
1884 {
1885  if (!empty())
1886  return at(0) == chSymbol;
1887  else
1888  return false;
1889 }
1890 
1891 template<class char_t, class traits_t>
1892 inline bool basic_string<char_t, traits_t>::starts_with(const_pointer pszStr, size_type nStrSize) const noexcept
1893 {
1894  if (pszStr)
1895  {
1896  if (size_type nThisSize = size(); nThisSize > 0)
1897  {
1898  if (nStrSize == npos)
1899  nStrSize = traits_t::length(pszStr);
1900 
1901  if (nStrSize <= nThisSize)
1902  return traits_t::compare_n(data(), pszStr, nStrSize) == 0;
1903  }
1904  }
1905 
1906  return false;
1907 }
1908 
1909 template<class char_t, class traits_t>
1910 inline bool basic_string<char_t, traits_t>::starts_with(const basic_string& sStr) const noexcept
1911 {
1912  return starts_with(sStr.data(), sStr.size());
1913 }
1914 
1915 template<class char_t, class traits_t>
1916 template<class fwd_it_t>
1917 inline bool basic_string<char_t, traits_t>::starts_with(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1918 {
1919  auto nStrSize = std::distance(itBegin, itEnd);
1920  return iter_strcmp(cbegin(), cbegin() + static_cast<size_type>(nStrSize), itBegin, itEnd) == 0;
1921 }
1922 
1923 template<class char_t, class traits_t>
1924 template<range_of_t_c<char_t> string_t>
1925 inline bool basic_string<char_t, traits_t>::starts_with(const string_t& sStr) const noexcept
1926 {
1927  return starts_with(sStr.cbegin(), sStr.cend());
1928 }
1929 
1930 template<class char_t, class traits_t>
1931 inline bool basic_string<char_t, traits_t>::ends_with(value_type chSymbol) const noexcept
1932 {
1933  const size_type nSize = size();
1934  if (nSize > 0)
1935  return at(nSize - 1) == chSymbol;
1936  else
1937  return false;
1938 }
1939 
1940 template<class char_t, class traits_t>
1941 inline bool basic_string<char_t, traits_t>::ends_with(const_pointer pszStr, size_type nStrSize) const noexcept
1942 {
1943  if (!pszStr)
1944  return false;
1945 
1946  if (nStrSize == npos)
1947  nStrSize = traits_t::length(pszStr);
1948 
1949  return ends_with(pszStr, pszStr + nStrSize);
1950 }
1951 
1952 template<class char_t, class traits_t>
1953 inline bool basic_string<char_t, traits_t>::ends_with(const basic_string& sStr) const noexcept
1954 {
1955  return ends_with(sStr.data(), sStr.size());
1956 }
1957 
1958 template<class char_t, class traits_t>
1959 template<class fwd_it_t>
1960 inline bool basic_string<char_t, traits_t>::ends_with(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1961 {
1962  const size_t nOtherSize = static_cast<size_type>(std::distance(itBegin, itEnd));
1963  if (nOtherSize > size())
1964  return false;
1965 
1966  return iter_strcmp(cend() - nOtherSize, cend(), itBegin, itEnd) == 0;
1967 }
1968 
1969 template<class char_t, class traits_t>
1970 template<range_of_t_c<char_t> string_t>
1971 inline bool basic_string<char_t, traits_t>::ends_with(const string_t& sStr) const noexcept
1972 {
1973  return ends_with(sStr.cbegin(), sStr.cend());
1974 }
1975 
1976 template<class char_t, class traits_t>
1977 inline bool basic_string<char_t, traits_t>::contains(value_type chSymbol) const noexcept
1978 {
1979  return find(chSymbol) != npos;
1980 }
1981 
1982 template<class char_t, class traits_t>
1983 inline bool basic_string<char_t, traits_t>::contains(const_pointer pszStr, size_type nStrSize) const noexcept
1984 {
1985  return find(pszStr, 0, nStrSize) != npos;
1986 }
1987 
1988 template<class char_t, class traits_t>
1989 inline bool basic_string<char_t, traits_t>::contains(const basic_string& sStr) const noexcept
1990 {
1991  return find(sStr) != npos;
1992 }
1993 
1994 template<class char_t, class traits_t>
1995 template<class fwd_it_t>
1996 inline bool basic_string<char_t, traits_t>::contains(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1997 {
1998  return find(itBegin, itEnd) != npos;
1999 }
2000 
2001 template<class char_t, class traits_t>
2002 template<range_of_t_c<char_t> string_t>
2003 inline bool basic_string<char_t, traits_t>::contains(const string_t& sStr) const noexcept
2004 {
2005  return find(sStr) != npos;
2006 }
2007 
2008 template<class char_t, class traits_t>
2009 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(const_pointer pszSource) noexcept
2010 {
2011  assign(pszSource);
2012  return *this;
2013 }
2014 
2015 template<class char_t, class traits_t>
2016 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(basic_string&& sStr) noexcept
2017 {
2018  assign(std::move(sStr));
2019  return *this;
2020 }
2021 
2022 template<class char_t, class traits_t>
2023 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(const basic_string& sStr) noexcept
2024 {
2025  assign(sStr);
2026  return *this;
2027 }
2028 
2029 template<class char_t, class traits_t>
2030 template<range_of_t_c<char_t> string_t>
2031 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(const string_t& sStr) noexcept
2032 {
2033  assign(sStr);
2034  return *this;
2035 }
2036 
2037 template<class char_t, class traits_t>
2038 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(value_type chSymbol) noexcept
2039 {
2040  append(&chSymbol, 1);
2041  return *this;
2042 }
2043 
2044 template<class char_t, class traits_t>
2045 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(const_pointer pszSource) noexcept
2046 {
2047  if (pszSource)
2048  append(pszSource, traits_t::length(pszSource));
2049 
2050  return *this;
2051 }
2052 
2053 template<class char_t, class traits_t>
2054 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(const basic_string& sStr) noexcept
2055 {
2056  append(sStr.data(), sStr.size());
2057  return *this;
2058 }
2059 
2060 template<class char_t, class traits_t>
2061 template<range_of_t_c<char_t> string_t>
2062 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(const string_t& sStr) noexcept
2063 {
2064  append(sStr.cbegin(), sStr.cend());
2065  return *this;
2066 }
2067 
2068 template<class char_t, class traits_t>
2069 inline bool basic_string<char_t, traits_t>::operator==(value_type chSymbol) const noexcept
2070 {
2071  return size() == 1 && at(0) == chSymbol;
2072 }
2073 
2074 template<class char_t, class traits_t>
2075 inline bool basic_string<char_t, traits_t>::operator==(const_pointer pszSource) const noexcept
2076 {
2077  return compare(pszSource) == 0;
2078 }
2079 
2080 template<class char_t, class traits_t>
2081 inline bool basic_string<char_t, traits_t>::operator==(const basic_string& sStr) const noexcept
2082 {
2083  return size() == sStr.size() && compare(sStr.data(), sStr.size()) == 0;
2084 }
2085 
2086 template<class char_t, class traits_t>
2087 template<range_of_t_c<char_t> string_t>
2088 inline bool basic_string<char_t, traits_t>::operator==(const string_t& sStr) const noexcept
2089 {
2090  return iter_strcmp(cbegin(), cend(), sStr.cbegin(), sStr.cend()) == 0;
2091 }
2092 
2093 template<class char_t, class traits_t>
2094 inline bool basic_string<char_t, traits_t>::operator!=(value_type chSymbol) const noexcept
2095 {
2096  return !operator==(chSymbol);
2097 }
2098 
2099 template<class char_t, class traits_t>
2100 inline bool basic_string<char_t, traits_t>::operator!=(const_pointer pszSource) const noexcept
2101 {
2102  return !operator==(pszSource);
2103 }
2104 
2105 template<class char_t, class traits_t>
2106 inline bool basic_string<char_t, traits_t>::operator!=(const basic_string& sStr) const noexcept
2107 {
2108  return !operator==(sStr);
2109 }
2110 
2111 template<class char_t, class traits_t>
2112 template<range_of_t_c<char_t> string_t>
2113 inline bool basic_string<char_t, traits_t>::operator!=(const string_t& sStr) const noexcept
2114 {
2115  return !operator==(sStr);
2116 }
2117 
2118 template<class char_t, class traits_t>
2119 inline bool basic_string<char_t, traits_t>::operator<(value_type chSymbol) const noexcept
2120 {
2121  return compare(&chSymbol, 1) < 0;
2122 }
2123 
2124 template<class char_t, class traits_t>
2125 inline bool basic_string<char_t, traits_t>::operator<(const_pointer pszSource) const noexcept
2126 {
2127  return compare(pszSource) < 0;
2128 }
2129 
2130 template<class char_t, class traits_t>
2131 inline bool basic_string<char_t, traits_t>::operator<(const basic_string& sStr) const noexcept
2132 {
2133  return compare(sStr.data(), sStr.size()) < 0;
2134 }
2135 
2136 template<class char_t, class traits_t>
2137 template<range_of_t_c<char_t> string_t>
2138 inline bool basic_string<char_t, traits_t>::operator<(const string_t& sStr) const noexcept
2139 {
2140  return iter_strcmp(cbegin(), cend(), sStr.cbegin(), sStr.cend()) < 0;
2141 }
2142 
2143 template<class char_t, class traits_t>
2144 inline bool basic_string<char_t, traits_t>::operator<=(value_type chSymbol) const noexcept
2145 {
2146  return compare(&chSymbol, 1) <= 0;
2147 }
2148 
2149 template<class char_t, class traits_t>
2150 inline bool basic_string<char_t, traits_t>::operator<=(const_pointer pszSource) const noexcept
2151 {
2152  return compare(pszSource) <= 0;
2153 }
2154 
2155 template<class char_t, class traits_t>
2156 inline bool basic_string<char_t, traits_t>::operator<=(const basic_string& sStr) const noexcept
2157 {
2158  return compare(sStr.data(), sStr.size()) <= 0;
2159 }
2160 
2161 template<class char_t, class traits_t>
2162 template<range_of_t_c<char_t> string_t>
2163 inline bool basic_string<char_t, traits_t>::operator<=(const string_t& sStr) const noexcept
2164 {
2165  return iter_strcmp(cbegin(), cend(), sStr.cbegin(), sStr.cend()) <= 0;
2166 }
2167 
2168 template<class char_t, class traits_t>
2169 inline bool basic_string<char_t, traits_t>::operator>(value_type chSymbol) const noexcept
2170 {
2171  return compare(&chSymbol, 1) > 0;
2172 }
2173 
2174 template<class char_t, class traits_t>
2175 inline bool basic_string<char_t, traits_t>::operator>(const_pointer pszSource) const noexcept
2176 {
2177  return compare(pszSource) > 0;
2178 }
2179 
2180 template<class char_t, class traits_t>
2181 inline bool basic_string<char_t, traits_t>::operator>(const basic_string& sStr) const noexcept
2182 {
2183  return compare(sStr.data(), sStr.size()) > 0;
2184 }
2185 
2186 template<class char_t, class traits_t>
2187 template<range_of_t_c<char_t> string_t>
2188 inline bool basic_string<char_t, traits_t>::operator>(const string_t& sStr) const noexcept
2189 {
2190  return iter_strcmp(cbegin(), cend(), sStr.cbegin(), sStr.cend()) > 0;
2191 }
2192 
2193 template<class char_t, class traits_t>
2194 inline bool basic_string<char_t, traits_t>::operator>=(value_type chSymbol) const noexcept
2195 {
2196  return compare(&chSymbol, 1) >= 0;
2197 }
2198 
2199 template<class char_t, class traits_t>
2200 inline bool basic_string<char_t, traits_t>::operator>=(const_pointer pszSource) const noexcept
2201 {
2202  return compare(pszSource) >= 0;
2203 }
2204 
2205 template<class char_t, class traits_t>
2206 inline bool basic_string<char_t, traits_t>::operator>=(const basic_string& sStr) const noexcept
2207 {
2208  return compare(sStr.data(), sStr.size()) >= 0;
2209 }
2210 
2211 template<class char_t, class traits_t>
2212 template<range_of_t_c<char_t> string_t>
2213 inline bool basic_string<char_t, traits_t>::operator>=(const string_t& sStr) const noexcept
2214 {
2215  return iter_strcmp(cbegin(), cend(), sStr.cbegin(), sStr.cend()) >= 0;
2216 }
2217 
2218 template<class char_t, class traits_t>
2219 inline typename basic_string<char_t, traits_t>::reference basic_string<char_t, traits_t>::operator[](
2220  size_type nSymbol) noexcept
2221 {
2222  return data()[nSymbol];
2223 }
2224 
2225 template<class char_t, class traits_t>
2226 inline typename basic_string<char_t, traits_t>::const_reference basic_string<char_t, traits_t>::operator[](
2227  size_type nSymbol) const noexcept
2228 {
2229  return data()[nSymbol];
2230 }
2231 
2232 template<class char_t, class traits_t>
2233 inline basic_string<char_t, traits_t>::operator std::basic_string_view<
2234  typename basic_string<char_t, traits_t>::value_type>() const noexcept
2235 {
2236  return string_view(data(), size());
2237 }
2238 
2239 template<class char_t, class traits_t>
2240 inline basic_string<char_t, traits_t>::operator bool() const noexcept
2241 {
2242  return !empty();
2243 }
2244 
2245 template<class char_t, class traits_t>
2246 inline bool basic_string<char_t, traits_t>::_resize(size_type nSymbols, sbo_resize_type eType) noexcept
2247 {
2248  const bool bRet = m_Data.resize(
2249  (nSymbols > 0 ? nSymbols + 1 : 0) * sizeof(value_type), // + null terminator
2250  traits_t::align() * sizeof(value_type),
2251  eType,
2252  true);
2253 
2254  if (bRet && eType != sbo_resize_type::reserve)
2255  (*this)[nSymbols] = QX_CHAR_PREFIX(typename traits_t::value_type, '\0');
2256 
2257  return bRet;
2258 }
2259 
2260 template<class char_t, class traits_t>
2261 template<class searcher_t>
2262 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_trim_left(
2263  const searcher_t& searcher) noexcept
2264 {
2265  size_type nSymbols = 0;
2266 
2267  for (size_type i = 0; i < size(); ++i)
2268  {
2269  if (searcher(at(i)))
2270  ++nSymbols;
2271  else
2272  break;
2273  }
2274 
2275  erase(0, nSymbols);
2276  return nSymbols;
2277 }
2278 
2279 template<class char_t, class traits_t>
2280 template<class searcher_t>
2281 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_trim_right(
2282  const searcher_t& searcher) noexcept
2283 {
2284  size_type nSymbols = 0;
2285  size_type nSize = size();
2286 
2287  for (size_type i = nSize - 1; i != std::numeric_limits<size_type>::max(); --i)
2288  {
2289  if (searcher(at(i)))
2290  ++nSymbols;
2291  else
2292  break;
2293  }
2294 
2295  erase(nSize - nSymbols, nSymbols);
2296  return nSymbols;
2297 }
2298 
2299 template<class char_t, class traits_t>
2300 template<class searcher_t>
2301 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_trim(
2302  const searcher_t& searcher) noexcept
2303 {
2304  const size_type nSize = size();
2305  size_type nStartPos = 0;
2306  size_type nEndPos = nSize;
2307 
2308  while (nStartPos < nSize && searcher(at(nStartPos)))
2309  ++nStartPos;
2310 
2311  while (nEndPos > nStartPos && searcher(at(nEndPos - 1)))
2312  --nEndPos;
2313 
2314  size_type nNewSize = nEndPos - nStartPos;
2315 
2316  std::memmove(data(), data() + nStartPos, nNewSize * sizeof(value_type));
2317 
2318  _resize(nNewSize);
2319  return nSize - nNewSize;
2320 }
2321 
2322 template<class char_t, class traits_t>
2323 template<class comparator_t>
2324 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_find(
2325  size_type nBegin,
2326  size_type nEnd,
2327  const comparator_t& comparator) const noexcept
2328 {
2329  if (nEnd == npos)
2330  nEnd = size();
2331 
2332  const_pointer pData = data();
2333  const_pointer pCurrentChar = pData + nBegin;
2334  const_pointer pEnd = pData + nEnd;
2335 
2336  while (pCurrentChar < pEnd)
2337  {
2338  if (comparator(pCurrentChar))
2339  return static_cast<size_type>(pCurrentChar - pData);
2340  else
2341  ++pCurrentChar;
2342  }
2343 
2344  return npos;
2345 }
2346 
2347 template<class char_t, class traits_t>
2348 template<class comparator_t>
2349 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_rfind(
2350  size_type nBegin,
2351  size_type nEnd,
2352  const comparator_t& comparator) const noexcept
2353 {
2354  if (nBegin == npos)
2355  nBegin = size() - 1;
2356 
2357  const_pointer pData = data();
2358  const_pointer pCurrentChar = pData + nBegin;
2359  const_pointer pEnd = pData + nEnd;
2360 
2361  while (pCurrentChar >= pEnd)
2362  {
2363  if (comparator(pCurrentChar))
2364  return static_cast<size_type>(pCurrentChar - pData);
2365  else
2366  --pCurrentChar;
2367  }
2368 
2369  return npos;
2370 }
2371 
2372 template<class char_t, class traits_t>
2373 template<class incrementer_t, class fwd_it_t>
2374 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_find_first_of(
2375  fwd_it_t itBegin,
2376  fwd_it_t itEnd,
2377  size_type nBegin,
2378  const incrementer_t& incrementer) const noexcept
2379 {
2380  for (size_type i = nBegin; i < size(); ++i)
2381  for (fwd_it_t it = itBegin; it != itEnd; it = incrementer(it))
2382  if (*it == at(i))
2383  return i;
2384 
2385  return npos;
2386 }
2387 
2388 template<class char_t, class traits_t>
2389 template<class incrementer_t, class fwd_it_t>
2390 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_find_last_of(
2391  fwd_it_t itBegin,
2392  fwd_it_t itEnd,
2393  size_type nEnd,
2394  const incrementer_t& incrementer) const noexcept
2395 {
2396  for (size_type i = size() - 1; i != nEnd - 1; --i)
2397  for (fwd_it_t it = itBegin; it != itEnd; it = incrementer(it))
2398  if (*it == at(i))
2399  return i;
2400 
2401  return npos;
2402 }
2403 
2404 template<class char_t, class traits_t>
2405 template<class incrementer_t, class fwd_it_t>
2406 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_find_first_not_of(
2407  fwd_it_t itBegin,
2408  fwd_it_t itEnd,
2409  size_type nBegin,
2410  const incrementer_t& incrementer) const noexcept
2411 {
2412  for (size_type i = nBegin; i < size(); ++i)
2413  {
2414  bool bFoundOneOf = false;
2415  for (fwd_it_t it = itBegin; !bFoundOneOf && it != itEnd; it = incrementer(it))
2416  bFoundOneOf |= *it == at(i);
2417 
2418  if (!bFoundOneOf)
2419  return i;
2420  }
2421 
2422  return npos;
2423 }
2424 
2425 template<class char_t, class traits_t>
2426 template<class incrementer_t, class fwd_it_t>
2427 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_find_last_not_of(
2428  fwd_it_t itBegin,
2429  fwd_it_t itEnd,
2430  size_type nEnd,
2431  const incrementer_t& incrementer) const noexcept
2432 {
2433  for (size_type i = size() - 1; i != nEnd - 1; --i)
2434  {
2435  bool bFoundOneOf = false;
2436  for (fwd_it_t it = itBegin; !bFoundOneOf && it != itEnd; it = incrementer(it))
2437  bFoundOneOf |= *it == at(i);
2438 
2439  if (!bFoundOneOf)
2440  return i;
2441  }
2442 
2443  return npos;
2444 }
2445 
2446 template<class char_t, class traits_t>
2447 template<class string_view_like_t>
2448 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::_get_string_view_like_size(
2449  const string_view_like_t& sValue) noexcept
2450 {
2451  if constexpr (std::is_same_v<string_view_like_t, value_type>)
2452  {
2453  return 1;
2454  }
2455  else if constexpr (std::is_convertible_v<string_view_like_t, const_pointer>)
2456  {
2457  return traits_t::length(sValue);
2458  }
2459  else if constexpr (range_of_t_c<string_view_like_t, char_t>)
2460  {
2461  return sValue.size();
2462  }
2463  else
2464  {
2465  QX_STATIC_ASSERT_NO_INSTANTIATION("Unexpected type");
2466  return 0;
2467  }
2468 }
2469 
2470 template<class char_t, class traits_t>
2471 template<class string_view_like_t>
2472 inline typename basic_string<char_t, traits_t>::const_pointer basic_string<char_t, traits_t>::
2473  _get_string_view_like_data(const string_view_like_t& sValue) noexcept
2474 {
2475  if constexpr (std::is_same_v<string_view_like_t, value_type>)
2476  {
2477  return &sValue;
2478  }
2479  else if constexpr (std::is_convertible_v<string_view_like_t, const_pointer>)
2480  {
2481  return sValue;
2482  }
2483  else if constexpr (range_of_t_c<string_view_like_t, char_t>)
2484  {
2485  return sValue.data();
2486  }
2487  else
2488  {
2489  QX_STATIC_ASSERT_NO_INSTANTIATION("Unexpected type");
2490  return nullptr;
2491  }
2492 }
2493 
2494 template<class T, class char_t, class traits_t>
2496 {
2497  return basic_string<char_t, traits_t>::static_format(QX_STR_PREFIX(char_t, "{}"), value);
2498 }
2499 
2500 template<class char_t, class traits_t>
2501 basic_string<char_t, traits_t> operator+(
2502  const basic_string<char_t, traits_t>& lhs,
2503  const basic_string<char_t, traits_t>& rhs) noexcept
2504 {
2505  basic_string<char_t, traits_t> str(lhs);
2506  str += rhs;
2507  return str;
2508 }
2509 
2510 template<class char_t, class traits_t>
2511 basic_string<char_t, traits_t> operator+(
2512  basic_string<char_t, traits_t>&& lhs,
2513  const basic_string<char_t, traits_t>& rhs) noexcept
2514 {
2515  basic_string<char_t, traits_t> str(std::move(lhs));
2516  str += rhs;
2517  return str;
2518 }
2519 
2520 template<class char_t, class traits_t>
2521 basic_string<char_t, traits_t> operator+(
2522  const basic_string<char_t, traits_t>& lhs,
2523  typename traits_t::const_pointer rhs) noexcept
2524 {
2525  basic_string<char_t, traits_t> str(lhs);
2526  str += rhs;
2527  return str;
2528 }
2529 
2530 template<class char_t, class traits_t>
2531 basic_string<char_t, traits_t> operator+(
2532  basic_string<char_t, traits_t>&& lhs,
2533  typename traits_t::const_pointer rhs) noexcept
2534 {
2535  basic_string<char_t, traits_t> str(std::move(lhs));
2536  str += rhs;
2537  return str;
2538 }
2539 
2540 template<class char_t, class traits_t>
2541 basic_string<char_t, traits_t> operator+(
2542  typename traits_t::const_pointer lhs,
2543  const basic_string<char_t, traits_t>& rhs) noexcept
2544 {
2545  basic_string<char_t, traits_t> str(lhs);
2546  str += rhs;
2547  return str;
2548 }
2549 
2550 template<class char_t, class traits_t>
2551 basic_string<char_t, traits_t> operator+(
2552  const basic_string<char_t, traits_t>& lhs,
2553  typename traits_t::value_type rhs) noexcept
2554 {
2555  basic_string<char_t, traits_t> str(lhs);
2556  str += rhs;
2557  return str;
2558 }
2559 
2560 template<class char_t, class traits_t>
2561 basic_string<char_t, traits_t> operator+(
2562  basic_string<char_t, traits_t>&& lhs,
2563  typename traits_t::value_type rhs) noexcept
2564 {
2565  basic_string<char_t, traits_t> str(std::move(lhs));
2566  str += rhs;
2567  return str;
2568 }
2569 
2570 template<class char_t, class traits_t>
2571 basic_string<char_t, traits_t> operator+(
2572  typename traits_t::value_type lhs,
2573  const basic_string<char_t, traits_t>& rhs) noexcept
2574 {
2575  basic_string<char_t, traits_t> str(&lhs, 1);
2576  str += rhs;
2577  return str;
2578 }
2579 
2580 template<class char_t, class traits_t, range_of_t_c<char_t> string_t>
2581 basic_string<char_t, traits_t> operator+(const basic_string<char_t, traits_t>& lhs, const string_t& rhs) noexcept
2582 {
2583  basic_string<char_t, traits_t> str(lhs);
2584  str += rhs;
2585  return str;
2586 }
2587 
2588 template<class char_t, class traits_t, range_of_t_c<char_t> string_t>
2589 basic_string<char_t, traits_t> operator+(basic_string<char_t, traits_t>&& lhs, const string_t& rhs) noexcept
2590 {
2591  basic_string<char_t, traits_t> str(std::move(lhs));
2592  str += rhs;
2593  return str;
2594 }
2595 
2596 template<class char_t, class traits_t, range_of_t_c<char_t> string_t>
2597 basic_string<char_t, traits_t> operator+(const string_t& lhs, const basic_string<char_t, traits_t>& rhs) noexcept
2598 {
2599  basic_string<char_t, traits_t> str(lhs);
2600  str += rhs;
2601  return str;
2602 }
2603 
2604 /**
2605  @brief Get string size (excluding null terminator)
2606  @retval - string size (excluding null terminator)
2607 **/
2608 template<class char_t, class traits_t>
2609 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::size() const noexcept
2610 {
2611  const size_type nSize = m_Data.size() / sizeof(value_type);
2612  return nSize == 0 ? 0 : nSize - 1; // - null terminator
2613 }
2614 
2615 /**
2616  @brief Get c-string
2617  @retval - c-string
2618 **/
2619 template<class char_t, class traits_t>
2620 inline typename basic_string<char_t, traits_t>::pointer basic_string<char_t, traits_t>::data() noexcept
2621 {
2622  return reinterpret_cast<pointer>(m_Data.data());
2623 }
2624 
2625 /**
2626  @brief Get char at the ind position
2627  @param nIndex - char index
2628  @retval - char value
2629 **/
2630 template<class char_t, class traits_t>
2631 inline typename basic_string<char_t, traits_t>::reference basic_string<char_t, traits_t>::at(size_type nIndex)
2632 {
2633  // if (nIndex >= size())
2634  // throw std::out_of_range("invalid string position");
2635 
2636  return data()[nIndex];
2637 }
2638 
2639 /**
2640  @brief Clear string
2641 **/
2642 template<class char_t, class traits_t>
2643 inline void basic_string<char_t, traits_t>::clear() noexcept
2644 {
2645  assign(QX_STR_PREFIX(typename traits_t::value_type, ""));
2646 }
2647 
2648 } // namespace qx
2649 
2650 
2651 
2652 // -------------------------------------------------------- hash -------------------------------------------------------
2653 
2654 namespace std
2655 {
2656 
2657 template<class char_t, class traits_t>
2658 struct hash<qx::basic_string<char_t, traits_t>>
2659 {
2660  size_t operator()(const qx::basic_string<char_t, traits_t>& str) const noexcept
2661  {
2662  return traits_t::hash_function(str.data(), traits_t::hash_seed(), str.size());
2663  }
2664 };
2665 
2666 // -------------------------------------------------------- swap -------------------------------------------------------
2667 
2668 template<class char_t, class traits_t>
2670 {
2671  lhs.swap(rhs);
2672 }
2673 
2674 // ----------------------------------------------------- formatter -----------------------------------------------------
2675 
2676 template<class char_t, class traits_t>
2677 struct formatter<qx::basic_string<char_t, traits_t>, char_t> : qx::basic_formatter<char_t>
2678 {
2679  template<class format_context_type>
2680  constexpr auto format(const qx::basic_string<char_t, traits_t>& value, format_context_type& ctx) const
2681  {
2682  return format_to(ctx.out(), QX_STR_PREFIX(char_t, "{}"), value.c_str());
2683  }
2684 };
2685 
2686 } // namespace std
2687 
2688 
2689 // ------------------------------------------- istream / ostream overloading -------------------------------------------
2690 
2691 template<class char_t, class traits_t>
2692 qx::details::ostream<char_t>& operator<<(
2693  qx::details::ostream<char_t>& os,
2695 {
2696  os << str.data();
2697  return os;
2698 }
2699 
2700 template<class char_t, class traits_t>
2701 qx::details::istream<char_t>& operator>>(qx::details::istream<char_t>& is, qx::basic_string<char_t, traits_t>& str)
2702 {
2703  typename qx::details::istream<traits_t>::iostate ret_bit = qx::details::istream<traits_t>::goodbit;
2704 
2705  auto try_push_back = [&str, &is, &ret_bit](char_t ch)
2706  {
2707  typename traits_t::size_type nCurrentSize = str.size();
2708  if (str._resize(nCurrentSize + 1))
2709  {
2710  str[nCurrentSize] = ch;
2711  return true;
2712  }
2713  else
2714  {
2715  is.unget();
2716  ret_bit |= qx::details::istream<traits_t>::failbit;
2717  return false;
2718  }
2719  };
2720 
2721  str.clear();
2722  char_t ch;
2723 
2724  // skip all space symbols and add first symbol is any
2725  while (is.get(ch))
2726  {
2727  if (!traits_t::is_space(ch))
2728  {
2729  try_push_back(ch);
2730  break;
2731  }
2732  }
2733 
2734  // add other symbols until space symbol
2735  while (is.get(ch))
2736  {
2737  if (!traits_t::is_space(ch))
2738  {
2739  if (!try_push_back(ch))
2740  break;
2741  }
2742  else
2743  {
2744  is.unget();
2745  break;
2746  }
2747  }
2748 
2749  is.setstate(ret_bit);
2750  return is;
2751 }
@ append
append all
String class.
Definition: string.h:77
void push_back(value_type chSymbol) noexcept
Insert char in the end of the string.
Definition: string.inl:553
void erase(iterator itFirst, iterator itLast) noexcept
Erase substring.
Definition: string.inl:565
size_type find(value_type chSymbol, size_type nBegin=0, size_type nEnd=npos) const noexcept
Find substring.
Definition: string.inl:1271
bool remove_prefix(value_type chSymbol) noexcept
Remove string prefix if matches.
Definition: string.inl:996
size_type remove_all(value_type chSymbol, size_type nBegin=0, size_type nEnd=npos) noexcept
Remove all occurrences of a substring in a string.
Definition: string.inl:1073
std::optional< to_t > to(const_pointer pszFormat=nullptr) const noexcept
Convert string to specified type.
Definition: string.inl:264
int compare(value_type chSymbol) const noexcept
Performs a binary comparison of the characters.
Definition: string.inl:1233
size_type find_last_of(value_type chSymbol, size_type nEnd=0) const noexcept
Find last position of character.
Definition: string.inl:1522
void push_front(value_type chSymbol) noexcept
Insert char in the beginning of the string.
Definition: string.inl:559
size_type capacity() const noexcept
Get allocated memory size (including null terminator)
Definition: string.inl:250
value_type pop_back() noexcept
Erase last char and return it.
Definition: string.inl:603
size_type copy(pointer pDest, size_type nCount, size_type nPos=0) const noexcept
Copies a substring [nPos, nPos + nCount) to character string pointed to by pDest.
Definition: string.inl:327
views split(const value_type chSeparator) const noexcept
Split string by separator.
Definition: string.inl:1795
size_type rfind(value_type chSymbol, size_type nBegin=npos, size_type nEnd=0) const noexcept
Find substring (reverse direction)
Definition: string.inl:1353
size_type length() const noexcept
Get string length.
Definition: string.inl:238
void free() noexcept
Clear string and free allocated memory.
Definition: string.inl:198
void from(const from_t &data)
Construct string from custom type.
Definition: string.inl:345
size_type trim_right() noexcept
Trim the string to the right (whitespace characters)
Definition: string.inl:719
requires format_acceptable_args_c< char_t, args_t... > void vformat(string_view svFormat, args_t &&... args)
Clear the string and format it with the format string and the args.
Definition: string.inl:147
void assign(size_type nSymbols, value_type chSymbol) noexcept
Assign by filling.
Definition: string.inl:58
size_type replace_all(const find_string_t &sFind, const replace_string_t &sReplace, size_type nBegin=0, size_type nEnd=npos) noexcept
Replace all occurrences of sFind with sReplace.
Definition: string.inl:1213
bool ends_with(value_type chSymbol) const noexcept
Check if current string ends with char.
Definition: string.inl:1931
void swap(basic_string &sOther) noexcept
Swap this str and other.
Definition: string.inl:175
value_type pop_front() noexcept
Erase first char and return it.
Definition: string.inl:611
void append(value_type chSymbol) noexcept
Append char.
Definition: string.inl:384
bool contains(value_type chSymbol) const noexcept
Check if string contains char.
Definition: string.inl:1977
size_type trim() noexcept
Trim the string to the both sides (whitespace characters)
Definition: string.inl:819
void to_upper() noexcept
Convert string to uppercase.
Definition: string.inl:219
void shrink_to_fit() noexcept
Fit allocated size to string's actual size.
Definition: string.inl:191
static basic_string static_from(const from_t &data)
Construct string from custom type and get it.
size_type find_last_not_of(value_type chSymbol, size_type nEnd=0) const noexcept
Finds the last character not equal to chSymbol.
Definition: string.inl:1702
size_type trim_left() noexcept
Trim the string to the left (whitespace characters)
Definition: string.inl:619
size_type reserve(size_type nCapacity) noexcept
Reserve memory for the string.
Definition: string.inl:181
requires format_acceptable_args_c< char_t, args_t... > void append_vformat(string_view svFormat, args_t &&... args)
Append the formatted string to the current one.
Definition: string.inl:168
string_view substr(size_type nPos, size_type nSymbols=npos) const noexcept
Get substring.
Definition: string.inl:204
requires format_acceptable_args_c< char_t, args_t... > void append_format(const format_string_type< std::type_identity_t< args_t >... > sFormat, args_t &&... args)
Append the formatted string to the current one.
Definition: string.inl:137
void to_lower() noexcept
Convert string to lowercase.
Definition: string.inl:212
requires format_acceptable_args_c< char_t, args_t... > void format(const format_string_type< std::type_identity_t< args_t >... > sFormat, args_t &&... args)
Clear the string and format it with the format string and the args.
Definition: string.inl:117
size_type insert(size_type nPos, value_type chSymbol) noexcept
Insert substring.
Definition: string.inl:424
bool remove_suffix(value_type chSymbol) noexcept
Remove string suffix if matches.
Definition: string.inl:1029
const_pointer c_str() const noexcept
Get pointer to string zero terminated.
Definition: string.inl:244
requires static format_acceptable_args_c< char_t, args_t... > basic_string static_vformat(string_view svFormat, args_t &&... args)
Create a string by formatting it with the format string and the args.
size_type remove(value_type chSymbol, size_type nBegin=0, size_type nEnd=npos) noexcept
Remove the first occurrence of a substring in a string.
Definition: string.inl:919
static constexpr size_type max_size() noexcept
Get the theoretical maximum of string size.
Definition: string.inl:256
bool starts_with(value_type chSymbol) const noexcept
Check if current string starts with char.
Definition: string.inl:1883
value_type front() const noexcept
Get first char of the string.
Definition: string.inl:226
value_type back() const noexcept
Get last char of the string.
Definition: string.inl:232
requires static format_acceptable_args_c< char_t, args_t... > basic_string static_format(const format_string_type< std::type_identity_t< args_t >... > sFormat, args_t &&... args)
Create a string by formatting it with the format string and the args.
size_type replace(size_type nBegin, size_type nSize, const_pointer pszReplace, size_t nReplaceSize) noexcept
Replace a substring with a given string.
Definition: string.inl:1156
size_type find_first_of(value_type chSymbol, size_type nBegin=0) const noexcept
Find first position of character.
Definition: string.inl:1435
size_type insert(const_iterator itPos, const basic_string &sWhat) noexcept
Insert substring.
Definition: string.inl:526
size_type find_first_not_of(value_type chSymbol, size_type nBegin=0) const noexcept
Finds the first character not equal to chSymbol.
Definition: string.inl:1609
Const random access iterator type.
Definition: iterator.h:74
Non-const random access iterator type.
Definition: iterator.h:35
requires(same_variadic_args_v< args_t... >) const expr auto coalesce(args_t &&... args)
Coalesce function, C# a ?? b analogue.
Definition: coalesce.inl:57
#define QX_STATIC_ASSERT_NO_INSTANTIATION(Message)
This static assert will fail if block it placed in must not be instantiated.
basic_string< char_t, traits_t > convert_to_string(const T &value)
Converts any type that has a std::formatter overload to qx::basic_string.
Definition: string.inl:2495
#define QX_CHAR_PREFIX(value_t, ch)
Chose witch of prefixes add to char : L or none.
Definition: string_utils.h:261
constexpr int iter_strcmp(fwd_it_1_t itBegin1, fwd_it_1_t itEnd1, fwd_it_2_t itBegin2, fwd_it_2_t itEnd2) noexcept
Compares string 1 with string 2.
Definition: string_utils.h:150
#define QX_STR_PREFIX(value_t, str)
Chose witch of prefixes add to string : L or none.
Definition: string_utils.h:253