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 (c) 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>
209 inline bool basic_string<char_t, traits_t>::resize(size_type nSymbols) noexcept
210 {
211  // + 1: null terminator
212  const bool bRet = m_Data.resize((nSymbols > 0 ? nSymbols + 1 : 0) * sizeof(value_type));
213  if (bRet)
214  (*this)[nSymbols] = QX_CHAR_PREFIX(typename traits_t::value_type, '\0');
215 
216  return bRet;
217 }
218 
219 template<class char_t, class traits_t>
221 {
222  m_Data.shrink_to_fit();
223 }
224 
225 template<class char_t, class traits_t>
227 {
228  m_Data.free();
229  resize(0);
230 }
231 
232 template<class char_t, class traits_t>
233 inline typename basic_string<char_t, traits_t>::string_view basic_string<char_t, traits_t>::substr(
234  size_type nPos,
235  size_type nSymbols) const noexcept
236 {
237  return string_view(data() + nPos, nSymbols != npos ? nSymbols : size() - nPos);
238 }
239 
240 template<class char_t, class traits_t>
242 {
243  for (value_type& ch : *this)
244  ch = traits_t::to_lower(ch);
245 }
246 
247 template<class char_t, class traits_t>
249 {
250  for (value_type& ch : *this)
251  ch = traits_t::to_upper(ch);
252 }
253 
254 template<class char_t, class traits_t>
255 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::front() const noexcept
256 {
257  return at(0);
258 }
259 
260 template<class char_t, class traits_t>
261 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::back() const noexcept
262 {
263  return at(size() - 1);
264 }
265 
266 template<class char_t, class traits_t>
267 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::length() const noexcept
268 {
269  return size();
270 }
271 
272 template<class char_t, class traits_t>
273 inline typename basic_string<char_t, traits_t>::const_pointer basic_string<char_t, traits_t>::c_str() const noexcept
274 {
275  return data();
276 }
277 
278 template<class char_t, class traits_t>
279 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::capacity() const noexcept
280 {
281  return m_Data.capacity() / sizeof(value_type) - 1; // - null terminator
282 }
283 
284 template<class char_t, class traits_t>
285 constexpr typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::max_size() noexcept
286 {
287  return std::numeric_limits<size_type>::max() - 1 // npos reserved
288  - 1; // null terminator
289 }
290 
291 template<class char_t, class traits_t>
292 template<class to_t>
293 inline std::optional<to_t> basic_string<char_t, traits_t>::to(const_pointer pszFormat) const noexcept
294 {
295  std::optional<to_t> optResult = std::nullopt;
296 
297  if constexpr (
298  std::is_trivial_v<to_t> && std::is_standard_layout_v<to_t> || std::is_pointer_v<to_t>
299  || std::is_same_v<to_t, std::nullptr_t>)
300  {
301  if constexpr (std::is_same_v<to_t, std::nullptr_t>)
302  {
303  if (compare(QX_STR_PREFIX(typename traits_t::value_type, "nullptr")) == 0)
304  {
305  optResult = nullptr;
306  }
307  }
308  else if constexpr (std::is_same_v<to_t, bool>)
309  {
310  if (compare(QX_STR_PREFIX(typename traits_t::value_type, "true")) == 0)
311  {
312  optResult = true;
313  }
314  else if (compare(QX_STR_PREFIX(typename traits_t::value_type, "false")) == 0)
315  {
316  optResult = false;
317  }
318  }
319  else if (const auto pszSelectedFormat = pszFormat ? pszFormat : get_format_specifier<value_type, to_t>())
320  {
321  constexpr string_view svNSpecifier(QX_STR_PREFIX(value_type, "%n"));
322  constexpr size_t nBufferSize = 256;
323 
324  const size_t nFormatSpecifierLength = traits_t::length(pszSelectedFormat);
325  if (nFormatSpecifierLength <= nBufferSize - svNSpecifier.size() - 1)
326  {
327  value_type formatBuffer[nBufferSize];
328  std::memcpy(formatBuffer, pszSelectedFormat, nFormatSpecifierLength * sizeof(value_type));
329  std::memcpy(
330  formatBuffer + nFormatSpecifierLength,
331  svNSpecifier.data(),
332  svNSpecifier.size() * sizeof(value_type));
333  formatBuffer[nFormatSpecifierLength + svNSpecifier.size()] = QX_CHAR_PREFIX(value_type, '\0');
334 
335  to_t result;
336  int nSymbolsRead;
337  const int nConvertedArgs = traits_t::sscanf(data(), formatBuffer, &result, &nSymbolsRead);
338 
339  if (static_cast<size_type>(nSymbolsRead) == size() && nConvertedArgs == 1)
340  optResult = result;
341  }
342  }
343  }
344  else
345  {
346  to_t result;
347  sstream_type ss(data());
348  ss >> result;
349  optResult = result;
350  }
351 
352  return optResult;
353 }
354 
355 template<class char_t, class traits_t>
356 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::copy(
357  pointer pDest,
358  size_type nCount,
359  size_type nPos) const noexcept
360 {
361  size_type nCharsToCopy = 0;
362 
363  if (pDest && nCount > 0 && nPos < size())
364  {
365  nCharsToCopy = std::min(nPos + nCount, size()) - nPos;
366  std::memcpy(pDest, data() + nPos, nCharsToCopy * sizeof(value_type));
367  }
368 
369  return nCharsToCopy;
370 }
371 
372 template<class char_t, class traits_t>
373 template<class from_t>
374 inline void basic_string<char_t, traits_t>::from(const from_t& data)
375 {
376  if constexpr (
377  std::is_trivial_v<from_t> && std::is_standard_layout_v<from_t> || std::is_pointer_v<from_t>
378  || std::is_same_v<from_t, std::nullptr_t>)
379  {
380  if constexpr (std::is_same_v<from_t, std::nullptr_t>)
381  {
382  assign(QX_STR_PREFIX(typename traits_t::value_type, "nullptr"));
383  }
384  else if constexpr (std::is_same_v<from_t, bool>)
385  {
386  assign(
387  data ? QX_STR_PREFIX(typename traits_t::value_type, "true")
388  : QX_STR_PREFIX(typename traits_t::value_type, "false"));
389  }
390  else
391  {
392  format(QX_STR_PREFIX(typename traits_t::value_type, "{}"), data);
393  }
394  }
395  else
396  {
397  sstream_type ss;
398  ss << data;
399  assign(ss.str());
400  }
401 }
402 
403 template<class char_t, class traits_t>
404 template<class from_t>
405 inline basic_string<char_t, traits_t> basic_string<char_t, traits_t>::static_from(const from_t& data)
406 {
407  basic_string sTemp;
408  sTemp.from(data);
409  return std::move(sTemp);
410 }
411 
412 template<class char_t, class traits_t>
413 inline void basic_string<char_t, traits_t>::append(value_type chSymbol) noexcept
414 {
415  append(&chSymbol, 1);
416 }
417 
418 template<class char_t, class traits_t>
419 inline void basic_string<char_t, traits_t>::append(const_pointer pszStr, size_type nSymbols) noexcept
420 {
421  if (pszStr)
422  {
423  const size_type nSize = size();
424  const size_type nSizeSource = nSymbols == npos ? traits_t::length(pszStr) : nSymbols;
425 
426  if (resize(nSize + nSizeSource))
427  std::memcpy(data() + nSize, pszStr, nSizeSource * sizeof(value_type));
428  }
429 }
430 
431 template<class char_t, class traits_t>
432 inline void basic_string<char_t, traits_t>::append(const basic_string& sStr) noexcept
433 {
434  append(sStr.data(), sStr.size());
435 }
436 
437 template<class char_t, class traits_t>
438 template<class fwd_it_t>
439 inline void basic_string<char_t, traits_t>::append(fwd_it_t itBegin, fwd_it_t itEnd) noexcept
440 {
441  for (auto it = itBegin; it != itEnd; ++it)
442  push_back(*it);
443 }
444 
445 template<class char_t, class traits_t>
446 template<range_of_t_c<char_t> string_t>
447 inline void basic_string<char_t, traits_t>::append(const string_t& sStr) noexcept
448 {
449  if constexpr (std::ranges::contiguous_range<string_t> && std::ranges::sized_range<string_t>)
450  {
451  append(sStr.data(), sStr.size());
452  }
453  else
454  {
455  append(sStr.begin(), sStr.end());
456  }
457 }
458 
459 template<class char_t, class traits_t>
460 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
461  size_type nPos,
462  value_type chSymbol) noexcept
463 {
464  return insert(nPos, &chSymbol, 1);
465 }
466 
467 template<class char_t, class traits_t>
468 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
469  size_type nPos,
470  const_pointer pszWhat,
471  size_type nSymbols) noexcept
472 {
473  if (pszWhat)
474  {
475  const size_type nSize = size();
476  const size_type nSizeSource = nSymbols == npos ? traits_t::length(pszWhat) : nSymbols;
477 
478  if (nSizeSource > 0 && resize(nSize + nSizeSource))
479  {
480  std::memmove(data() + nPos + nSizeSource, data() + nPos, (nSize - nPos) * sizeof(value_type));
481  std::memcpy(data() + nPos, pszWhat, nSizeSource * sizeof(value_type));
482  return nPos + nSizeSource;
483  }
484  }
485 
486  return npos;
487 }
488 
489 template<class char_t, class traits_t>
490 template<class fwd_it_t>
491 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
492  size_type nPos,
493  fwd_it_t itWhatBegin,
494  fwd_it_t itWhatEnd) noexcept
495 {
496  if constexpr (is_random_access_iterator<fwd_it_t>)
497  {
498  return insert(nPos, itWhatBegin.operator->(), static_cast<size_type>(itWhatEnd - itWhatBegin));
499  }
500  else
501  {
502  size_type nWhatSize = 0;
503  for (auto it = itWhatBegin; it != itWhatEnd; ++it)
504  ++nWhatSize;
505 
506  size_type nStartSymbols = size();
507  if (nWhatSize > 0 && resize(nStartSymbols + nWhatSize))
508  {
509  std::memmove(data() + nPos + nWhatSize, data() + nPos, (nStartSymbols - nPos) * sizeof(value_type));
510 
511  size_type nWhatPos = 0;
512  for (auto it = itWhatBegin; it != itWhatEnd; ++it)
513  {
514  at(nPos + nWhatPos) = *it;
515  ++nWhatPos;
516  }
517 
518  return nPos + nWhatSize;
519  }
520  else
521  {
522  return npos;
523  }
524  }
525 }
526 
527 template<class char_t, class traits_t>
528 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
529  size_type nPos,
530  const basic_string& sWhat) noexcept
531 {
532  return insert(nPos, sWhat.data(), sWhat.size());
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  size_type nPos,
539  string_t sWhat) noexcept
540 {
541  return insert(static_cast<size_type>(nPos), sWhat.begin(), sWhat.end());
542 }
543 
544 template<class char_t, class traits_t>
545 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
546  const_iterator itPos,
547  value_type chSymbol) noexcept
548 {
549  return insert(static_cast<size_type>(itPos - cbegin()), chSymbol);
550 }
551 
552 template<class char_t, class traits_t>
553 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
554  const_iterator itPos,
555  const_pointer pszWhat,
556  size_type nSymbols) noexcept
557 {
558  return insert(static_cast<size_type>(itPos - cbegin()), pszWhat, nSymbols);
559 }
560 
561 template<class char_t, class traits_t>
562 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
563  const_iterator itPos,
564  const basic_string& sWhat) noexcept
565 {
566  return insert(static_cast<size_type>(itPos - cbegin()), sWhat.data(), sWhat.size());
567 }
568 
569 template<class char_t, class traits_t>
570 template<class fwd_it_t>
571 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
572  const_iterator itPos,
573  fwd_it_t itWhatBegin,
574  fwd_it_t itWhatEnd) noexcept
575 {
576  return insert(static_cast<size_type>(itPos - begin()), itWhatBegin, itWhatEnd);
577 }
578 
579 template<class char_t, class traits_t>
580 template<range_of_t_c<char_t> string_t>
581 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::insert(
582  const_iterator itPos,
583  string_t sWhat) noexcept
584 {
585  return insert(static_cast<size_type>(itPos - begin()), sWhat.begin(), sWhat.end());
586 }
587 
588 template<class char_t, class traits_t>
589 inline void basic_string<char_t, traits_t>::push_back(value_type chSymbol) noexcept
590 {
591  const size_t nStartSize = size();
592  resize(nStartSize + 1);
593  (*this)[nStartSize] = chSymbol;
594 }
595 
596 template<class char_t, class traits_t>
597 inline void basic_string<char_t, traits_t>::push_front(value_type chSymbol) noexcept
598 {
599  insert(0, &chSymbol, 1);
600 }
601 
602 template<class char_t, class traits_t>
603 inline void basic_string<char_t, traits_t>::erase(iterator itFirst, iterator itLast) noexcept
604 {
605  if (const typename iterator::difference_type nCharsToErase = itLast - itFirst; nCharsToErase > 0)
606  {
607  const size_type nStartSize = size();
608  const size_type nSymbolsToCopy = itLast != end() ? traits_t::length(itLast.operator->()) : 0;
609 
610  if (nSymbolsToCopy > 0)
611  {
612  std::memmove(itFirst.operator->(), itLast.operator->(), nSymbolsToCopy * sizeof(value_type));
613  }
614 
615  if (static_cast<typename iterator::difference_type>(nStartSize) >= nCharsToErase)
616  {
617  resize(nStartSize - nCharsToErase);
618  }
619  }
620 }
621 
622 template<class char_t, class traits_t>
624 {
625  erase(itPos, itPos + 1);
626 }
627 
628 template<class char_t, class traits_t>
629 inline void basic_string<char_t, traits_t>::erase(size_type nPos) noexcept
630 {
631  erase(iterator(this, nPos), iterator(this, nPos + 1));
632 }
633 
634 template<class char_t, class traits_t>
635 inline void basic_string<char_t, traits_t>::erase(size_type nPos, size_type nSymbols) noexcept
636 {
637  erase(iterator(this, nPos), iterator(this, nPos + nSymbols));
638 }
639 
640 template<class char_t, class traits_t>
641 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::pop_back() noexcept
642 {
643  value_type chRet = back();
644  erase(size() - 1);
645  return chRet;
646 }
647 
648 template<class char_t, class traits_t>
649 inline typename basic_string<char_t, traits_t>::value_type basic_string<char_t, traits_t>::pop_front() noexcept
650 {
651  value_type chRet = front();
652  erase(0);
653  return chRet;
654 }
655 
656 template<class char_t, class traits_t>
657 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left() noexcept
658 {
659  return _trim_left(
660  [](value_type ch)
661  {
662  return traits_t::is_space(ch);
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  value_type chSymbol) noexcept
669 {
670  return _trim_left(
671  [chSymbol](value_type ch)
672  {
673  return ch == chSymbol;
674  });
675 }
676 
677 template<class char_t, class traits_t>
678 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
679  const_pointer pszStr) noexcept
680 {
681  if (pszStr)
682  {
683  return _trim_left(
684  [pszStr](value_type ch)
685  {
686  for (size_type j = 0; pszStr[j] != QX_CHAR_PREFIX(value_type, '\0'); ++j)
687  {
688  if (pszStr[j] == ch)
689  return true;
690  }
691 
692  return false;
693  });
694  }
695  else
696  {
697  return 0;
698  }
699 }
700 
701 template<class char_t, class traits_t>
702 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
703  const_pointer pszStr,
704  size_type nStrSize) noexcept
705 {
706  if (pszStr)
707  {
708  return _trim_left(
709  [pszStr, nStrSize](value_type ch)
710  {
711  for (size_type j = 0; j < nStrSize; ++j)
712  if (pszStr[j] == ch)
713  return true;
714 
715  return false;
716  });
717  }
718  else
719  {
720  return 0;
721  }
722 }
723 
724 template<class char_t, class traits_t>
725 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
726  const basic_string& sStr) noexcept
727 {
728  return trim_left(sStr.data(), sStr.size());
729 }
730 
731 template<class char_t, class traits_t>
732 template<class fwd_it_t>
733 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
734  fwd_it_t itBegin,
735  fwd_it_t itEnd) noexcept
736 {
737  return _trim_left(
738  [itBegin, itEnd](auto ch)
739  {
740  for (auto it = itBegin; it != itEnd; ++it)
741  if (*it == ch)
742  return true;
743 
744  return false;
745  });
746 }
747 
748 template<class char_t, class traits_t>
749 template<range_of_t_c<char_t> string_t>
750 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_left(
751  const string_t& sStr) noexcept
752 {
753  return trim_left(sStr.begin(), sStr.end());
754 }
755 
756 template<class char_t, class traits_t>
757 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right() noexcept
758 {
759  return _trim_right(
760  [](value_type ch)
761  {
762  return traits_t::is_space(ch);
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  value_type chSymbol) noexcept
769 {
770  return _trim_right(
771  [chSymbol](value_type ch)
772  {
773  return ch == chSymbol;
774  });
775 }
776 
777 template<class char_t, class traits_t>
778 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
779  const_pointer pszStr) noexcept
780 {
781  if (pszStr)
782  {
783  return _trim_right(
784  [pszStr](value_type ch)
785  {
786  for (size_type j = 0; pszStr[j] != QX_CHAR_PREFIX(value_type, '\0'); ++j)
787  {
788  if (pszStr[j] == ch)
789  return true;
790  }
791 
792  return false;
793  });
794  }
795  else
796  {
797  return 0;
798  }
799 }
800 
801 template<class char_t, class traits_t>
802 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
803  const_pointer pszStr,
804  size_type nStrSize) noexcept
805 {
806  if (pszStr)
807  {
808  return _trim_right(
809  [pszStr, nStrSize](value_type ch)
810  {
811  for (size_type j = 0; j < nStrSize; ++j)
812  if (pszStr[j] == ch)
813  return true;
814 
815  return false;
816  });
817  }
818  else
819  {
820  return 0;
821  }
822 }
823 
824 template<class char_t, class traits_t>
825 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
826  const basic_string& sStr) noexcept
827 {
828  return trim_right(sStr.data(), sStr.size());
829 }
830 
831 template<class char_t, class traits_t>
832 template<class fwd_it_t>
833 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
834  fwd_it_t itBegin,
835  fwd_it_t itEnd) noexcept
836 {
837  return _trim_right(
838  [itBegin, itEnd](auto ch)
839  {
840  for (auto it = itBegin; it != itEnd; ++it)
841  if (*it == ch)
842  return true;
843 
844  return false;
845  });
846 }
847 
848 template<class char_t, class traits_t>
849 template<range_of_t_c<char_t> string_t>
850 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim_right(
851  const string_t& sStr) noexcept
852 {
853  return trim_right(sStr.begin(), sStr.end());
854 }
855 
856 template<class char_t, class traits_t>
857 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim() noexcept
858 {
859  return _trim(
860  [](value_type ch)
861  {
862  return traits_t::is_space(ch);
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  value_type chSymbol) noexcept
869 {
870  return _trim(
871  [chSymbol](value_type ch)
872  {
873  return ch == chSymbol;
874  });
875 }
876 
877 template<class char_t, class traits_t>
878 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
879  const_pointer pszStr) noexcept
880 {
881  if (pszStr)
882  {
883  return _trim(
884  [pszStr](value_type ch)
885  {
886  for (size_type j = 0; pszStr[j] != QX_CHAR_PREFIX(value_type, '\0'); ++j)
887  {
888  if (pszStr[j] == ch)
889  return true;
890  }
891 
892  return false;
893  });
894  }
895  else
896  {
897  return 0;
898  }
899 }
900 
901 template<class char_t, class traits_t>
902 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
903  const_pointer pszStr,
904  size_type nStrSize) noexcept
905 {
906  if (pszStr)
907  {
908  return _trim(
909  [pszStr, nStrSize](value_type ch)
910  {
911  for (size_type j = 0; j < nStrSize; ++j)
912  if (pszStr[j] == ch)
913  return true;
914 
915  return false;
916  });
917  }
918  else
919  {
920  return 0;
921  }
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>::trim(
926  const basic_string& sStr) noexcept
927 {
928  return trim(sStr.data(), sStr.size());
929 }
930 
931 template<class char_t, class traits_t>
932 template<class fwd_it_t>
933 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
934  fwd_it_t itBegin,
935  fwd_it_t itEnd) noexcept
936 {
937  return _trim(
938  [itBegin, itEnd](auto ch)
939  {
940  for (auto it = itBegin; it != itEnd; ++it)
941  if (*it == ch)
942  return true;
943 
944  return false;
945  });
946 }
947 
948 template<class char_t, class traits_t>
949 template<range_of_t_c<char_t> string_t>
950 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::trim(
951  const string_t& sStr) noexcept
952 {
953  return trim(sStr.begin(), sStr.end());
954 }
955 
956 template<class char_t, class traits_t>
957 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
958  value_type chSymbol,
959  size_type nBegin,
960  size_type nEnd) noexcept
961 {
962  size_type nPos = find(chSymbol, nBegin, nEnd);
963 
964  if (nPos != npos)
965  erase(nPos, 1);
966 
967  return nPos;
968 }
969 
970 template<class char_t, class traits_t>
971 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
972  const_pointer pszStr,
973  size_type nBegin,
974  size_type nEnd,
975  size_type nStrSize) noexcept
976 {
977  if (pszStr)
978  {
979  const size_type nLocalStrSize = nStrSize != npos ? nStrSize : traits_t::length(pszStr);
980  const size_type nPos = find(pszStr, nBegin, nLocalStrSize, nEnd);
981 
982  if (nPos != npos)
983  erase(nPos, nLocalStrSize);
984 
985  return nPos;
986  }
987  else
988  {
989  return npos;
990  }
991 }
992 
993 template<class char_t, class traits_t>
994 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
995  const basic_string& sStr,
996  size_type nBegin,
997  size_type nEnd) noexcept
998 {
999  const size_type nPos = find(sStr, nBegin, nEnd);
1000 
1001  if (nPos != npos)
1002  erase(nPos, sStr.size());
1004  return nPos;
1005 }
1006 
1007 template<class char_t, class traits_t>
1008 template<class fwd_it_t>
1009 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
1010  fwd_it_t itBegin,
1011  fwd_it_t itEnd,
1012  size_type nBegin,
1013  size_type nEnd) noexcept
1015  const size_type nPos = find(itBegin, itEnd, nBegin, nEnd);
1016 
1017  if (nPos != npos)
1018  erase(nPos, static_cast<size_type>(std::distance(itBegin, itEnd)));
1019 
1020  return nPos;
1021 }
1022 
1023 template<class char_t, class traits_t>
1024 template<range_of_t_c<char_t> string_t>
1025 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove(
1026  const string_t& sStr,
1027  size_type nBegin,
1028  size_type nEnd) noexcept
1029 {
1030  return remove(sStr.begin(), sStr.end(), nBegin, nEnd);
1031 }
1032 
1033 template<class char_t, class traits_t>
1034 inline bool basic_string<char_t, traits_t>::remove_prefix(value_type chSymbol) noexcept
1035 {
1036  return remove(chSymbol, static_cast<size_type>(0), static_cast<size_type>(1)) != npos;
1038 
1039 template<class char_t, class traits_t>
1040 inline bool basic_string<char_t, traits_t>::remove_prefix(const_pointer pszStr, size_type nStrSize) noexcept
1041 {
1042  return remove(pszStr, static_cast<size_type>(0), nStrSize, nStrSize) != npos;
1043 }
1044 
1045 template<class char_t, class traits_t>
1047 {
1048  return remove(sStr, static_cast<size_type>(0), sStr.size()) != npos;
1049 }
1050 
1051 template<class char_t, class traits_t>
1052 template<class fwd_it_t>
1053 inline bool basic_string<char_t, traits_t>::remove_prefix(fwd_it_t itBegin, fwd_it_t itEnd) noexcept
1054 {
1055  return remove(itBegin, itEnd, static_cast<size_type>(0), static_cast<size_type>(std::distance(itBegin, itEnd)))
1056  != npos;
1057 }
1058 
1059 template<class char_t, class traits_t>
1060 template<range_of_t_c<char_t> string_t>
1061 inline bool basic_string<char_t, traits_t>::remove_prefix(const string_t& sStr) noexcept
1062 {
1063  return remove_prefix(sStr.begin(), sStr.end());
1065 
1066 template<class char_t, class traits_t>
1067 inline bool basic_string<char_t, traits_t>::remove_suffix(value_type chSymbol) noexcept
1068 {
1069  const size_type nSize = size();
1070  return remove(chSymbol, nSize - 1, nSize) != npos;
1071 }
1072 
1073 template<class char_t, class traits_t>
1074 inline bool basic_string<char_t, traits_t>::remove_suffix(const_pointer pszStr, size_type nStrSize) noexcept
1075 {
1076  if (pszStr)
1077  {
1078  const size_type nSize = size();
1079  const size_type nLocalStrSize = nStrSize != npos ? nStrSize : traits_t::length(pszStr);
1080 
1081  return remove(pszStr, nSize - nLocalStrSize, nSize, nLocalStrSize) != npos;
1082  }
1083  else
1084  {
1085  return false;
1086  }
1087 }
1088 
1089 template<class char_t, class traits_t>
1091 {
1092  return remove_suffix(sStr.data(), sStr.size());
1094 
1095 template<class char_t, class traits_t>
1096 template<class fwd_it_t>
1097 inline bool basic_string<char_t, traits_t>::remove_suffix(fwd_it_t itBegin, fwd_it_t itEnd) noexcept
1098 {
1099  const size_type nSize = size();
1100  return remove(itBegin, itEnd, nSize - static_cast<size_type>(std::distance(itBegin, itEnd)), nSize) != npos;
1101 }
1102 
1103 template<class char_t, class traits_t>
1104 template<range_of_t_c<char_t> string_t>
1105 inline bool basic_string<char_t, traits_t>::remove_suffix(const string_t& sStr) noexcept
1106 {
1107  return remove_suffix(sStr.begin(), sStr.end());
1108 }
1109 
1110 template<class char_t, class traits_t>
1111 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1112  value_type chSymbol,
1113  size_type nBegin,
1114  size_type nEnd) noexcept
1115 {
1116  size_type nOccurrences = 0;
1117  size_type nLastOccurrencePos = nBegin;
1118 
1119  do
1120  {
1121  ++nOccurrences;
1122  nLastOccurrencePos = remove(chSymbol, nLastOccurrencePos, nEnd);
1123  } while (nLastOccurrencePos != npos);
1124 
1125  return nOccurrences - 1;
1126 }
1128 template<class char_t, class traits_t>
1129 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1130  const_pointer pszStr,
1131  size_type nBegin,
1132  size_type nEnd,
1133  size_type nStrSize) noexcept
1134 {
1135  if (pszStr)
1136  {
1137  size_type nOccurrences = 0;
1138  size_type nLastOccurrencePos = nBegin;
1139 
1140  do
1141  {
1142  ++nOccurrences;
1143  nLastOccurrencePos = remove(pszStr, nLastOccurrencePos, nEnd, nStrSize);
1144  } while (nLastOccurrencePos != npos);
1145 
1146  return nOccurrences - 1;
1147  }
1148  else
1149  {
1150  return 0;
1151  }
1152 }
1153 
1154 template<class char_t, class traits_t>
1155 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1156  const basic_string& sStr,
1157  size_type nBegin,
1158  size_type nEnd) noexcept
1159 {
1160  return remove_all(sStr.data(), nBegin, nEnd, sStr.size());
1161 }
1163 template<class char_t, class traits_t>
1164 template<class fwd_it_t>
1165 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1166  fwd_it_t itFirst,
1167  fwd_it_t itLast,
1168  size_type nBegin,
1169  size_type nEnd) noexcept
1170 {
1171  size_type nOccurrences = 0;
1172  size_type nLastOccurrencePos = nBegin;
1173 
1174  do
1175  {
1176  ++nOccurrences;
1177  nLastOccurrencePos = remove(itFirst, itLast, nLastOccurrencePos, nEnd);
1178  } while (nLastOccurrencePos != npos);
1179 
1180  return nOccurrences - 1;
1181 }
1182 
1183 template<class char_t, class traits_t>
1184 template<range_of_t_c<char_t> string_t>
1185 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::remove_all(
1186  const string_t& sStr,
1187  size_type nBegin,
1188  size_type nEnd) noexcept
1189 {
1190  return remove_all(sStr.begin(), sStr.end(), nBegin, nEnd);
1191 }
1193 template<class char_t, class traits_t>
1194 typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace(
1195  size_type nBegin,
1196  size_type nSize,
1197  const_pointer pszReplace,
1198  size_t nReplaceSize) noexcept
1199 {
1200  const size_type nStartSize = size();
1201  const size_type nNewSize = nStartSize - nSize + nReplaceSize;
1202 
1203  reserve(nNewSize);
1204 
1205  std::memmove(
1206  data() + nBegin + nReplaceSize,
1207  data() + nBegin + nSize,
1208  (nStartSize - nBegin - nSize) * sizeof(value_type));
1209 
1210  std::memcpy(data() + nBegin, pszReplace, nReplaceSize * sizeof(value_type));
1211 
1212  resize(nNewSize);
1213 
1214  return nBegin + nReplaceSize;
1215 }
1216 
1217 template<class char_t, class traits_t>
1218 template<class replace_string_t>
1219 typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace(
1220  size_type nBegin,
1221  size_type nSize,
1222  const replace_string_t& sReplace) noexcept
1223 {
1224  return replace(nBegin, nSize, _get_string_view_like_data(sReplace), _get_string_view_like_size(sReplace));
1225 }
1226 
1227 template<class char_t, class traits_t>
1228 template<class find_string_t, class replace_string_t>
1229 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace(
1230  const find_string_t& sFind,
1231  const replace_string_t& sReplace,
1232  size_type nBegin,
1233  size_type nEnd) noexcept
1234 {
1235  if (size_type nPos = find(sFind, nBegin, nEnd); nPos != npos)
1236  {
1237  return replace(
1238  nPos,
1239  _get_string_view_like_size(sFind),
1240  _get_string_view_like_data(sReplace),
1241  _get_string_view_like_size(sReplace));
1242  }
1243  else
1244  {
1245  return npos;
1246  }
1247 }
1248 
1249 template<class char_t, class traits_t>
1250 template<class find_string_t, class replace_string_t>
1251 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::replace_all(
1252  const find_string_t& sFind,
1253  const replace_string_t& sReplace,
1254  size_type nBegin,
1255  size_type nEnd) noexcept
1256 {
1257  size_type nOccurrences = 0;
1258  size_type nPos = nBegin;
1259 
1260  do
1261  {
1262  nPos = replace(sFind, sReplace, nPos, nEnd);
1263  if (nPos != npos)
1264  ++nOccurrences;
1265  } while (nPos != npos);
1266 
1267  return nOccurrences;
1268 }
1269 
1270 template<class char_t, class traits_t>
1271 inline int basic_string<char_t, traits_t>::compare(value_type chSymbol) const noexcept
1272 {
1273  return compare(&chSymbol, 1);
1274 }
1275 
1276 template<class char_t, class traits_t>
1277 inline int basic_string<char_t, traits_t>::compare(const_pointer pszStr) const noexcept
1278 {
1279  return traits_t::compare(data(), pszStr);
1280 }
1281 
1282 template<class char_t, class traits_t>
1283 inline int basic_string<char_t, traits_t>::compare(const_pointer pStr, size_type nSymbols) const noexcept
1284 {
1285  return traits_t::compare_n(data(), pStr, nSymbols);
1286 }
1287 
1288 template<class char_t, class traits_t>
1289 inline int basic_string<char_t, traits_t>::compare(const basic_string& sStr) const noexcept
1290 {
1291  return compare(sStr.data(), sStr.size());
1292 }
1293 
1294 template<class char_t, class traits_t>
1295 template<class fwd_it_t>
1296 inline int basic_string<char_t, traits_t>::compare(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1297 {
1298  return iter_strcmp(cbegin(), cend(), itBegin, itEnd);
1299 }
1301 template<class char_t, class traits_t>
1302 template<range_of_t_c<char_t> string_t>
1303 inline int basic_string<char_t, traits_t>::compare(const string_t& sStr) const noexcept
1304 {
1305  return compare(sStr.begin(), sStr.end());
1306 }
1307 
1308 template<class char_t, class traits_t>
1309 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1310  value_type chSymbol,
1311  size_type nBegin,
1312  size_type nEnd) const noexcept
1313 {
1314  return _find(
1315  nBegin,
1316  nEnd,
1317  [chSymbol](const_pointer pCurrentChar)
1318  {
1319  return *pCurrentChar == chSymbol;
1320  });
1321 }
1322 
1323 template<class char_t, class traits_t>
1324 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1325  const_pointer pszWhat,
1326  size_type nBegin,
1327  size_type nWhatSize,
1328  size_type nEnd) const noexcept
1329 {
1330  if (pszWhat)
1331  {
1332  const size_type nLocalWhatSize = nWhatSize != npos ? nWhatSize : traits_t::length(pszWhat);
1333 
1334  return _find(
1335  nBegin,
1336  nEnd,
1337  [pszWhat, nLocalWhatSize](const_pointer pCurrentChar)
1338  {
1339  return !traits_t::compare_n(pszWhat, pCurrentChar, nLocalWhatSize);
1340  });
1341  }
1342  else
1343  {
1344  return npos;
1345  }
1346 }
1347 
1348 template<class char_t, class traits_t>
1349 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1350  const basic_string& sWhat,
1351  size_type nBegin,
1352  size_type nEnd) const noexcept
1353 {
1354  return find(sWhat.data(), nBegin, sWhat.size(), nEnd);
1355 }
1356 
1357 template<class char_t, class traits_t>
1358 template<class fwd_it_t>
1359 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1360  fwd_it_t itWhatBegin,
1361  fwd_it_t itWhatEnd,
1362  size_type nBegin,
1363  size_type nEnd) const noexcept
1364 {
1365  const size_t nWhatSize = itWhatEnd - itWhatBegin;
1366  return _find(
1367  nBegin,
1368  nEnd,
1369  [this, itWhatBegin, itWhatEnd, nWhatSize](const_pointer pCurrentChar)
1370  {
1371  const size_t nStart = static_cast<size_type>(pCurrentChar - data());
1372  return !iter_strcmp(
1373  const_iterator(this, nStart),
1374  const_iterator(this, nStart + nWhatSize),
1375  itWhatBegin,
1376  itWhatEnd);
1377  });
1378 }
1379 
1380 template<class char_t, class traits_t>
1381 template<range_of_t_c<char_t> string_t>
1382 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find(
1383  string_t sWhat,
1384  size_type nBegin,
1385  size_type nEnd) const noexcept
1386 {
1387  return find(sWhat.begin(), sWhat.end(), nBegin, nEnd);
1388 }
1389 
1390 template<class char_t, class traits_t>
1391 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1392  value_type chSymbol,
1393  size_type nBegin,
1394  size_type nEnd) const noexcept
1395 {
1396  return _rfind(
1397  nBegin,
1398  nEnd,
1399  [chSymbol](const_pointer pCurrentChar)
1400  {
1401  return *pCurrentChar == chSymbol;
1402  });
1403 }
1404 
1405 template<class char_t, class traits_t>
1406 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1407  const_pointer pszWhat,
1408  size_type nBegin,
1409  size_type nWhatSize,
1410  size_type nEnd) const noexcept
1411 {
1412  if (pszWhat)
1413  {
1414  const size_type nLocalWhatSize = nWhatSize != npos ? nWhatSize : traits_t::length(pszWhat);
1415 
1416  return _rfind(
1417  nBegin,
1418  nEnd,
1419  [pszWhat, nLocalWhatSize](const_pointer pCurrentChar)
1420  {
1421  return !traits_t::compare_n(pszWhat, pCurrentChar, nLocalWhatSize);
1422  });
1423  }
1424  else
1425  {
1426  return npos;
1427  }
1428 }
1429 
1430 template<class char_t, class traits_t>
1431 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1432  const basic_string& sWhat,
1433  size_type nBegin,
1434  size_type nEnd) const noexcept
1435 {
1436  return rfind(sWhat.data(), nBegin, sWhat.size(), nEnd);
1437 }
1438 
1439 template<class char_t, class traits_t>
1440 template<class fwd_it_t>
1441 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1442  fwd_it_t itWhatBegin,
1443  fwd_it_t itWhatEnd,
1444  size_type nBegin,
1445  size_type nEnd) const noexcept
1446 {
1447  const size_t nWhatSize = itWhatEnd - itWhatBegin;
1448  return _rfind(
1449  nBegin,
1450  nEnd,
1451  [this, itWhatBegin, itWhatEnd, nWhatSize](const_pointer pCurrentChar)
1452  {
1453  const size_t nStart = static_cast<size_type>(pCurrentChar - data());
1454  return !iter_strcmp(
1455  const_iterator(this, nStart),
1456  const_iterator(this, nStart + nWhatSize),
1457  itWhatBegin,
1458  itWhatEnd);
1459  });
1460 }
1461 
1462 template<class char_t, class traits_t>
1463 template<range_of_t_c<char_t> string_t>
1464 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::rfind(
1465  string_t sWhat,
1466  size_type nBegin,
1467  size_type nEnd) const noexcept
1468 {
1469  return rfind(sWhat.begin(), sWhat.end(), nBegin, nEnd);
1470 }
1471 
1472 template<class char_t, class traits_t>
1473 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1474  value_type chSymbol,
1475  size_type nBegin) const noexcept
1476 {
1477  return find(chSymbol, nBegin);
1478 }
1479 
1480 template<class char_t, class traits_t>
1481 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1482  const_pointer pszWhat,
1483  size_type nBegin,
1484  size_type nWhatSize) const noexcept
1485 {
1486  if (pszWhat)
1487  {
1488  return _find_first_of(
1489  pszWhat,
1490  pszWhat + nWhatSize,
1491  nBegin,
1492  [](const_pointer pChar)
1493  {
1494  return pChar + 1;
1495  });
1496  }
1497  else
1498  {
1499  return npos;
1500  }
1501 }
1502 
1503 template<class char_t, class traits_t>
1504 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1505  const_pointer pszWhat,
1506  size_type nBegin) const noexcept
1507 {
1508  if (pszWhat)
1509  {
1510  return _find_first_of(
1511  pszWhat,
1512  static_cast<const_pointer>(nullptr),
1513  nBegin,
1514  [](const_pointer pChar)
1515  {
1516  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1517  });
1518  }
1519  else
1520  {
1521  return npos;
1522  }
1523 }
1524 
1525 template<class char_t, class traits_t>
1526 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1527  const basic_string& sWhat,
1528  size_type nBegin) const noexcept
1529 {
1530  return find_first_of(sWhat.data(), nBegin, sWhat.size());
1532 
1533 template<class char_t, class traits_t>
1534 template<class fwd_it_t>
1535 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1536  fwd_it_t itWhatBegin,
1537  fwd_it_t itWhatEnd,
1538  size_type nBegin) const noexcept
1540  return _find_first_of(
1541  itWhatBegin,
1542  itWhatEnd,
1543  nBegin,
1544  [](fwd_it_t itChar)
1545  {
1546  return ++itChar;
1547  });
1548 }
1549 
1550 template<class char_t, class traits_t>
1551 template<range_of_t_c<char_t> string_t>
1552 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_of(
1553  string_t sWhat,
1554  size_type nBegin) const noexcept
1555 {
1556  return find_first_of(sWhat.begin(), sWhat.end(), nBegin);
1557 }
1558 
1559 template<class char_t, class traits_t>
1560 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1561  value_type chSymbol,
1562  size_type nEnd) const noexcept
1563 {
1564  return rfind(chSymbol, npos, nEnd);
1565 }
1566 
1567 template<class char_t, class traits_t>
1568 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1569  const_pointer pszWhat,
1570  size_type nEnd,
1571  size_type nWhatSize) const noexcept
1572 {
1573  if (pszWhat)
1574  {
1575  return _find_last_of(
1576  pszWhat,
1577  pszWhat + nWhatSize,
1578  nEnd,
1579  [](const_pointer pChar)
1580  {
1581  return pChar + 1;
1582  });
1583  }
1584  else
1585  {
1586  return npos;
1587  }
1588 }
1589 
1590 template<class char_t, class traits_t>
1591 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1592  const_pointer pszWhat,
1593  size_type nEnd) const noexcept
1594 {
1595  if (pszWhat)
1596  {
1597  return _find_last_of(
1598  pszWhat,
1599  static_cast<const_pointer>(nullptr),
1600  nEnd,
1601  [](const_pointer pChar)
1602  {
1603  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1604  });
1605  }
1606  else
1607  {
1608  return npos;
1609  }
1610 }
1611 
1612 template<class char_t, class traits_t>
1613 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1614  const basic_string& sWhat,
1615  size_type nEnd) const noexcept
1616 {
1617  return find_last_of(sWhat.data(), nEnd, sWhat.size());
1618 }
1619 
1620 template<class char_t, class traits_t>
1621 template<class fwd_it_t>
1622 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1623  fwd_it_t itWhatBegin,
1624  fwd_it_t itWhatEnd,
1625  size_type nEnd) const noexcept
1626 {
1627  return _find_last_of(
1628  itWhatBegin,
1629  itWhatEnd,
1630  nEnd,
1631  [](fwd_it_t itChar)
1632  {
1633  return ++itChar;
1634  });
1635 }
1636 
1637 template<class char_t, class traits_t>
1638 template<range_of_t_c<char_t> string_t>
1639 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_of(
1640  string_t sWhat,
1641  size_type nEnd) const noexcept
1642 {
1643  return find_last_of(sWhat.begin(), sWhat.end(), nEnd);
1644 }
1645 
1646 template<class char_t, class traits_t>
1647 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1648  value_type chSymbol,
1649  size_type nBegin) const noexcept
1650 {
1651  return _find(
1652  nBegin,
1653  npos,
1654  [chSymbol](const_pointer pCurrentChar)
1655  {
1656  return *pCurrentChar != chSymbol;
1657  });
1658 }
1659 
1660 template<class char_t, class traits_t>
1661 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1662  const_pointer pszWhat,
1663  size_type nBegin,
1664  size_type nWhatSize) const noexcept
1665 {
1666  if (pszWhat)
1667  {
1668  return _find_first_not_of(
1669  pszWhat,
1670  pszWhat + nWhatSize,
1671  nBegin,
1672  [](const_pointer pChar)
1673  {
1674  return pChar + 1;
1675  });
1676  }
1677  else
1678  {
1679  return npos;
1680  }
1681 }
1682 
1683 template<class char_t, class traits_t>
1684 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1685  const_pointer pszWhat,
1686  size_type nBegin) const noexcept
1687 {
1688  if (pszWhat)
1689  {
1690  return _find_first_not_of(
1691  pszWhat,
1692  static_cast<const_pointer>(nullptr),
1693  nBegin,
1694  [](const_pointer pChar)
1695  {
1696  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1697  });
1698  }
1699  else
1700  {
1701  return npos;
1702  }
1703 }
1704 
1705 template<class char_t, class traits_t>
1706 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1707  const basic_string& sWhat,
1708  size_type nBegin) const noexcept
1709 {
1710  return find_first_not_of(sWhat.data(), nBegin, sWhat.size());
1711 }
1712 
1713 template<class char_t, class traits_t>
1714 template<class fwd_it_t>
1715 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1716  fwd_it_t itWhatBegin,
1717  fwd_it_t itWhatEnd,
1718  size_type nBegin) const noexcept
1719 {
1720  return _find_first_not_of(
1721  itWhatBegin,
1722  itWhatEnd,
1723  nBegin,
1724  [](fwd_it_t itChar)
1725  {
1726  return ++itChar;
1727  });
1728 }
1729 
1730 template<class char_t, class traits_t>
1731 template<range_of_t_c<char_t> string_t>
1732 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_first_not_of(
1733  string_t sWhat,
1734  size_type nBegin) const noexcept
1735 {
1736  return find_first_not_of(sWhat.begin(), sWhat.end(), nBegin);
1737 }
1738 
1739 template<class char_t, class traits_t>
1740 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1741  value_type chSymbol,
1742  size_type nEnd) const noexcept
1743 {
1744  return _rfind(
1745  npos,
1746  nEnd,
1747  [chSymbol](const_pointer pCurrentChar)
1748  {
1749  return *pCurrentChar != chSymbol;
1750  });
1751 }
1752 
1753 template<class char_t, class traits_t>
1754 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1755  const_pointer pszWhat,
1756  size_type nEnd,
1757  size_type nWhatSize) const noexcept
1758 {
1759  if (pszWhat)
1760  {
1761  return _find_last_not_of(
1762  pszWhat,
1763  pszWhat + nWhatSize,
1764  nEnd,
1765  [](const_pointer pChar)
1766  {
1767  return pChar + 1;
1768  });
1769  }
1770  else
1771  {
1772  return npos;
1773  }
1774 }
1775 
1776 template<class char_t, class traits_t>
1777 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1778  const_pointer pszWhat,
1779  size_type nEnd) const noexcept
1780 {
1781  if (pszWhat)
1782  {
1783  return _find_last_not_of(
1784  pszWhat,
1785  static_cast<const_pointer>(nullptr),
1786  nEnd,
1787  [](const_pointer pChar)
1788  {
1789  return *(pChar + 1) != QX_CHAR_PREFIX(value_type, '\0') ? pChar + 1 : nullptr;
1790  });
1791  }
1792  else
1793  {
1794  return npos;
1795  }
1796 }
1797 
1798 template<class char_t, class traits_t>
1799 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1800  const basic_string& sWhat,
1801  size_type nEnd) const noexcept
1802 {
1803  return find_last_not_of(sWhat.data(), nEnd, sWhat.size());
1804 }
1805 
1806 template<class char_t, class traits_t>
1807 template<class fwd_it_t>
1808 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1809  fwd_it_t itWhatBegin,
1810  fwd_it_t itWhatEnd,
1811  size_type nEnd) const noexcept
1812 {
1813  return _find_last_not_of(
1814  itWhatBegin,
1815  itWhatEnd,
1816  nEnd,
1817  [](fwd_it_t itChar)
1818  {
1819  return ++itChar;
1820  });
1821 }
1822 
1823 template<class char_t, class traits_t>
1824 template<range_of_t_c<char_t> string_t>
1825 inline typename basic_string<char_t, traits_t>::size_type basic_string<char_t, traits_t>::find_last_not_of(
1826  string_t sWhat,
1827  size_type nEnd) const noexcept
1828 {
1829  return find_last_not_of(sWhat.begin(), sWhat.end(), nEnd);
1830 }
1831 
1832 template<class char_t, class traits_t>
1833 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1834  const value_type chSeparator) const noexcept
1835 {
1836  views tokens;
1837 
1838  size_type nStart = 0;
1839  size_type nEnd = 0;
1840  while ((nEnd = find(chSeparator, nStart)) != npos)
1841  {
1842  tokens.emplace_back(substr(nStart, nEnd - nStart));
1843  nStart = nEnd;
1844  while (traits_t::compare_n(data() + nStart, &chSeparator, 1) == 0)
1845  ++nStart;
1846  }
1847 
1848  if (nStart != size())
1849  tokens.emplace_back(substr(nStart));
1850 
1851  return std::move(tokens);
1852 }
1853 
1854 template<class char_t, class traits_t>
1855 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1856  const_pointer pszSeparator,
1857  size_type nSepLen) const noexcept
1858 {
1859  views tokens;
1860 
1861  if (!pszSeparator)
1862  return tokens;
1863 
1864  if (nSepLen == npos)
1865  nSepLen = traits_t::length(pszSeparator);
1866 
1867  size_type nStart = 0;
1868  size_type nEnd = 0;
1869  while ((nEnd = find(pszSeparator, nStart, nSepLen, npos)) != npos)
1870  {
1871  tokens.emplace_back(substr(nStart, nEnd - nStart));
1872  nStart = nEnd;
1873  while (traits_t::compare_n(data() + nStart, pszSeparator, nSepLen) == 0)
1874  nStart += nSepLen;
1875  }
1876 
1877  if (nStart != size())
1878  tokens.emplace_back(substr(nStart));
1879 
1880  return tokens;
1881 }
1882 
1883 template<class char_t, class traits_t>
1884 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1885  const basic_string& sSeparator) const noexcept
1886 {
1887  return split(sSeparator.data(), sSeparator.size());
1888 }
1889 
1890 template<class char_t, class traits_t>
1891 template<class fwd_it_t>
1892 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1893  fwd_it_t itSepFirst,
1894  fwd_it_t itSepLast) const noexcept
1895 {
1896  views tokens;
1897 
1898  const size_type nSepLen = static_cast<size_type>(std::distance(itSepFirst, itSepLast));
1899 
1900  size_type nStart = 0;
1901  size_type nEnd = 0;
1902  while ((nEnd = find(itSepFirst, itSepLast, nStart)) != npos)
1903  {
1904  tokens.emplace_back(substr(nStart, nEnd - nStart));
1905  nStart = nEnd + nSepLen;
1906  }
1907  tokens.emplace_back(substr(nStart));
1908 
1909  return tokens;
1910 }
1911 
1912 template<class char_t, class traits_t>
1913 template<range_of_t_c<char_t> string_t>
1914 inline typename basic_string<char_t, traits_t>::views basic_string<char_t, traits_t>::split(
1915  const string_t& sSeparator) const noexcept
1916 {
1917  return split(sSeparator.begin(), sSeparator.end());
1918 }
1919 
1920 template<class char_t, class traits_t>
1921 inline bool basic_string<char_t, traits_t>::starts_with(value_type chSymbol) const noexcept
1922 {
1923  if (!empty())
1924  return at(0) == chSymbol;
1925  else
1926  return false;
1927 }
1928 
1929 template<class char_t, class traits_t>
1930 inline bool basic_string<char_t, traits_t>::starts_with(const_pointer pszStr, size_type nStrSize) const noexcept
1931 {
1932  if (pszStr)
1933  {
1934  if (size_type nThisSize = size(); nThisSize > 0)
1935  {
1936  if (nStrSize == npos)
1937  nStrSize = traits_t::length(pszStr);
1938 
1939  if (nStrSize <= nThisSize)
1940  return traits_t::compare_n(data(), pszStr, nStrSize) == 0;
1941  }
1942  }
1943 
1944  return false;
1945 }
1946 
1947 template<class char_t, class traits_t>
1948 inline bool basic_string<char_t, traits_t>::starts_with(const basic_string& sStr) const noexcept
1949 {
1950  return starts_with(sStr.data(), sStr.size());
1951 }
1952 
1953 template<class char_t, class traits_t>
1954 template<class fwd_it_t>
1955 inline bool basic_string<char_t, traits_t>::starts_with(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1956 {
1957  auto nStrSize = std::distance(itBegin, itEnd);
1958  return iter_strcmp(cbegin(), cbegin() + static_cast<size_type>(nStrSize), itBegin, itEnd) == 0;
1959 }
1960 
1961 template<class char_t, class traits_t>
1962 template<range_of_t_c<char_t> string_t>
1963 inline bool basic_string<char_t, traits_t>::starts_with(const string_t& sStr) const noexcept
1964 {
1965  return starts_with(sStr.begin(), sStr.end());
1966 }
1967 
1968 template<class char_t, class traits_t>
1969 inline bool basic_string<char_t, traits_t>::ends_with(value_type chSymbol) const noexcept
1970 {
1971  const size_type nSize = size();
1972  if (nSize > 0)
1973  return at(nSize - 1) == chSymbol;
1974  else
1975  return false;
1976 }
1977 
1978 template<class char_t, class traits_t>
1979 inline bool basic_string<char_t, traits_t>::ends_with(const_pointer pszStr, size_type nStrSize) const noexcept
1980 {
1981  if (!pszStr)
1982  return false;
1983 
1984  if (nStrSize == npos)
1985  nStrSize = traits_t::length(pszStr);
1986 
1987  return ends_with(pszStr, pszStr + nStrSize);
1988 }
1989 
1990 template<class char_t, class traits_t>
1991 inline bool basic_string<char_t, traits_t>::ends_with(const basic_string& sStr) const noexcept
1992 {
1993  return ends_with(sStr.data(), sStr.size());
1994 }
1995 
1996 template<class char_t, class traits_t>
1997 template<class fwd_it_t>
1998 inline bool basic_string<char_t, traits_t>::ends_with(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
1999 {
2000  const size_t nOtherSize = static_cast<size_type>(std::distance(itBegin, itEnd));
2001  if (nOtherSize > size())
2002  return false;
2003 
2004  return iter_strcmp(cend() - nOtherSize, cend(), itBegin, itEnd) == 0;
2005 }
2006 
2007 template<class char_t, class traits_t>
2008 template<range_of_t_c<char_t> string_t>
2009 inline bool basic_string<char_t, traits_t>::ends_with(const string_t& sStr) const noexcept
2010 {
2011  return ends_with(sStr.begin(), sStr.end());
2012 }
2013 
2014 template<class char_t, class traits_t>
2015 inline bool basic_string<char_t, traits_t>::contains(value_type chSymbol) const noexcept
2016 {
2017  return find(chSymbol) != npos;
2018 }
2019 
2020 template<class char_t, class traits_t>
2021 inline bool basic_string<char_t, traits_t>::contains(const_pointer pszStr, size_type nStrSize) const noexcept
2022 {
2023  return find(pszStr, 0, nStrSize) != npos;
2024 }
2025 
2026 template<class char_t, class traits_t>
2027 inline bool basic_string<char_t, traits_t>::contains(const basic_string& sStr) const noexcept
2028 {
2029  return find(sStr) != npos;
2030 }
2031 
2032 template<class char_t, class traits_t>
2033 template<class fwd_it_t>
2034 inline bool basic_string<char_t, traits_t>::contains(fwd_it_t itBegin, fwd_it_t itEnd) const noexcept
2035 {
2036  return find(itBegin, itEnd) != npos;
2037 }
2038 
2039 template<class char_t, class traits_t>
2040 template<range_of_t_c<char_t> string_t>
2041 inline bool basic_string<char_t, traits_t>::contains(const string_t& sStr) const noexcept
2042 {
2043  return find(sStr) != npos;
2044 }
2045 
2046 template<class char_t, class traits_t>
2047 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(const_pointer pszSource) noexcept
2048 {
2049  assign(pszSource);
2050  return *this;
2051 }
2052 
2053 template<class char_t, class traits_t>
2054 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(basic_string&& sStr) noexcept
2055 {
2056  assign(std::move(sStr));
2057  return *this;
2058 }
2059 
2060 template<class char_t, class traits_t>
2061 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(const basic_string& sStr) noexcept
2062 {
2063  assign(sStr);
2064  return *this;
2065 }
2066 
2067 template<class char_t, class traits_t>
2068 template<range_of_t_c<char_t> string_t>
2069 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator=(const string_t& sStr) noexcept
2070 {
2071  assign(sStr);
2072  return *this;
2073 }
2074 
2075 template<class char_t, class traits_t>
2076 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(value_type chSymbol) noexcept
2077 {
2078  append(&chSymbol, 1);
2079  return *this;
2080 }
2081 
2082 template<class char_t, class traits_t>
2083 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(const_pointer pszSource) noexcept
2084 {
2085  if (pszSource)
2086  append(pszSource, traits_t::length(pszSource));
2087 
2088  return *this;
2089 }
2090 
2091 template<class char_t, class traits_t>
2092 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(const basic_string& sStr) noexcept
2093 {
2094  append(sStr.data(), sStr.size());
2095  return *this;
2096 }
2097 
2098 template<class char_t, class traits_t>
2099 template<range_of_t_c<char_t> string_t>
2100 inline basic_string<char_t, traits_t>& basic_string<char_t, traits_t>::operator+=(const string_t& sStr) noexcept
2101 {
2102  append(sStr.begin(), sStr.end());
2103  return *this;
2104 }
2105 
2106 template<class char_t, class traits_t>
2107 inline bool basic_string<char_t, traits_t>::operator==(value_type chSymbol) const noexcept
2108 {
2109  return size() == 1 && at(0) == chSymbol;
2110 }
2111 
2112 template<class char_t, class traits_t>
2113 inline bool basic_string<char_t, traits_t>::operator==(const_pointer pszSource) const noexcept
2114 {
2115  return compare(pszSource) == 0;
2116 }
2117 
2118 template<class char_t, class traits_t>
2119 inline bool basic_string<char_t, traits_t>::operator==(const basic_string& sStr) const noexcept
2120 {
2121  return size() == sStr.size() && compare(sStr.data(), sStr.size()) == 0;
2122 }
2123 
2124 template<class char_t, class traits_t>
2125 template<range_of_t_c<char_t> string_t>
2126 inline bool basic_string<char_t, traits_t>::operator==(const string_t& sStr) const noexcept
2127 {
2128  return iter_strcmp(cbegin(), cend(), sStr.begin(), sStr.end()) == 0;
2129 }
2130 
2131 template<class char_t, class traits_t>
2132 inline bool basic_string<char_t, traits_t>::operator!=(value_type chSymbol) const noexcept
2133 {
2134  return !operator==(chSymbol);
2135 }
2136 
2137 template<class char_t, class traits_t>
2138 inline bool basic_string<char_t, traits_t>::operator!=(const_pointer pszSource) const noexcept
2139 {
2140  return !operator==(pszSource);
2141 }
2142 
2143 template<class char_t, class traits_t>
2144 inline bool basic_string<char_t, traits_t>::operator!=(const basic_string& sStr) const noexcept
2145 {
2146  return !operator==(sStr);
2147 }
2148 
2149 template<class char_t, class traits_t>
2150 template<range_of_t_c<char_t> string_t>
2151 inline bool basic_string<char_t, traits_t>::operator!=(const string_t& sStr) const noexcept
2152 {
2153  return !operator==(sStr);
2154 }
2155 
2156 template<class char_t, class traits_t>
2157 inline bool basic_string<char_t, traits_t>::operator<(value_type chSymbol) const noexcept
2158 {
2159  return compare(&chSymbol, 1) < 0;
2160 }
2161 
2162 template<class char_t, class traits_t>
2163 inline bool basic_string<char_t, traits_t>::operator<(const_pointer pszSource) const noexcept
2164 {
2165  return compare(pszSource) < 0;
2166 }
2167 
2168 template<class char_t, class traits_t>
2169 inline bool basic_string<char_t, traits_t>::operator<(const basic_string& sStr) const noexcept
2170 {
2171  return compare(sStr.data(), sStr.size()) < 0;
2172 }
2173 
2174 template<class char_t, class traits_t>
2175 template<range_of_t_c<char_t> string_t>
2176 inline bool basic_string<char_t, traits_t>::operator<(const string_t& sStr) const noexcept
2177 {
2178  return iter_strcmp(cbegin(), cend(), sStr.begin(), sStr.end()) < 0;
2179 }
2180 
2181 template<class char_t, class traits_t>
2182 inline bool basic_string<char_t, traits_t>::operator<=(value_type chSymbol) const noexcept
2183 {
2184  return compare(&chSymbol, 1) <= 0;
2185 }
2186 
2187 template<class char_t, class traits_t>
2188 inline bool basic_string<char_t, traits_t>::operator<=(const_pointer pszSource) const noexcept
2189 {
2190  return compare(pszSource) <= 0;
2191 }
2192 
2193 template<class char_t, class traits_t>
2194 inline bool basic_string<char_t, traits_t>::operator<=(const basic_string& sStr) const noexcept
2195 {
2196  return compare(sStr.data(), sStr.size()) <= 0;
2197 }
2198 
2199 template<class char_t, class traits_t>
2200 template<range_of_t_c<char_t> string_t>
2201 inline bool basic_string<char_t, traits_t>::operator<=(const string_t& sStr) const noexcept
2202 {
2203  return iter_strcmp(cbegin(), cend(), sStr.begin(), sStr.end()) <= 0;
2204 }
2205 
2206 template<class char_t, class traits_t>
2207 inline bool basic_string<char_t, traits_t>::operator>(value_type chSymbol) const noexcept
2208 {
2209  return compare(&chSymbol, 1) > 0;
2210 }
2211 
2212 template<class char_t, class traits_t>
2213 inline bool basic_string<char_t, traits_t>::operator>(const_pointer pszSource) const noexcept
2214 {
2215  return compare(pszSource) > 0;
2216 }
2217 
2218 template<class char_t, class traits_t>
2219 inline bool basic_string<char_t, traits_t>::operator>(const basic_string& sStr) const noexcept
2220 {
2221  return compare(sStr.data(), sStr.size()) > 0;
2222 }
2223 
2224 template<class char_t, class traits_t>
2225 template<range_of_t_c<char_t> string_t>
2226 inline bool basic_string<char_t, traits_t>::operator>(const string_t& sStr) const noexcept
2227 {
2228  return iter_strcmp(cbegin(), cend(), sStr.begin(), sStr.end()) > 0;
2229 }
2230 
2231 template<class char_t, class traits_t>
2232 inline bool basic_string<char_t, traits_t>::operator>=(value_type chSymbol) const noexcept
2233 {
2234  return compare(&chSymbol, 1) >= 0;
2235 }
2236 
2237 template<class char_t, class traits_t>
2238 inline bool basic_string<char_t, traits_t>::operator>=(const_pointer pszSource) const noexcept
2239 {
2240  return compare(pszSource) >= 0;
2241 }
2242 
2243 template<class char_t, class traits_t>
2244 inline bool basic_string<char_t, traits_t>::operator>=(const basic_string& sStr) const noexcept
2245 {
2246  return compare(sStr.data(), sStr.size()) >= 0;
2247 }
2248 
2249 template<class char_t, class traits_t>
2250 template<range_of_t_c<char_t> string_t>
2251 inline bool basic_string<char_t, traits_t>::operator>=(const string_t& sStr) const noexcept
2252 {
2253  return iter_strcmp(cbegin(), cend(), sStr.begin(), sStr.end()) >= 0;
2254 }
2255 
2256 template<class char_t, class traits_t>
2257 inline typename basic_string<char_t, traits_t>::reference basic_string<char_t, traits_t>::operator[](
2258  size_type nSymbol) noexcept
2259 {
2260  return data()[nSymbol];
2261 }
2262 
2263 template<class char_t, class traits_t>
2264 inline typename basic_string<char_t, traits_t>::const_reference basic_string<char_t, traits_t>::operator[](
2265  size_type nSymbol) const noexcept
2266 {
2267  return data()[nSymbol];
2268 }
2269 
2270 template<class char_t, class traits_t>
2271 inline basic_string<char_t, traits_t>::operator std::basic_string_view<
2272  typename basic_string<char_t, traits_t>::value_type>() const noexcept
2273 {
2274  return string_view(data(), size());
2275 }
2276 
2277 template<class char_t, class traits_t>
2278 inline basic_string<char_t, traits_t>::operator bool() const noexcept
2279 {
2280  return !empty();
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:589
void erase(iterator itFirst, iterator itLast) noexcept
Erase substring.
Definition: string.inl:603
size_type find(value_type chSymbol, size_type nBegin=0, size_type nEnd=npos) const noexcept
Find substring.
Definition: string.inl:1309
bool remove_prefix(value_type chSymbol) noexcept
Remove string prefix if matches.
Definition: string.inl:1034
size_type insert(size_type nPos, const basic_string &sWhat) noexcept
Insert substring.
Definition: string.inl:528
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:1111
std::optional< to_t > to(const_pointer pszFormat=nullptr) const noexcept
Convert string to specified type.
Definition: string.inl:293
int compare(value_type chSymbol) const noexcept
Performs a binary comparison of the characters.
Definition: string.inl:1271
size_type find_last_of(value_type chSymbol, size_type nEnd=0) const noexcept
Find last position of character.
Definition: string.inl:1560
void push_front(value_type chSymbol) noexcept
Insert char in the beginning of the string.
Definition: string.inl:597
size_type capacity() const noexcept
Get allocated memory size (including null terminator)
Definition: string.inl:279
value_type pop_back() noexcept
Erase last char and return it.
Definition: string.inl:641
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:356
views split(const value_type chSeparator) const noexcept
Split string by separator.
Definition: string.inl:1833
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:1391
size_type length() const noexcept
Get string length.
Definition: string.inl:267
void free() noexcept
Clear string and free allocated memory.
Definition: string.inl:226
void from(const from_t &data)
Construct string from custom type.
Definition: string.inl:374
size_type trim_right() noexcept
Trim the string to the right (whitespace characters)
Definition: string.inl:757
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:1251
bool ends_with(value_type chSymbol) const noexcept
Check if current string ends with char.
Definition: string.inl:1969
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:649
void append(value_type chSymbol) noexcept
Append char.
Definition: string.inl:413
bool contains(value_type chSymbol) const noexcept
Check if string contains char.
Definition: string.inl:2015
size_type trim() noexcept
Trim the string to the both sides (whitespace characters)
Definition: string.inl:857
void to_upper() noexcept
Convert string to uppercase.
Definition: string.inl:248
void shrink_to_fit() noexcept
Fit allocated size to string's actual size.
Definition: string.inl:220
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:1740
size_type trim_left() noexcept
Trim the string to the left (whitespace characters)
Definition: string.inl:657
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:233
void to_lower() noexcept
Convert string to lowercase.
Definition: string.inl:241
size_type insert(size_type nPos, value_type chSymbol) noexcept
Insert substring.
Definition: string.inl:460
bool remove_suffix(value_type chSymbol) noexcept
Remove string suffix if matches.
Definition: string.inl:1067
const_pointer c_str() const noexcept
Get pointer to string zero terminated.
Definition: string.inl:273
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:957
static constexpr size_type max_size() noexcept
Get the theoretical maximum of string size.
Definition: string.inl:285
bool starts_with(value_type chSymbol) const noexcept
Check if current string starts with char.
Definition: string.inl:1921
value_type front() const noexcept
Get first char of the string.
Definition: string.inl:255
value_type back() const noexcept
Get last char of the string.
Definition: string.inl:261
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:1194
size_type find_first_of(value_type chSymbol, size_type nBegin=0) const noexcept
Find first position of character.
Definition: string.inl:1473
bool resize(size_type nSymbols) noexcept
Resize string.
Definition: string.inl:209
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:1647
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