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