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