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