NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
basic_string.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_STRING_BASIC_STRING_HPP__
2#define NEFORCE_CORE_STRING_BASIC_STRING_HPP__
3
10
17NEFORCE_BEGIN_NAMESPACE__
18
24
33template <bool IsConst, typename String>
34struct basic_string_iterator : iiterator<basic_string_iterator<IsConst, String>> {
35public:
36 using container_type = String;
37 using value_type = typename container_type::value_type;
38 using size_type = typename container_type::size_type;
39 using difference_type = typename container_type::difference_type;
41 using reference = conditional_t<IsConst, typename container_type::const_reference,
42 typename container_type::reference>;
43 using pointer = conditional_t<IsConst, typename container_type::const_pointer,
44 typename container_type::pointer>;
45
46private:
47 pointer current_ = nullptr;
48 const container_type* str_ = nullptr;
49
50public:
51 NEFORCE_CONSTEXPR20 basic_string_iterator() noexcept = default;
52 NEFORCE_CONSTEXPR20 ~basic_string_iterator() = default;
53
54 NEFORCE_CONSTEXPR20 basic_string_iterator(const basic_string_iterator&) noexcept = default;
55 NEFORCE_CONSTEXPR20 basic_string_iterator& operator=(const basic_string_iterator&) noexcept = default;
56 NEFORCE_CONSTEXPR20 basic_string_iterator(basic_string_iterator&&) noexcept = default;
57 NEFORCE_CONSTEXPR20 basic_string_iterator& operator=(basic_string_iterator&&) noexcept = default;
58
64 NEFORCE_CONSTEXPR20 basic_string_iterator(pointer ptr, const container_type* str) noexcept :
65 current_(ptr),
66 str_(str) {}
67
72 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference dereference() const noexcept {
73 NEFORCE_DEBUG_VERIFY(current_ && str_, "Attempting to dereference on a null pointer");
74 NEFORCE_DEBUG_VERIFY(str_->data() <= current_ && current_ <= str_->data() + str_->size(),
75 "Attempting to dereference out of boundary");
76 return *current_;
77 }
78
82 NEFORCE_CONSTEXPR20 void increment() noexcept {
83 NEFORCE_DEBUG_VERIFY(current_ && str_, "Attempting to increment a null pointer");
84 NEFORCE_DEBUG_VERIFY(current_ < str_->data() + str_->size(), "Attempting to increment out of boundary");
85 ++current_;
86 }
87
91 NEFORCE_CONSTEXPR20 void decrement() noexcept {
92 NEFORCE_DEBUG_VERIFY(current_ && str_, "Attempting to decrement a null pointer");
93 NEFORCE_DEBUG_VERIFY(str_->data() < current_, "Attempting to decrement out of boundary");
94 --current_;
95 }
96
101 NEFORCE_CONSTEXPR20 void advance(difference_type off) noexcept {
102 NEFORCE_DEBUG_VERIFY((current_ && str_) || off == 0, "Attempting to advance a null pointer");
103 NEFORCE_DEBUG_VERIFY((off < 0 ? off >= str_->data() - current_ : off <= str_->data() + str_->size() - current_),
104 "Attempting to advance out of boundary");
105 current_ += off;
106 }
107
113 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 difference_type
114 distance_to(const basic_string_iterator& other) const noexcept {
115 NEFORCE_DEBUG_VERIFY(str_ == other.str_, "Attempting to distance to a different container");
116 return static_cast<difference_type>(current_ - other.current_);
117 }
118
124 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference operator[](difference_type n) const noexcept {
125 return *(*this + n);
126 }
127
133 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const basic_string_iterator& rhs) const noexcept {
134 NEFORCE_DEBUG_VERIFY(str_ == rhs.str_, "Attempting to equal to a different container");
135 return current_ == rhs.current_;
136 }
137
143 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool less_than(const basic_string_iterator& rhs) const noexcept {
144 NEFORCE_DEBUG_VERIFY(str_ == rhs.str_, "Attempting to less than a different container");
145 return current_ < rhs.current_;
146 }
147
152 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 pointer base() const noexcept { return current_; }
153
158 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const container_type* container() const noexcept { return str_; }
159};
160
161
172template <typename CharT, typename Traits = char_traits<CharT>, typename Alloc = allocator<CharT>>
173class basic_string : public icommon<basic_string<CharT, Traits, Alloc>> {
174 static_assert(is_allocator_v<Alloc>, "Alloc type is not a standard allocator type.");
175 static_assert(is_same_v<CharT, typename Alloc::value_type>, "allocator type mismatch.");
176 static_assert(is_same_v<CharT, typename Traits::char_type>, "trait type mismatch.");
178 "basic string only contains non-array trivial standard-layout types.");
179
180public:
181 using value_type = CharT;
182 using pointer = CharT*;
183 using reference = CharT&;
184 using const_pointer = const CharT*;
185 using const_reference = const CharT&;
192
193 using traits_type = Traits;
195 using allocator_type = Alloc;
196
198 static constexpr size_type npos = string_view::npos;
199
200private:
201#ifdef NEFORCE_USING_SSO
203 static constexpr size_type sso_buffer_bytes = MEMORY_ALIGN_THRESHHOLD;
205 static constexpr size_type sso_buffer_size = (sso_buffer_bytes + sizeof(CharT) - 1) / sizeof(CharT);
207 static constexpr size_type sso_capacity = sso_buffer_size - 1;
209 static constexpr size_type long_flag = static_cast<size_type>(1) << (sizeof(size_type) * 8 - 1);
210
214 union storage {
215 struct long_pointer {
216 pointer ptr;
217 size_type cap;
218 } long_;
219 CharT short_[sso_buffer_size];
220 } storage_;
221#else
222 pointer data_ = nullptr;
223 size_type size_ = 0;
225 compressed_pair<allocator_type, size_type> capacity_pair_{default_construct_tag{}, 0};
226#endif
227
228private:
229#ifdef NEFORCE_USING_SSO
234 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool is_long() const noexcept { return (size_pair_.value & long_flag) != 0; }
235
240 NEFORCE_CONSTEXPR20 void set_size(size_type new_size) noexcept {
241 size_pair_.value = (is_long() ? (new_size | long_flag) : new_size);
242 }
243
248 NEFORCE_CONSTEXPR20 void switch_to_long(size_type new_cap) {
249 NEFORCE_DEBUG_VERIFY(new_cap >= sso_buffer_size, "switch_to_long: new_cap too small");
250 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
251 const size_type old_size = size();
252 traits_type::copy(new_ptr, storage_.short_, old_size);
253 traits_type::assign(new_ptr + old_size, 1, value_type());
254
255 storage_.long_.ptr = new_ptr;
256 storage_.long_.cap = new_cap;
257 size_pair_.value = old_size | long_flag;
258 }
259
263 NEFORCE_CONSTEXPR20 void destroy_long() noexcept {
264 if (storage_.long_.ptr) {
265 size_pair_.get_base().deallocate(storage_.long_.ptr, storage_.long_.cap);
266 storage_.long_.ptr = nullptr;
267 storage_.long_.cap = 0;
268 }
269 }
270#endif
271
278 template <typename Iterator>
279 NEFORCE_CONSTEXPR20 void construct_from_iter(Iterator first, Iterator last) {
280 const size_type n = _NEFORCE distance(first, last);
281
282#ifdef NEFORCE_USING_SSO
283 if (n < sso_capacity) {
284 pointer dest = storage_.short_;
285 for (size_type i = 0; i < n; ++i) {
286 dest[i] = *first++;
287 }
288 traits_type::assign(dest + n, 1, value_type());
289 size_pair_.value = n;
290 } else {
291 const size_type init_cap = _NEFORCE max(sso_buffer_size, n + 1);
292 pointer new_ptr = size_pair_.get_base().allocate(init_cap);
293 pointer dest = new_ptr;
294 for (size_type i = 0; i < n; ++i) {
295 *dest++ = *first++;
296 }
297 traits_type::assign(new_ptr + n, 1, value_type());
298
299 storage_.long_.ptr = new_ptr;
300 storage_.long_.cap = init_cap;
301 size_pair_.value = n | long_flag;
302 }
303#else
304 const size_type init_size = _NEFORCE max(MEMORY_ALIGN_THRESHHOLD, n + 1);
305 pointer temp_data = nullptr;
306 try {
307 temp_data = capacity_pair_.get_base().allocate(init_size);
308 size_ = n;
309 capacity_pair_.value = init_size;
310 _NEFORCE uninitialized_copy(first, last, temp_data);
311
312 data_ = temp_data;
313 size_ = n;
314 capacity_pair_.value = init_size;
315 traits_type::assign(data_ + size_, 1, value_type());
316 } catch (...) {
317 if (temp_data) {
318 _NEFORCE destroy(temp_data, temp_data + n);
319 capacity_pair_.get_base().deallocate(temp_data, capacity_pair_.value);
320 }
321 destroy_buffer();
322 throw;
323 }
324#endif
325 }
326
333 NEFORCE_CONSTEXPR20 void construct_from_ptr(const_pointer str, size_type position, size_type n) {
334#ifdef NEFORCE_USING_SSO
335 if (n < sso_capacity) {
336 traits_type::copy(storage_.short_, str + position, n);
337 traits_type::assign(storage_.short_ + n, 1, value_type());
338 size_pair_.value = n;
339 } else {
340 const size_type init_cap = _NEFORCE max(sso_buffer_size, n + 1);
341 pointer new_ptr = size_pair_.get_base().allocate(init_cap);
342 traits_type::copy(new_ptr, str + position, n);
343 traits_type::assign(new_ptr + n, 1, value_type());
344
345 storage_.long_.ptr = new_ptr;
346 storage_.long_.cap = init_cap;
347 size_pair_.value = n | long_flag;
348 }
349#else
350 pointer temp_data = nullptr;
351 size_type temp_capacity = 0;
352 try {
353 temp_capacity = _NEFORCE max(MEMORY_ALIGN_THRESHHOLD, n + 1);
354 temp_data = capacity_pair_.get_base().allocate(temp_capacity);
355 traits_type::copy(temp_data, str + position, n);
356
357 data_ = temp_data;
358 size_ = n;
359 capacity_pair_.value = temp_capacity;
360 traits_type::assign(data_ + size_, 1, value_type());
361 } catch (...) {
362 if (temp_data) {
363 capacity_pair_.get_base().deallocate(temp_data, capacity_pair_.value);
364 }
365 data_ = nullptr;
366 size_ = 0;
367 capacity_pair_.value = 0;
368 throw;
369 }
370#endif
371 }
372
376 NEFORCE_CONSTEXPR20 void destroy_buffer() noexcept {
377#ifdef NEFORCE_USING_SSO
378 if (is_long()) {
379 destroy_long();
380 }
381 size_pair_.value = 0;
382 traits_type::assign(storage_.short_, 1, value_type());
383#else
384 if (data_) {
385 if (capacity_pair_.value > 0) {
386 capacity_pair_.get_base().deallocate(data_, capacity_pair_.value);
387 }
388 data_ = nullptr;
389 }
390 capacity_pair_.value = 0;
391 size_ = 0;
392#endif
393 }
394
403 NEFORCE_CONSTEXPR20 basic_string& replace_fill(iterator first, size_type n1, const size_type n2,
404 const value_type value) {
405#ifdef NEFORCE_USING_SSO
406 const difference_type offset = first - begin();
407 const size_type old_size = size();
408 const size_type actual_n1 = _NEFORCE min(n1, old_size - offset);
409 if (actual_n1 == 0 && n2 == 0) {
410 return *this;
411 }
412
413 const size_type new_size = old_size - actual_n1 + n2;
414
415 if (!is_long() && new_size < sso_capacity) {
416 pointer p = storage_.short_ + offset;
417 if (static_cast<difference_type>(old_size - offset - actual_n1) > 0) {
418 traits_type::move(p + n2, p + actual_n1, old_size - offset - actual_n1);
419 }
420 traits_type::assign(p, n2, value);
421 size_pair_.value = new_size;
422 traits_type::assign(storage_.short_ + new_size, 1, value_type());
423 return *this;
424 }
425
426 size_type new_cap = is_long() ? storage_.long_.cap : sso_buffer_size;
427 if (new_cap < new_size + 1) {
428 new_cap = _NEFORCE max(new_size + 1, new_cap + (new_cap >> 1));
429 }
430
431 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
432 pointer dest = new_ptr;
433
434 dest = traits_type::copy(dest, data(), offset) + offset;
435 dest = traits_type::assign(dest, n2, value) + n2;
436 traits_type::copy(dest, data() + offset + actual_n1, old_size - offset - actual_n1);
437
438 if (is_long()) {
439 destroy_long();
440 }
441 storage_.long_.ptr = new_ptr;
442 storage_.long_.cap = new_cap;
443 size_pair_.value = new_size | long_flag;
444 traits_type::assign(storage_.long_.ptr + new_size, 1, value_type());
445
446 return *this;
447#else
448 if (static_cast<size_type>(end() - first) < n1) {
449 n1 = static_cast<size_type>(end() - first);
450 }
451
452 if (n1 < n2) {
453 const size_type diff = n2 - n1;
454 NEFORCE_DEBUG_VERIFY(size_ + diff < max_size(), "basic_string index out of range.");
455 if (size_ > capacity_pair_.value - diff) {
456 reallocate(diff);
457 }
458
459 pointer raw_ptr = &*first;
460 traits_type::move(raw_ptr + n2, raw_ptr + n1, end() - (first + n1));
461 traits_type::assign(raw_ptr, n2, value);
462 size_ += diff;
463 } else {
464 pointer raw_ptr = &*first;
465 traits_type::move(raw_ptr + n2, raw_ptr + n1, end() - (first + n1));
466 traits_type::assign(raw_ptr, n2, value);
467 size_ -= n1 - n2;
468 }
469
470 traits_type::assign(data_ + size_, 1, value_type());
471 return *this;
472#endif
473 }
474
484 template <typename Iterator, enable_if_t<is_iter_v<Iterator>, int> = 0>
485 NEFORCE_CONSTEXPR20 basic_string& replace_copy(iterator first1, iterator last1, Iterator first2, Iterator last2) {
486 static_assert(is_iter_v<Iterator> && is_same_v<iter_value_t<Iterator>, value_type>, "Iterator type mismatch.");
487
488 size_type len1 = _NEFORCE distance(first1, last1);
489 size_type len2 = _NEFORCE distance(first2, last2);
490
491#ifdef NEFORCE_USING_SSO
492 const difference_type offset = first1 - begin();
493 const size_type old_size = size();
494 const size_type new_size = old_size - len1 + len2;
495
496 if (!is_long() && new_size < sso_capacity) {
497 pointer p = storage_.short_ + offset;
498 if (static_cast<difference_type>(old_size - offset - len1) > 0) {
499 traits_type::move(p + len2, p + len1, old_size - offset - len1);
500 }
501 for (size_type i = 0; i < len2; ++i) {
502 p[i] = *first2++;
503 }
504 size_pair_.value = new_size;
505 traits_type::assign(storage_.short_ + new_size, 1, value_type());
506 return *this;
507 }
508
509 size_type new_cap = is_long() ? storage_.long_.cap : sso_buffer_size;
510 if (new_cap < new_size + 1) {
511 new_cap = _NEFORCE max(new_size + 1, new_cap + (new_cap >> 1));
512 }
513
514 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
515 pointer dest = new_ptr;
516
517 dest = traits_type::copy(dest, data(), offset) + offset;
518 dest = _NEFORCE uninitialized_copy(first2, last2, dest);
519 traits_type::copy(dest, data() + offset + len1, old_size - offset - len1);
520
521 if (is_long()) {
522 destroy_long();
523 }
524 storage_.long_.ptr = new_ptr;
525 storage_.long_.cap = new_cap;
526 size_pair_.value = new_size | long_flag;
527 traits_type::assign(storage_.long_.ptr + new_size, 1, value_type());
528
529 return *this;
530#else
531 if (len1 < len2) {
532 const size_type diff = len2 - len1;
533 NEFORCE_DEBUG_VERIFY(size_ + diff < max_size(), "basic_string replace_copy index out of range.");
534 if (size_ > capacity_pair_.value - diff) {
535 reallocate(diff);
536 }
537
538 pointer raw_ptr = &*first1;
539 traits_type::move(raw_ptr + len2, raw_ptr + len1, end() - (first1 + len1));
540 traits_type::copy(raw_ptr, &*first2, len2);
541 size_ += diff;
542 } else {
543 pointer raw_ptr = &*first1;
544 traits_type::move(raw_ptr + len2, raw_ptr + len1, end() - (first1 + len1));
545 traits_type::copy(raw_ptr, &*first2, len2);
546 size_ -= len1 - len2;
547 }
548
549 traits_type::assign(data_ + size_, 1, value_type());
550 return *this;
551#endif
552 }
553
563 template <typename Iterator, enable_if_t<is_iter_v<Iterator>, int> = 0>
564 NEFORCE_CONSTEXPR20 basic_string& replace_copy(iterator first1, const size_type n1, Iterator first2,
565 const size_type n2) {
566 return replace_copy(first1, first1 + n1, first2, _NEFORCE next(first2, n2));
567 }
568
573 NEFORCE_CONSTEXPR20 void reallocate(size_type n) {
574#ifdef NEFORCE_USING_SSO
575 if (!is_long()) {
576 const size_type new_cap = _NEFORCE max(sso_buffer_size, size() + n + 1);
577 switch_to_long(new_cap);
578 return;
579 }
580
581 const size_type old_cap = storage_.long_.cap;
582 const size_type min_new_cap = size() + n + 1;
583 const size_type new_cap = _NEFORCE max(min_new_cap, old_cap + (old_cap >> 1));
584
585 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
586 traits_type::move(new_ptr, storage_.long_.ptr, size());
587 traits_type::assign(new_ptr + size(), 1, value_type());
588
589 destroy_long();
590 storage_.long_.ptr = new_ptr;
591 storage_.long_.cap = new_cap;
592#else
593 pointer new_buffer = nullptr;
594 try {
595 const size_t new_cap =
596 _NEFORCE max(capacity_pair_.value + n, capacity_pair_.value + (capacity_pair_.value >> 1)) + 1;
597 new_buffer = capacity_pair_.get_base().allocate(new_cap);
598 traits_type::move(new_buffer, data_, size_);
599
600 capacity_pair_.get_base().deallocate(data_, capacity_pair_.value);
601 data_ = new_buffer;
602 capacity_pair_.value = new_cap;
603 traits_type::assign(data_ + size_, 1, value_type());
604 } catch (...) {
605 if (new_buffer) {
606 capacity_pair_.get_base().deallocate(new_buffer, capacity_pair_.value);
607 }
608 throw;
609 }
610#endif
611 }
612
620 NEFORCE_CONSTEXPR20 iterator reallocate_fill(iterator position, size_type n, value_type value) {
621#ifdef NEFORCE_USING_SSO
622 const size_type offset = position - begin();
623 if (!is_long() && size() + n < sso_buffer_size) {
624 pointer p = storage_.short_ + offset;
625 traits_type::move(p + n, p, size() - offset);
626 traits_type::assign(p, n, value);
627 size_pair_.value = (size() + n);
628 traits_type::assign(storage_.short_ + size(), 1, value_type());
629 return iterator(storage_.short_ + offset, this);
630 }
631
632 const size_type old_size = size();
633 const size_type new_cap = _NEFORCE max((is_long() ? storage_.long_.cap : sso_buffer_size) + n,
634 (is_long() ? storage_.long_.cap : sso_buffer_size) +
635 ((is_long() ? storage_.long_.cap : sso_buffer_size) >> 1)) +
636 1;
637
638 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
639 pointer dest = new_ptr;
640
641 dest = traits_type::copy(dest, data(), offset) + offset;
642 dest = traits_type::assign(dest, n, value) + n;
643 traits_type::copy(dest, data() + offset, old_size - offset);
644
645 if (is_long()) {
646 destroy_long();
647 }
648 storage_.long_.ptr = new_ptr;
649 storage_.long_.cap = new_cap;
650 size_pair_.value = (old_size + n) | long_flag;
651 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
652
653 return iterator(storage_.long_.ptr + offset, this);
654#else
655 const difference_type diff = (&*position) - data_;
656 const size_t old_cap = capacity_pair_.value;
657 const size_t new_cap = _NEFORCE max(old_cap + n, old_cap + (old_cap >> 1));
658 pointer new_buffer = capacity_pair_.get_base().allocate(new_cap);
659 pointer end1 = traits_type::move(new_buffer, data_, diff) + diff;
660 pointer end2 = traits_type::assign(end1, n, value) + n;
661 traits_type::move(end2, data_ + diff, size_ - diff);
662 capacity_pair_.get_base().deallocate(data_, old_cap);
663 data_ = new_buffer;
664 size_ += n;
665 capacity_pair_.value = new_cap;
666 traits_type::assign(data_ + size_, 1, value_type());
667 return iterator(data_ + diff, this);
668#endif
669 }
670
679 template <typename Iterator>
680 NEFORCE_CONSTEXPR20 iterator reallocate_copy(iterator position, Iterator first, Iterator last) {
681#ifdef NEFORCE_USING_SSO
682 const size_type offset = position - begin();
683 const size_type n = _NEFORCE distance(first, last);
684 const size_type old_size = size();
685
686 if (!is_long() && old_size + n < sso_buffer_size) {
687 pointer p = storage_.short_ + offset;
688 traits_type::move(p + n, p, old_size - offset);
689 for (size_type i = 0; i < n; ++i) {
690 p[i] = *first++;
691 }
692 size_pair_.value = old_size + n;
693 traits_type::assign(storage_.short_ + size(), 1, value_type());
694 return iterator(storage_.short_ + offset, this);
695 }
696
697 const size_type new_cap = _NEFORCE max((is_long() ? storage_.long_.cap : sso_buffer_size) + n,
698 (is_long() ? storage_.long_.cap : sso_buffer_size) +
699 ((is_long() ? storage_.long_.cap : sso_buffer_size) >> 1)) +
700 1;
701
702 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
703 pointer dest = new_ptr;
704
705 dest = traits_type::copy(dest, data(), offset) + offset;
706 dest = _NEFORCE uninitialized_copy(first, last, dest);
707 traits_type::copy(dest, data() + offset, old_size - offset);
708
709 if (is_long()) {
710 destroy_long();
711 }
712 storage_.long_.ptr = new_ptr;
713 storage_.long_.cap = new_cap;
714 size_pair_.value = (old_size + n) | long_flag;
715 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
716
717 return iterator(storage_.long_.ptr + offset, this);
718#else
719 const difference_type diff = position - begin();
720 const size_type old_cap = capacity_pair_.value;
721 const size_type n = _NEFORCE distance(first, last);
722 const size_t new_cap = _NEFORCE max(old_cap + n, old_cap + (old_cap >> 1));
723 pointer new_buffer = capacity_pair_.get_base().allocate(new_cap);
724 pointer end1 = traits_type::move(new_buffer, data_, diff) + diff;
725 pointer end2 = _NEFORCE uninitialized_copy_n(first, n, end1) + n;
726 traits_type::move(end2, data_ + diff, size_ - diff);
727 capacity_pair_.get_base().deallocate(data_, old_cap);
728 data_ = new_buffer;
729 size_ += n;
730 capacity_pair_.value = new_cap;
731 traits_type::assign(data_ + size_, 1, value_type());
732 return iterator(data_ + diff, this);
733#endif
734 }
735
736public:
742 NEFORCE_CONSTEXPR20 basic_string() {
743#ifdef NEFORCE_USING_SSO
744 traits_type::assign(storage_.short_, 1, value_type());
745 size_pair_.value = 0;
746#else
747 basic_string::reserve(MEMORY_ALIGN_THRESHHOLD);
748#endif
749 }
750
755 NEFORCE_CONSTEXPR20 explicit basic_string(size_type n) :
756 basic_string(n, static_cast<value_type>(0)) {}
757
763 NEFORCE_CONSTEXPR20 explicit basic_string(size_type n, int32_t value) :
764 basic_string(n, static_cast<value_type>(value)) {}
765
771 NEFORCE_CONSTEXPR20 explicit basic_string(size_type n, int64_t value) :
772 basic_string(n, static_cast<value_type>(value)) {}
773
779 NEFORCE_CONSTEXPR20 explicit basic_string(size_type n, value_type value) {
780#ifdef NEFORCE_USING_SSO
781 if (n < sso_capacity) {
782 traits_type::assign(storage_.short_, n, value);
783 traits_type::assign(storage_.short_ + n, 1, value_type());
784 size_pair_.value = n;
785 } else {
786 const size_type init_cap = _NEFORCE max(sso_buffer_size, n + 1);
787 pointer new_ptr = size_pair_.get_base().allocate(init_cap);
788 traits_type::assign(new_ptr, n, value);
789 traits_type::assign(new_ptr + n, 1, value_type());
790
791 storage_.long_.ptr = new_ptr;
792 storage_.long_.cap = init_cap;
793 size_pair_.value = n | long_flag;
794 }
795#else
796 const size_type init_size = _NEFORCE max(MEMORY_ALIGN_THRESHHOLD, n + 1);
797 data_ = capacity_pair_.get_base().allocate(init_size);
798 traits_type::assign(data_, n, value);
799 size_ = n;
800 capacity_pair_.value = init_size;
801 traits_type::assign(data_ + size_, 1, value_type());
802#endif
803 }
804
809 NEFORCE_CONSTEXPR20 basic_string(const basic_string& other) {
810#ifdef NEFORCE_USING_SSO
811 const size_type len = other.size();
812 if (len < sso_capacity) {
813 traits_type::copy(storage_.short_, other.data(), len);
814 traits_type::assign(storage_.short_ + len, 1, value_type());
815 size_pair_.value = len;
816 } else {
817 const size_type cap = other.is_long() ? other.storage_.long_.cap : (len + 1);
818 pointer new_ptr = size_pair_.get_base().allocate(cap);
819 traits_type::copy(new_ptr, other.data(), len);
820 traits_type::assign(new_ptr + len, 1, value_type());
821
822 storage_.long_.ptr = new_ptr;
823 storage_.long_.cap = cap;
824 size_pair_.value = len | long_flag;
825 }
826#else
827 construct_from_ptr(other.data(), 0, other.size());
828#endif
829 }
830
836 NEFORCE_CONSTEXPR20 basic_string& operator=(const basic_string& other) {
837 if (_NEFORCE addressof(other) == this) {
838 return *this;
839 }
840
841#ifdef NEFORCE_USING_SSO
842 const size_type len = other.size();
843
844 if (len < sso_capacity) {
845 if (is_long()) {
846 destroy_long();
847 }
848 traits_type::copy(storage_.short_, other.data(), len);
849 traits_type::assign(storage_.short_ + len, 1, value_type());
850 size_pair_.value = len;
851 } else {
852 if (is_long()) {
853 if (storage_.long_.cap >= len + 1) {
854 traits_type::copy(storage_.long_.ptr, other.data(), len);
855 traits_type::assign(storage_.long_.ptr + len, 1, value_type());
856 size_pair_.value = len | long_flag;
857 return *this;
858 }
859 destroy_long();
860 }
861
862 const size_type cap = other.is_long() ? other.storage_.long_.cap : (len + 1);
863 pointer new_ptr = size_pair_.get_base().allocate(cap);
864 traits_type::copy(new_ptr, other.data(), len);
865 traits_type::assign(new_ptr + len, 1, value_type());
866
867 storage_.long_.ptr = new_ptr;
868 storage_.long_.cap = cap;
869 size_pair_.value = len | long_flag;
870 }
871#else
872 destroy_buffer();
873 construct_from_ptr(other.data(), 0, other.size());
874#endif
875 return *this;
876 }
877
882 NEFORCE_CONSTEXPR20 basic_string(basic_string&& other) noexcept
883#ifdef NEFORCE_USING_SSO
884 :
885 size_pair_(_NEFORCE move(other.size_pair_)) {
886 if (other.is_long()) {
887 storage_.long_.ptr = other.storage_.long_.ptr;
888 storage_.long_.cap = other.storage_.long_.cap;
889 size_pair_.value = other.size_pair_.value;
890
891 other.storage_.long_.ptr = nullptr;
892 other.storage_.long_.cap = 0;
893 other.size_pair_.value = 0;
894 } else {
895 traits_type::copy(storage_.short_, other.storage_.short_, other.size() + 1);
896 size_pair_.value = other.size();
897 traits_type::assign(other.storage_.short_, 1, value_type());
898 other.size_pair_.value = 0;
899 }
900#else
901 :
902 data_(other.data_),
903 size_(other.size_),
904 capacity_pair_(_NEFORCE move(other.capacity_pair_)) {
905 other.data_ = nullptr;
906 other.size_ = 0;
907 other.capacity_pair_.value = 0;
908#endif
909 }
910
916 NEFORCE_CONSTEXPR20 basic_string& operator=(basic_string&& other) noexcept {
917 if (_NEFORCE addressof(other) == this) {
918 return *this;
919 }
920
921#ifdef NEFORCE_USING_SSO
922 destroy_buffer();
923
924 size_pair_ = _NEFORCE move(other.size_pair_);
925
926 if (other.is_long()) {
927 storage_.long_.ptr = other.storage_.long_.ptr;
928 storage_.long_.cap = other.storage_.long_.cap;
929 size_pair_.value = other.size_pair_.value;
930
931 other.storage_.long_.ptr = nullptr;
932 other.storage_.long_.cap = 0;
933 other.size_pair_.value = 0;
934 } else {
935 traits_type::copy(storage_.short_, other.storage_.short_, other.size() + 1);
936 size_pair_.value = other.size();
937 traits_type::assign(other.storage_.short_, 1, value_type());
938 other.size_pair_.value = 0;
939 }
940#else
941 pointer new_data = other.data_;
942 const size_type new_size = other.size_;
943 auto new_capacity_pair = _NEFORCE move(other.capacity_pair_);
944
945 other.data_ = nullptr;
946 other.size_ = 0;
947 other.capacity_pair_.value = 0;
948
949 destroy_buffer();
950 data_ = new_data;
951 size_ = new_size;
952 capacity_pair_ = _NEFORCE move(new_capacity_pair);
953#endif
954
955 return *this;
956 }
957
962 NEFORCE_CONSTEXPR20 basic_string(view_type view) { construct_from_ptr(view.data(), 0, view.size()); }
963
969 NEFORCE_CONSTEXPR20 basic_string(view_type view, const size_type n) { construct_from_ptr(view.data(), 0, n); }
970
976 NEFORCE_CONSTEXPR20 basic_string& operator=(view_type view) {
977 const size_type len = view.size();
978
979#ifdef NEFORCE_USING_SSO
980 if (len < sso_capacity) {
981 if (is_long()) {
982 destroy_long();
983 }
984 traits_type::copy(storage_.short_, view.data(), len);
985 traits_type::assign(storage_.short_ + len, 1, value_type());
986 size_pair_.value = len;
987 } else {
988 if (is_long() && storage_.long_.cap >= len + 1) {
989 traits_type::copy(storage_.long_.ptr, view.data(), len);
990 traits_type::assign(storage_.long_.ptr + len, 1, value_type());
991 size_pair_.value = len | long_flag;
992 return *this;
993 }
994
995 if (is_long()) {
996 destroy_long();
997 }
998 const size_type new_cap = len + 1;
999 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
1000 traits_type::copy(new_ptr, view.data(), len);
1001 traits_type::assign(new_ptr + len, 1, value_type());
1002
1003 storage_.long_.ptr = new_ptr;
1004 storage_.long_.cap = new_cap;
1005 size_pair_.value = len | long_flag;
1006 }
1007#else
1008 if (capacity_pair_.value < len) {
1009 pointer new_buffer = capacity_pair_.get_base().allocate(len + 1);
1010 capacity_pair_.get_base().deallocate(data_);
1011 data_ = new_buffer;
1012 capacity_pair_.value = len + 1;
1013 }
1014
1015 traits_type::copy(data_, view.data(), len);
1016 size_ = len;
1017 traits_type::assign(data_ + size_, 1, value_type());
1018#endif
1019 return *this;
1020 }
1021
1027 NEFORCE_CONSTEXPR20 basic_string(const basic_string& other, size_type position) {
1028 NEFORCE_DEBUG_VERIFY(position <= other.size(), "basic_string index out of range");
1029 construct_from_ptr(other.data(), position, other.size() - position);
1030 }
1031
1038 NEFORCE_CONSTEXPR20 basic_string(const basic_string& other, size_type position, size_type n) {
1039 NEFORCE_DEBUG_VERIFY(position <= other.size(), "basic_string index out of range");
1040 n = _NEFORCE min(n, other.size() - position);
1041 construct_from_ptr(other.data(), position, n);
1042 }
1043
1050 NEFORCE_CONSTEXPR20 basic_string(const_pointer str) { construct_from_ptr(str, 0, traits_type::length(str)); }
1051
1057 NEFORCE_CONSTEXPR20 basic_string(const_pointer str, const size_type n) { construct_from_ptr(str, 0, n); }
1058
1066 NEFORCE_CONSTEXPR20 basic_string& operator=(const_pointer str) {
1067 const size_type len = traits_type::length(str);
1068#ifdef NEFORCE_USING_SSO
1069 if (len < sso_capacity) {
1070 if (is_long()) {
1071 destroy_long();
1072 }
1073 traits_type::copy(storage_.short_, str, len);
1074 traits_type::assign(storage_.short_ + len, 1, value_type());
1075 size_pair_.value = len;
1076 } else {
1077 if (is_long() && storage_.long_.cap >= len + 1) {
1078 traits_type::copy(storage_.long_.ptr, str, len);
1079 traits_type::assign(storage_.long_.ptr + len, 1, value_type());
1080 size_pair_.value = len | long_flag;
1081 return *this;
1082 }
1083
1084 if (is_long()) {
1085 destroy_long();
1086 }
1087 const size_type new_cap = len + 1;
1088 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
1089 traits_type::copy(new_ptr, str, len);
1090 traits_type::assign(new_ptr + len, 1, value_type());
1091
1092 storage_.long_.ptr = new_ptr;
1093 storage_.long_.cap = new_cap;
1094 size_pair_.value = len | long_flag;
1095 }
1096#else
1097 if (capacity_pair_.value < len) {
1098 pointer new_buffer = capacity_pair_.get_base().allocate(len + 1);
1099 capacity_pair_.get_base().deallocate(data_);
1100 data_ = new_buffer;
1101 capacity_pair_.value = len + 1;
1102 }
1103 traits_type::copy(data_, str, len);
1104 size_ = len;
1105 traits_type::assign(data_ + size_, 1, value_type());
1106#endif
1107 return *this;
1108 }
1109
1116 template <typename Iterator, enable_if_t<!is_convertible_v<Iterator, value_type>, int> = 0>
1117 NEFORCE_CONSTEXPR20 basic_string(Iterator first, Iterator last) {
1118 construct_from_iter(first, last);
1119 }
1120
1125 NEFORCE_CONSTEXPR20 basic_string(std::initializer_list<value_type> ilist) :
1126 basic_string(ilist.begin(), ilist.end()) {}
1127
1133 NEFORCE_CONSTEXPR20 basic_string& operator=(std::initializer_list<value_type> ilist) {
1134 clear();
1135 insert(begin(), ilist.begin(), ilist.end());
1136 return *this;
1137 }
1138
1142 NEFORCE_CONSTEXPR20 ~basic_string() { destroy_buffer(); }
1143
1148 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 iterator begin() noexcept { return {data(), this}; }
1149
1154 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 iterator end() noexcept { return {data() + size(), this}; }
1155
1160 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator begin() const noexcept { return cbegin(); }
1161
1166 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator end() const noexcept { return cend(); }
1167
1172 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator cbegin() const noexcept { return {data(), this}; }
1173
1178 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator cend() const noexcept { return {data() + size(), this}; }
1179
1184 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
1185
1190 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
1191
1196 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator rbegin() const noexcept { return crbegin(); }
1197
1202 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator rend() const noexcept { return crend(); }
1203
1208 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator crbegin() const noexcept {
1209 return const_reverse_iterator(cend());
1210 }
1211
1216 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator crend() const noexcept {
1218 }
1219
1224 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type size() const noexcept {
1225#ifdef NEFORCE_USING_SSO
1226 return size_pair_.value & ~long_flag;
1227#else
1228 return size_;
1229#endif
1230 }
1231
1236 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type max_size() const noexcept {
1237#ifdef NEFORCE_USING_SSO
1238 constexpr size_type flag_mask = ~long_flag;
1239 const size_type alloc_max = size_pair_.get_base().max_size();
1240#else
1241 constexpr size_type flag_mask = npos;
1242 const size_type alloc_max = capacity_pair_.get_base().max_size();
1243#endif
1244 return _NEFORCE min(alloc_max - 1, npos & flag_mask);
1245 }
1246
1251 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type capacity() const noexcept {
1252#ifdef NEFORCE_USING_SSO
1253 return is_long() ? storage_.long_.cap : sso_buffer_size;
1254#else
1255 return capacity_pair_.value;
1256#endif
1257 }
1258
1263 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type length() const noexcept { return size(); }
1264
1269 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool empty() const noexcept { return size() == 0; }
1270
1275 NEFORCE_CONSTEXPR20 void reserve(const size_type n) {
1276 NEFORCE_DEBUG_VERIFY(n < max_size(), "basic_string reserve index out of range.");
1277 const size_type new_cap = n + 1;
1278 if (new_cap <= capacity()) {
1279 return;
1280 }
1281
1282#ifdef NEFORCE_USING_SSO
1283 if (!is_long()) {
1284 switch_to_long(new_cap);
1285 } else {
1286 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
1287 traits_type::move(new_ptr, storage_.long_.ptr, size());
1288 traits_type::assign(new_ptr + size(), 1, value_type());
1289 destroy_long();
1290 storage_.long_.ptr = new_ptr;
1291 storage_.long_.cap = new_cap;
1292 }
1293#else
1294 pointer new_buffer = capacity_pair_.get_base().allocate(new_cap);
1295 traits_type::move(new_buffer, data_, size_);
1296 capacity_pair_.get_base().deallocate(data_, capacity_pair_.value);
1297
1298 data_ = new_buffer;
1299 capacity_pair_.value = new_cap;
1300 traits_type::assign(data_ + size_, 1, value_type());
1301#endif
1302 }
1303
1309 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference operator[](const size_type n) noexcept {
1310 NEFORCE_DEBUG_VERIFY(n <= size(), "basic_string [] index out of range.");
1311 return *(data() + n);
1312 }
1313
1319 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference operator[](const size_type n) const noexcept {
1320 NEFORCE_DEBUG_VERIFY(n <= size(), "basic_string [] index out of range.");
1321 return *(data() + n);
1322 }
1323
1329 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference at(const size_type n) noexcept { return (*this)[n]; }
1330
1336 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference at(const size_type n) const noexcept { return (*this)[n]; }
1337
1342 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference front() noexcept {
1343 NEFORCE_DEBUG_VERIFY(!empty(), "front called on empty basic_string");
1344 return *data();
1345 }
1346
1351 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference front() const noexcept {
1352 NEFORCE_DEBUG_VERIFY(!empty(), "front called on empty basic_string");
1353 return *data();
1354 }
1355
1360 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference back() noexcept {
1361 NEFORCE_DEBUG_VERIFY(!empty(), "back called on empty basic_string");
1362 return *(data() + size() - 1);
1363 }
1364
1369 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference back() const noexcept {
1370 NEFORCE_DEBUG_VERIFY(!empty(), "back called on empty basic_string");
1371 return *(data() + size() - 1);
1372 }
1373
1378 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 pointer data() noexcept {
1379#ifdef NEFORCE_USING_SSO
1380 if (!is_long()) {
1381 return storage_.short_;
1382 }
1383 return storage_.long_.ptr;
1384#else
1385 return data_;
1386#endif
1387 }
1388
1393 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_pointer data() const noexcept {
1394#ifdef NEFORCE_USING_SSO
1395 if (!is_long()) {
1396 return storage_.short_;
1397 }
1398 return storage_.long_.ptr;
1399#else
1400 return data_;
1401#endif
1402 }
1403
1410 NEFORCE_CONSTEXPR20 iterator insert(iterator position, value_type value) {
1411#ifdef NEFORCE_USING_SSO
1412 const size_type offset = position - begin();
1413 if (!is_long() && size() + 1 < sso_buffer_size) {
1414 pointer p = storage_.short_ + offset;
1415 traits_type::move(p + 1, p, size() - offset);
1416 *p = value;
1417 ++size_pair_.value;
1418 traits_type::assign(storage_.short_ + size(), 1, value_type());
1419 return iterator(p, this);
1420 }
1421 return basic_string::reallocate_fill(position, 1, value);
1422#else
1423 if (size_ == capacity_pair_.value) {
1424 return basic_string::reallocate_fill(position, 1, value);
1425 }
1426
1427 size_type offset = position - begin();
1428 pointer p = data_ + offset;
1429 size_type chars_after = size_ - offset;
1430 if (chars_after > 0) {
1431 traits_type::move(p + 1, p, chars_after);
1432 }
1433
1434 *p = value;
1435 ++size_;
1436 traits_type::assign(data_ + size_, 1, value_type());
1437 return iterator(p, this);
1438#endif
1439 }
1440
1448 NEFORCE_CONSTEXPR20 basic_string& insert(size_type position, size_type n, value_type value) {
1449 insert(begin() + position, n, value);
1450 return *this;
1451 }
1452
1453 NEFORCE_CONSTEXPR20 iterator insert(iterator position, size_type n, value_type value) {
1454 if (n == 0) {
1455 return position;
1456 }
1457
1458#ifdef NEFORCE_USING_SSO
1459 if (!is_long() && size() + n < sso_buffer_size) {
1460 const size_type offset = position - begin();
1461 pointer p = storage_.short_ + offset;
1462 traits_type::move(p + n, p, size() - offset);
1463 traits_type::assign(p, n, value);
1464 size_pair_.value = size() + n;
1465 traits_type::assign(storage_.short_ + size(), 1, value_type());
1466 return iterator(p, this);
1467 }
1468
1469 return basic_string::reallocate_fill(position, n, value);
1470#else
1471 if (capacity_pair_.value - size_ < n) {
1472 return basic_string::reallocate_fill(position, n, value);
1473 }
1474
1475 const size_type offset = position - begin();
1476 pointer p = data_ + offset;
1477 const size_type chars_after = size_ - offset;
1478
1479 if (chars_after > 0) {
1480 traits_type::move(p + n, p, chars_after);
1481 }
1482 traits_type::assign(p, n, value);
1483
1484 size_ += n;
1485 traits_type::assign(data_ + size_, 1, value_type());
1486 return iterator(p, this);
1487#endif
1488 }
1489
1498 template <typename Iterator>
1499 NEFORCE_CONSTEXPR20 iterator insert(iterator position, Iterator first, Iterator last) {
1500 const size_type len = _NEFORCE distance(first, last);
1501 if (len == 0) {
1502 return position;
1503 }
1504
1505#ifdef NEFORCE_USING_SSO
1506 if (!is_long() && size() + len < sso_buffer_size) {
1507 const size_type offset = position - begin();
1508 pointer p = storage_.short_ + offset;
1509 traits_type::move(p + len, p, size() - offset);
1510 for (size_type i = 0; i < len; ++i) {
1511 p[i] = *first++;
1512 }
1513 size_pair_.value = size() + len;
1514 traits_type::assign(storage_.short_ + size(), 1, value_type());
1515 return iterator(p, this);
1516 }
1517 return basic_string::reallocate_copy(position, first, last);
1518#else
1519 if (capacity_pair_.value - size_ < len) {
1520 return basic_string::reallocate_copy(position, first, last);
1521 }
1522
1523 const size_type offset = position - begin();
1524 pointer p = data_ + offset;
1525 const size_type chars_after = size_ - offset;
1526
1527 if (chars_after > 0) {
1528 traits_type::move(p + len, p, chars_after);
1529 }
1530 pointer curr = p;
1531 for (Iterator it = first; it != last; ++it, ++curr) {
1532 *curr = *it;
1533 }
1534
1535 size_ += len;
1536 traits_type::assign(data_ + size_, 1, value_type());
1537 return position;
1538#endif
1539 }
1540
1545 NEFORCE_CONSTEXPR20 void push_back(value_type value) { append(1, value); }
1546
1550 NEFORCE_CONSTEXPR20 void pop_back() noexcept {
1551 NEFORCE_DEBUG_VERIFY(!empty(), "pop_back called on empty basic_string");
1552#ifdef NEFORCE_USING_SSO
1553 const size_type new_size = size() - 1;
1554 if (is_long()) {
1555 size_pair_.value = new_size | long_flag;
1556 traits_type::assign(storage_.long_.ptr + new_size, 1, value_type());
1557 } else {
1558 size_pair_.value = new_size;
1559 traits_type::assign(storage_.short_ + new_size, 1, value_type());
1560 }
1561#else
1562 --size_;
1563 traits_type::assign(data_ + size_, 1, value_type());
1564#endif
1565 }
1566
1573 NEFORCE_CONSTEXPR20 basic_string& append(size_type n, value_type value) {
1574 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1575 if (n == 0) {
1576 return *this;
1577 }
1578
1579#ifdef NEFORCE_USING_SSO
1580 if (!is_long() && size() + n < sso_buffer_size) {
1581 pointer p = storage_.short_ + size();
1582 traits_type::assign(p, n, value);
1583 size_pair_.value = size() + n;
1584 traits_type::assign(storage_.short_ + size(), 1, value_type());
1585 return *this;
1586 }
1587
1588 const size_type old_size = size();
1589 if (is_long() && storage_.long_.cap >= old_size + n + 1) {
1590 pointer p = storage_.long_.ptr + old_size;
1591 traits_type::assign(p, n, value);
1592 size_pair_.value = (old_size + n) | long_flag;
1593 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1594 return *this;
1595 }
1596
1597 reallocate(n);
1598 pointer p = data() + old_size;
1599 traits_type::assign(p, n, value);
1600 size_pair_.value = (old_size + n) | (is_long() ? long_flag : 0);
1602#else
1603 if (capacity_pair_.value - size_ <= n) {
1604 reallocate(n);
1605 }
1606 traits_type::assign(data_ + size_, n, value);
1607 size_ += n;
1608 traits_type::assign(data_ + size_, 1, value_type());
1609#endif
1610 return *this;
1611 }
1612
1618 NEFORCE_CONSTEXPR20 basic_string& append(value_type value) { return append(1, value); }
1619
1627 NEFORCE_CONSTEXPR20 basic_string& append(const basic_string& other, size_type position, size_type n) {
1628 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1629 if (n == 0) {
1630 return *this;
1631 }
1632 n = _NEFORCE min(n, other.size() - position);
1633 return basic_string::append(other.data() + position, n);
1634 }
1635
1641 NEFORCE_CONSTEXPR20 basic_string& append(const basic_string& other) { return append(other, 0, other.size()); }
1642
1649 NEFORCE_CONSTEXPR20 basic_string& append(const basic_string& other, size_type position) {
1650 return append(other, position, other.size() - position);
1651 }
1652
1660 NEFORCE_CONSTEXPR20 basic_string& append(basic_string&& other, size_type position, size_type n) {
1661 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1662 if (n == 0) {
1663 return *this;
1664 }
1665 n = _NEFORCE min(n, other.size() - position);
1666 basic_string::append(other.data() + position, n);
1667 other.clear();
1668 return *this;
1669 }
1670
1676 NEFORCE_CONSTEXPR20 basic_string& append(basic_string&& other) {
1677 const size_type len = other.size();
1678 return basic_string::append(_NEFORCE move(other), 0, len);
1679 }
1680
1687 NEFORCE_CONSTEXPR20 basic_string& append(basic_string&& other, size_type position) {
1688 const size_type len = other.size();
1689 return basic_string::append(_NEFORCE move(other), position, len - position);
1690 }
1691
1698 NEFORCE_CONSTEXPR20 basic_string& append(view_type view, size_type n) { return append(view.data(), n); }
1699
1705 NEFORCE_CONSTEXPR20 basic_string& append(view_type view) { return append(view.data(), view.size()); }
1706
1713 NEFORCE_CONSTEXPR20 basic_string& append(const_pointer str, size_type n) {
1714 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1715 if (n == 0) {
1716 return *this;
1717 }
1718
1719#ifdef NEFORCE_USING_SSO
1720 const size_type old_size = size();
1721 if (!is_long() && old_size + n < sso_buffer_size) {
1722 traits_type::copy(storage_.short_ + old_size, str, n);
1723 size_pair_.value = old_size + n;
1724 traits_type::assign(storage_.short_ + size(), 1, value_type());
1725 return *this;
1726 }
1727
1728 if (is_long() && storage_.long_.cap >= old_size + n + 1) {
1729 traits_type::copy(storage_.long_.ptr + old_size, str, n);
1730 size_pair_.value = (old_size + n) | long_flag;
1731 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1732 return *this;
1733 }
1734
1735 reallocate(n);
1736 traits_type::copy(data() + old_size, str, n);
1737 size_pair_.value = (old_size + n) | long_flag;
1739#else
1740 if (capacity_pair_.value - size_ <= n) {
1741 reallocate(n);
1742 }
1743 traits_type::copy(data_ + size_, str, n);
1744 size_ += n;
1745 traits_type::assign(data_ + size_, 1, value_type());
1746#endif
1747 return *this;
1748 }
1749
1757 NEFORCE_CONSTEXPR20 basic_string& append(const_pointer str) { return append(str, traits_type::length(str)); }
1758
1766 template <typename Iterator, enable_if_t<is_iter_v<Iterator>, int> = 0>
1767 NEFORCE_CONSTEXPR20 basic_string& append(Iterator first, Iterator last) {
1768 const size_type n = _NEFORCE distance(first, last);
1769 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1770 if (n == 0) {
1771 return *this;
1772 }
1773
1774#ifdef NEFORCE_USING_SSO
1775 const size_type old_size = size();
1776 if (!is_long() && old_size + n < sso_buffer_size) {
1777 pointer p = storage_.short_ + old_size;
1778 for (size_type i = 0; i < n; ++i) {
1779 p[i] = *first++;
1780 }
1781 size_pair_.value = old_size + n;
1782 traits_type::assign(storage_.short_ + size(), 1, value_type());
1783 return *this;
1784 }
1785
1786 if (is_long() && storage_.long_.cap >= old_size + n + 1) {
1787 pointer p = storage_.long_.ptr + old_size;
1788 for (size_type i = 0; i < n; ++i) {
1789 p[i] = *first++;
1790 }
1791 size_pair_.value = (old_size + n) | long_flag;
1792 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1793 return *this;
1794 }
1795
1796 reallocate(n);
1797 pointer p = data() + old_size;
1798 for (size_type i = 0; i < n; ++i) {
1799 p[i] = *first++;
1800 }
1801 size_pair_.value = (old_size + n) | long_flag;
1803#else
1804 if (capacity_pair_.value - size_ <= n) {
1805 reallocate(n);
1806 }
1807 _NEFORCE uninitialized_copy_n(first, n, data_ + size_);
1808 size_ += n;
1809 traits_type::assign(data_ + size_, 1, value_type());
1810#endif
1811 return *this;
1812 }
1813
1819 NEFORCE_CONSTEXPR20 basic_string& append(std::initializer_list<value_type> ilist) {
1820 return append(ilist.begin(), ilist.end());
1821 }
1822
1824 NEFORCE_CONSTEXPR20 basic_string& operator+=(const basic_string& other) { return basic_string::append(other); }
1825
1827 NEFORCE_CONSTEXPR20 basic_string& operator+=(basic_string&& other) {
1828 return basic_string::append(_NEFORCE move(other));
1829 }
1830
1832 NEFORCE_CONSTEXPR20 basic_string& operator+=(const value_type value) { return basic_string::append(value); }
1833
1835 NEFORCE_CONSTEXPR20 basic_string& operator+=(const_pointer str) { return basic_string::append(str); }
1836
1838 NEFORCE_CONSTEXPR20 basic_string& operator+=(std::initializer_list<value_type> ilist) {
1839 return basic_string::append(ilist);
1840 }
1841
1844
1850 NEFORCE_CONSTEXPR20 basic_string& assign(const basic_string& other) { return *this = other; }
1851
1857 NEFORCE_CONSTEXPR20 basic_string& assign(basic_string&& other) { return *this = _NEFORCE move(other); }
1858
1864 NEFORCE_CONSTEXPR20 basic_string& assign(const_pointer str) { return *this = str; }
1865
1872 NEFORCE_CONSTEXPR20 basic_string& assign(const_pointer str, const size_type n) {
1873 clear();
1874 return append(str, n);
1875 }
1876
1883 NEFORCE_CONSTEXPR20 basic_string& assign(const size_type n, value_type value) {
1884 clear();
1885 return append(n, value);
1886 }
1887
1895 template <typename Iterator>
1896 NEFORCE_CONSTEXPR20 basic_string& assign(Iterator first, Iterator last) {
1897 clear();
1898 return append(first, last);
1899 }
1900
1906 NEFORCE_CONSTEXPR20 basic_string& assign(std::initializer_list<value_type> ilist) { return *this = ilist; }
1907
1913 NEFORCE_CONSTEXPR20 basic_string& assign(const view_type& view) { return *this = view; }
1914
1920 NEFORCE_CONSTEXPR20 iterator erase(iterator position) noexcept {
1921 NEFORCE_DEBUG_VERIFY(position != end(), "erase: cannot erase end() iterator");
1922
1923#ifdef NEFORCE_USING_SSO
1924 const size_type offset = position - begin();
1925 pointer p = data() + offset;
1926 const size_type chars_after = size() - offset - 1;
1927 if (chars_after > 0) {
1928 traits_type::move(p, p + 1, chars_after);
1929 }
1930 if (is_long()) {
1931 size_pair_.value = (size() - 1) | long_flag;
1932 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1933 } else {
1934 size_pair_.value = size() - 1;
1935 traits_type::assign(storage_.short_ + size(), 1, value_type());
1936 }
1937#else
1938 pointer ptr = &*position;
1939 const size_type chars_after = end() - position - 1;
1940 if (chars_after > 0) {
1941 traits_type::move(ptr, ptr + 1, chars_after);
1942 }
1943
1944 --size_;
1945 traits_type::assign(data_ + size_, 1, value_type());
1946#endif
1947 return position;
1948 }
1949
1956 NEFORCE_CONSTEXPR20 basic_string& erase(size_type position = 0, size_type n = npos) noexcept {
1957 if (position >= size()) {
1958 return *this;
1959 }
1960 n = _NEFORCE min(n, size() - position);
1961 basic_string::erase(begin() + position, n);
1962 return *this;
1963 }
1964
1971 NEFORCE_CONSTEXPR20 iterator erase(iterator first, const size_type n) noexcept {
1972 if (n == 0) {
1973 return first;
1974 }
1975 iterator last = first + _NEFORCE min(n, static_cast<size_type>(end() - first));
1976 return erase(first, last);
1977 }
1978
1985 NEFORCE_CONSTEXPR20 iterator erase(iterator first, iterator last) noexcept {
1986 if (first == last) {
1987 return first;
1988 }
1989
1990 const size_type erase_count = last - first;
1991
1992#ifdef NEFORCE_USING_SSO
1993 const size_type offset = first - begin();
1994 pointer p = data() + offset;
1995 const size_type chars_after = end() - last;
1996 if (chars_after > 0) {
1997 traits_type::move(p, p + erase_count, chars_after);
1998 }
1999 if (is_long()) {
2000 size_pair_.value = (size() - erase_count) | long_flag;
2001 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
2002 } else {
2003 size_pair_.value = size() - erase_count;
2004 traits_type::assign(storage_.short_ + size(), 1, value_type());
2005 }
2006#else
2007 const size_type chars_after = end() - last;
2008
2009 if (chars_after > 0) {
2010 pointer p_first = data_ + (first - begin());
2011 pointer p_last = data_ + (last - begin());
2012 traits_type::move(p_first, p_last, chars_after);
2013 }
2014
2015 size_ -= erase_count;
2016 traits_type::assign(data_ + size_, 1, value_type());
2017#endif
2018 return first;
2019 }
2020
2021
2027 NEFORCE_CONSTEXPR20 void resize(size_type n, value_type value) {
2028 if (n < size()) {
2029 basic_string::erase(begin() + n, end());
2030 } else {
2031 basic_string::append(n - size(), value);
2032 }
2033 }
2034
2039 NEFORCE_CONSTEXPR20 void resize(const size_type n) { basic_string::resize(n, value_type()); }
2040
2044 NEFORCE_CONSTEXPR20 void clear() noexcept {
2045#ifdef NEFORCE_USING_SSO
2046 if (is_long()) {
2047 destroy_long();
2048 traits_type::assign(storage_.short_, 1, value_type());
2049 size_pair_.value = 0;
2050 } else {
2051 traits_type::assign(storage_.short_, 1, value_type());
2052 size_pair_.value = 0;
2053 }
2054#else
2055 size_ = 0;
2056 traits_type::assign(data_ + size_, 1, value_type());
2057#endif
2058 }
2059
2063 NEFORCE_CONSTEXPR20 void shrink_to_fit() {
2064#ifdef NEFORCE_USING_SSO
2065 if (!is_long()) {
2066 return;
2067 }
2068 const size_type len = size();
2069 if (len < sso_capacity) {
2070 CharT tmp[sso_buffer_size];
2071 traits_type::copy(tmp, storage_.long_.ptr, len);
2072 traits_type::assign(tmp + len, 1, value_type());
2073 destroy_long();
2074 traits_type::copy(storage_.short_, tmp, len + 1);
2075 size_pair_.value = len;
2076 } else {
2077 if (storage_.long_.cap > len + 1) {
2078 pointer new_ptr = size_pair_.get_base().allocate(len + 1);
2079 traits_type::move(new_ptr, storage_.long_.ptr, len);
2080 traits_type::assign(new_ptr + len, 1, value_type());
2081 destroy_long();
2082 storage_.long_.ptr = new_ptr;
2083 storage_.long_.cap = len + 1;
2084 size_pair_.value = len | long_flag;
2085 }
2086 }
2087#else
2088 const size_type new_cap = size_ + 1;
2089 if (new_cap >= capacity_pair_.value) {
2090 return;
2091 }
2092
2093 basic_string temp;
2094 temp.reserve(new_cap);
2095 temp.append(*this);
2096 basic_string::swap(temp);
2097#endif
2098 }
2099
2105 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string repeat(size_type n) const noexcept {
2106 basic_string result;
2107 result.reserve(size() * n);
2108 while (n-- != 0U) {
2109 result += *this;
2110 }
2111 return _NEFORCE move(result);
2112 }
2113
2120 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string substr(const size_type off = 0,
2121 const size_type count = npos) const {
2122 NEFORCE_DEBUG_VERIFY(off <= size(), "basic_string index out of ranges.");
2123 const size_type clamp = _NEFORCE min(count, size() - off);
2124 return basic_string(data() + off, clamp);
2125 }
2126
2132 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string head(const size_type count = npos) const {
2133 return substr(0, count);
2134 }
2135
2141 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string tail(const size_type off = 0) const { return substr(off); }
2142
2147 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 view_type view() const noexcept { return view_type(data(), size()); }
2148
2155 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 view_type view(const size_type off, size_type count = npos) const noexcept {
2156 NEFORCE_DEBUG_VERIFY(off <= size(), "basic_string index out of ranges.");
2157 count = _NEFORCE min(count, size() - off);
2158 return view_type(data() + off, count);
2159 }
2160
2168 NEFORCE_CONSTEXPR20 size_type copy(pointer dest, const size_type count, size_type position = 0) const {
2169 NEFORCE_DEBUG_VERIFY(position <= size(), "basic_string copy position out of range");
2170 const size_type len = _NEFORCE min(count, size() - position);
2171 traits_type::copy(dest, data() + position, len);
2172 return len;
2173 }
2174
2180 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const basic_string& other) const noexcept {
2181 return compare(other.view());
2182 }
2183
2191 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n,
2192 const basic_string& other) const {
2193 return view(off, n).compare(other.view());
2194 }
2195
2205 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n, const basic_string& other,
2206 const size_type roff, const size_type count) const {
2207 return view(off, n).compare(other.view(roff, count));
2208 }
2209
2215 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const CharT* str) const noexcept {
2216 return compare(view_type(str));
2217 }
2218
2224 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const view_type& view) const noexcept {
2225 return char_traits_compare<traits_type>(data(), size(), view.data(), view.size());
2226 }
2227
2235 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n, const CharT* str) const {
2236 return view(off, n).compare(view_type(str));
2237 }
2238
2247 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n, const CharT* str,
2248 size_type count) const {
2249 return view(off, n).compare(view_type(str, count));
2250 }
2251
2257 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare_ignore_case(const view_type view) const noexcept {
2258 const size_type min_len = _NEFORCE min(size(), view.size());
2259 for (size_type i = 0; i < min_len; ++i) {
2260 const auto lc = _NEFORCE to_lowercase(data()[i]);
2261 const auto rc = _NEFORCE to_lowercase(view.data()[i]);
2262 if (lc != rc) {
2263 return (lc < rc) ? -1 : 1;
2264 }
2265 }
2266 if (size() < view.size()) {
2267 return -1;
2268 }
2269 if (size() > view.size()) {
2270 return 1;
2271 }
2272 return 0;
2273 }
2274
2280 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare_ignore_case(const_pointer str) const noexcept {
2281 return this->compare_ignore_case(view_type(str));
2282 }
2283
2289 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare_ignore_case(const basic_string& str) const noexcept {
2290 return this->compare_ignore_case(str.view());
2291 }
2292
2294 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n, const basic_string& other) {
2295 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2296 return replace_copy(begin() + position, n, other.data(), other.size());
2297 }
2298
2300 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const basic_string& other) {
2301 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2302 "basic_string replace iterator out of ranges.");
2303 return replace_copy(first, last - first, other.data(), other.size());
2304 }
2305
2307 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n, const_pointer str) {
2308 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2309 return replace_copy({data() + position, this}, n, str, traits_type::length(str));
2310 }
2311
2313 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const_pointer str) {
2314 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2315 "basic_string replace iterator out of ranges.");
2316 return replace_copy(first, last - first, str, traits_type::length(str));
2317 }
2318
2320 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n1, const_pointer str,
2321 const size_type n2) {
2322 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2323 return replace_copy({data() + position, this}, n1, str, n2);
2324 }
2325
2327 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const_pointer str, const size_type n) {
2328 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2329 "basic_string replace iterator out of ranges.");
2330 return replace_copy(first, last - first, str, n);
2331 }
2332
2334 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n1, const size_type n2,
2335 const value_type value) {
2336 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2337 return replace_fill({data() + position, this}, n1, n2, value);
2338 }
2339
2341 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const size_type n,
2342 const value_type value) {
2343 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2344 "basic_string replace iterator out of ranges.");
2345 return replace_fill(first, static_cast<size_type>(last - first), n, value);
2346 }
2347
2349 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position1, const size_type n1, const basic_string& str,
2350 const size_type position2, const size_type n2 = npos) {
2351 NEFORCE_DEBUG_VERIFY(position1 < size(), "basic_string index out of ranges.");
2352 NEFORCE_DEBUG_VERIFY(position2 < size(), "basic_string index out of ranges.");
2353 return replace_copy({data() + position1, this}, n1, str.data() + position2, n2);
2354 }
2355
2357 template <typename Iterator>
2358 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, Iterator first2, Iterator last2) {
2359 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2360 "basic_string replace iterator out of ranges.");
2361 return replace_copy(first, last, first2, last2);
2362 }
2363
2367 NEFORCE_CONSTEXPR20 void reverse() noexcept {
2368 if (size() < 2) {
2369 return;
2370 }
2371
2372 for (iterator first = begin(), last = end(); first < last;) {
2373 _NEFORCE iter_swap(first++, --last);
2374 }
2375 }
2376
2378 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const basic_string& other,
2379 const size_type n = 0) const noexcept {
2380 return (char_traits_find<Traits>) (data(), size(), n, other.data(), other.size());
2381 }
2382
2384 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const CharT value, const size_type n = 0) const noexcept {
2385 return (char_traits_find_char<Traits>) (data(), size(), n, value);
2386 }
2387
2389 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const CharT* str, const size_type off,
2390 const size_type count) const noexcept {
2391 return (char_traits_find<Traits>) (data(), size(), off, str, count);
2392 }
2393
2395 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const CharT* str, const size_type off = 0) const noexcept {
2396 return (char_traits_find<Traits>) (data(), size(), off, str, Traits::length(str));
2397 }
2398
2400 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const view_type& view, const size_type off,
2401 const size_type count) const noexcept {
2402 return (char_traits_find<Traits>) (data(), size(), off, view.data(), count);
2403 }
2404
2406 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const view_type& view,
2407 const size_type off = 0) const noexcept {
2408 return _NEFORCE char_traits_find<Traits>(data(), size(), off, view.data(), view.size());
2409 }
2410
2412 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const basic_string& other,
2413 const size_type off = npos) const noexcept {
2414 return (char_traits_rfind<Traits>) (data(), size(), off, other.data(), other.size());
2415 }
2416
2418 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const CharT value, const size_type n = npos) const noexcept {
2419 return (char_traits_rfind_char<Traits>) (data(), size(), n, value);
2420 }
2421
2423 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const CharT* str, const size_type off,
2424 const size_type n) const noexcept {
2425 return (char_traits_rfind<Traits>) (data(), size(), off, str, n);
2426 }
2427
2429 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const CharT* str, const size_type off = npos) const noexcept {
2430 return (char_traits_rfind<Traits>) (data(), size(), off, str, Traits::length(str));
2431 }
2432
2434 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const view_type& view, const size_type off,
2435 const size_type count) const noexcept {
2436 return (char_traits_rfind<Traits>) (data(), size(), off, view.data(), count);
2437 }
2438
2440 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const view_type& view,
2441 const size_type off = npos) const noexcept {
2442 return (char_traits_rfind<Traits>) (data(), size(), off, view.data(), view.size());
2443 }
2444
2446 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const basic_string& other,
2447 const size_type off = 0) const noexcept {
2448 return (char_traits_find_first_of<Traits>) (data(), size(), off, other.data(), other.size());
2449 }
2450
2452 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const CharT value,
2453 const size_type off = 0) const noexcept {
2454 return (char_traits_find_char<Traits>) (data(), size(), off, value);
2455 }
2456
2458 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const CharT* str, const size_type off,
2459 const size_type n) const noexcept {
2460 return (char_traits_find_first_of<Traits>) (data(), size(), off, str, n);
2461 }
2462
2464 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const CharT* str,
2465 const size_type off = 0) const noexcept {
2466 return (char_traits_find_first_of<Traits>) (data(), size(), off, str, Traits::length(str));
2467 }
2468
2470 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const view_type& view, const size_type off,
2471 const size_type n) const noexcept {
2472 return (char_traits_find_first_of<Traits>) (data(), size(), off, view.data(), n);
2473 }
2474
2476 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const view_type& view,
2477 const size_type off = 0) const noexcept {
2478 return (char_traits_find_first_of<Traits>) (data(), size(), off, view.data(), view.size());
2479 }
2480
2482 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const basic_string& other,
2483 const size_type off = npos) const noexcept {
2484 return (char_traits_find_last_of<Traits>) (data(), size(), off, other.data(), other.size());
2485 }
2486
2488 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const CharT value,
2489 const size_type off = npos) const noexcept {
2490 return (char_traits_rfind_char<Traits>) (data(), size(), off, value);
2491 }
2492
2494 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const CharT* str, const size_type off,
2495 const size_type n) const noexcept {
2496 return (char_traits_find_last_of<Traits>) (data(), size(), off, str, n);
2497 }
2498
2500 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const CharT* str,
2501 const size_type off = npos) const noexcept {
2502 return (char_traits_find_last_of<Traits>) (data(), size(), off, str, Traits::length(str));
2503 }
2504
2506 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const view_type& view, const size_type off,
2507 const size_type n) const noexcept {
2508 return (char_traits_find_last_of<Traits>) (data(), size(), off, view.data(), n);
2509 }
2510
2512 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const view_type& view,
2513 const size_type off = npos) const noexcept {
2514 return (char_traits_find_last_of<Traits>) (data(), size(), off, view.data(), view.size());
2515 }
2516
2518 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const basic_string& other,
2519 const size_type off = 0) const noexcept {
2520 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, other.data(), other.size());
2521 }
2522
2524 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const CharT value,
2525 const size_type off = 0) const noexcept {
2526 return (char_traits_find_not_char<Traits>) (data(), size(), off, value);
2527 }
2528
2530 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const CharT* str, const size_type off,
2531 const size_type n) const noexcept {
2532 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, str, n);
2533 }
2534
2536 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const CharT* str,
2537 const size_type off = 0) const noexcept {
2538 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, str, Traits::length(str));
2539 }
2540
2542 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const view_type& view, const size_type off,
2543 const size_type n) const noexcept {
2544 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, view.data(), n);
2545 }
2546
2548 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const view_type& view,
2549 const size_type off = 0) const noexcept {
2550 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, view.data(), view.size());
2551 }
2552
2554 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const basic_string& other,
2555 const size_type off = npos) const noexcept {
2556 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, other.data(), other.size());
2557 }
2558
2560 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const CharT value,
2561 const size_type off = npos) const noexcept {
2562 return (char_traits_rfind_not_char<Traits>) (data(), size(), off, value);
2563 }
2564
2566 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const CharT* str, const size_type off,
2567 const size_type n) const noexcept {
2568 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, str, n);
2569 }
2570
2572 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const CharT* str,
2573 const size_type off = npos) const noexcept {
2574 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, str, Traits::length(str));
2575 }
2576
2578 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const view_type& view, const size_type off,
2579 const size_type n) const noexcept {
2580 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, view.data(), n);
2581 }
2582
2584 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const view_type& view,
2585 const size_type off = npos) const noexcept {
2586 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, view.data(), view.size());
2587 }
2588
2590 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const charset& cs,
2591 const size_type off = 0) const noexcept {
2592 return (char_traits_find_first_of<Traits>) (data(), size(), off, cs);
2593 }
2594
2596 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const charset& cs,
2597 const size_type off = npos) const noexcept {
2598 return (char_traits_find_last_of<Traits>) (data(), size(), off, cs);
2599 }
2600
2602 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const charset& cs,
2603 const size_type off = 0) const noexcept {
2604 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, cs);
2605 }
2606
2608 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const charset& cs,
2609 const size_type off = npos) const noexcept {
2610 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, cs);
2611 }
2612
2619 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type count(value_type value,
2620 const size_type position = 0) const noexcept {
2621 size_type n = 0;
2622 for (size_type idx = position; idx < size(); ++idx) {
2623 if (*(data() + idx) == value) {
2624 ++n;
2625 }
2626 }
2627 return n;
2628 }
2629
2631 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(const basic_string& other) const noexcept {
2632 return other.size() <= size() && traits_type::compare(data(), other.data(), other.size()) == 0;
2633 }
2634
2636 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(view_type view) const noexcept {
2637 return view.size() <= size() && traits_type::compare(data(), view.data(), view.size()) == 0;
2638 }
2639
2641 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(const value_type value) const noexcept {
2642 return !empty() && traits_type::eq(front(), value);
2643 }
2644
2646 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(const_pointer str) const noexcept {
2647 return starts_with(view_type(str));
2648 }
2649
2651 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(const basic_string& other) const noexcept {
2652 const size_type other_size = other.size();
2653 return other_size <= size() &&
2654 traits_type::compare(data() + size() - other_size, other.data(), other_size) == 0;
2655 }
2656
2658 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(view_type view) const noexcept {
2659 const size_type view_size = view.size();
2660 return view_size <= size() && traits_type::compare(data() + size() - view_size, view.data(), view_size) == 0;
2661 }
2662
2664 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(value_type value) const noexcept {
2665 return !empty() && traits_type::eq(back(), value);
2666 }
2667
2669 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(const_pointer str) const noexcept {
2670 return ends_with(view_type(str));
2671 }
2672
2674 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(const basic_string& other) const noexcept {
2675 return find(other) != npos;
2676 }
2677
2679 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(view_type view) const noexcept { return find(view) != npos; }
2680
2682 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(value_type value) const noexcept { return find(value) != npos; }
2683
2685 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(const_pointer str) const noexcept { return find(str) != npos; }
2686
2691 NEFORCE_CONSTEXPR20 basic_string& trim_left() noexcept { return trim_left_if(charset::ascii_space()); }
2692
2697 NEFORCE_CONSTEXPR20 basic_string& trim_right() noexcept { return trim_right_if(charset::ascii_space()); }
2698
2703 NEFORCE_CONSTEXPR20 basic_string& trim() noexcept { return trim_left().trim_right(); }
2704
2711 template <typename Pred>
2712 NEFORCE_CONSTEXPR20 basic_string& trim_left_if(Pred pred) {
2713 if (empty()) {
2714 return *this;
2715 }
2716
2717 iterator it = begin();
2718 while (it != end() && pred(*it)) {
2719 ++it;
2720 }
2721 if (it != begin()) {
2722 basic_string::erase(begin(), it - begin());
2723 }
2724
2725 return *this;
2726 }
2727
2734 template <typename Pred>
2735 NEFORCE_CONSTEXPR20 basic_string& trim_right_if(Pred pred) {
2736 if (empty()) {
2737 return *this;
2738 }
2739
2740 reverse_iterator rit = rbegin();
2741 while (rit != rend() && pred(*rit)) {
2742 ++rit;
2743 }
2744 if (rit != rbegin()) {
2745 basic_string::erase(end() - (rit - rbegin()), end());
2746 }
2747
2748 return *this;
2749 }
2750
2756 NEFORCE_CONSTEXPR20 basic_string& trim_left_if(const charset& cs) noexcept {
2757 if (empty()) {
2758 return *this;
2759 }
2760
2761 iterator it = begin();
2762 while (it != end() && cs.contains(*it)) {
2763 ++it;
2764 }
2765 if (it != begin()) {
2766 basic_string::erase(begin(), it - begin());
2767 }
2768
2769 return *this;
2770 }
2771
2777 NEFORCE_CONSTEXPR20 basic_string& trim_right_if(const charset& cs) noexcept {
2778 if (empty()) {
2779 return *this;
2780 }
2781
2782 reverse_iterator rit = rbegin();
2783 while (rit != rend() && cs.contains(*rit)) {
2784 ++rit;
2785 }
2786 if (rit != rbegin()) {
2787 basic_string::erase(end() - (rit - rbegin()), end());
2788 }
2789
2790 return *this;
2791 }
2792
2798 NEFORCE_CONSTEXPR20 basic_string& trim_if(const charset& cs) noexcept { return trim_left_if(cs).trim_right_if(cs); }
2799
2806 template <typename Predicate>
2807 NEFORCE_CONSTEXPR20 basic_string& trim_if(Predicate pred) {
2808 return trim_left_if(pred).trim_right_if(pred);
2809 }
2810
2819 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 vector<basic_string> split(const view_type delimiters,
2820 const bool skip_empty = true) const {
2821 vector<basic_string> tokens;
2822
2823 if (empty()) {
2824 if (!skip_empty) {
2825 tokens.push_back(basic_string());
2826 }
2827 return tokens;
2828 }
2829
2830 if (delimiters.empty()) {
2831 tokens.push_back(*this);
2832 return tokens;
2833 }
2834
2835 size_t start = 0;
2836 size_t end = find_first_of(delimiters);
2837
2838 while (end != view_type::npos) {
2839 view_type token = view(start, end - start);
2840 if (!skip_empty || !token.empty()) {
2841 tokens.push_back(token);
2842 }
2843 start = end + 1;
2844 end = find_first_of(delimiters, start);
2845 }
2846
2847 const auto last_token = tail(start);
2848 if (!skip_empty || !last_token.empty()) {
2849 tokens.push_back(move(last_token));
2850 }
2851
2852 return tokens;
2853 }
2854
2861 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 vector<basic_string> split(const charset& delimiters,
2862 const bool skip_empty = true) const {
2863 vector<basic_string> tokens;
2864
2865 if (empty()) {
2866 if (!skip_empty) {
2867 tokens.push_back(basic_string());
2868 }
2869 return tokens;
2870 }
2871
2872 if (delimiters.empty()) {
2873 tokens.push_back(*this);
2874 return tokens;
2875 }
2876
2877 size_t start = 0;
2878 size_t end = find_first_of(delimiters);
2879
2880 while (end != npos) {
2881 view_type token = view(start, end - start);
2882 if (!skip_empty || !token.empty()) {
2883 tokens.push_back(token);
2884 }
2885 start = end + 1;
2886 end = find_first_of(delimiters, start);
2887 }
2888
2889 const auto last_token = tail(start);
2890 if (!skip_empty || !last_token.empty()) {
2891 tokens.push_back(move(last_token));
2892 }
2893
2894 return tokens;
2895 }
2896
2905 NEFORCE_NODISCARD static NEFORCE_CONSTEXPR20 basic_string join(const vector<basic_string>& vec,
2906 const view_type delimiter) {
2907 if (vec.empty()) {
2908 return {};
2909 }
2910
2911 size_t total_length = 0;
2912 for (const auto& s: vec) {
2913 total_length += s.length();
2914 }
2915 total_length += delimiter.length() * (vec.size() - 1);
2916
2917 basic_string result;
2918 result.reserve(total_length);
2919
2920 for (size_t i = 0; i < vec.size(); ++i) {
2921 if (i != 0) {
2922 result.append(delimiter);
2923 }
2924 result.append(vec[i]);
2925 }
2926
2927 return result;
2928 }
2929
2938 NEFORCE_NODISCARD static NEFORCE_CONSTEXPR20 basic_string join(const vector<view_type>& vec,
2939 const view_type delimiter) {
2940 if (vec.empty()) {
2941 return {};
2942 }
2943
2944 size_t total_length = 0;
2945 for (const auto& s: vec) {
2946 total_length += s.length();
2947 }
2948 total_length += delimiter.length() * (vec.size() - 1);
2949
2950 basic_string result;
2951 result.reserve(total_length);
2952
2953 for (size_t i = 0; i < vec.size(); ++i) {
2954 if (i != 0) {
2955 result.append(delimiter);
2956 }
2957 result.append(vec[i]);
2958 }
2959
2960 return result;
2961 }
2962
2968 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const basic_string& other) const noexcept {
2969 return equal_to(other.view());
2970 }
2971
2977 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const view_type view) const noexcept {
2978 return _NEFORCE char_traits_equal<Traits>(data(), size(), view.data(), view.size());
2979 }
2980
2986 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const CharT* str) const noexcept {
2987 return equal_to(view_type(str));
2988 }
2989
2993 NEFORCE_CONSTEXPR20 basic_string&
2994 lowercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase<CharT>))) {
2995 _NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase<CharT>);
2996 return *this;
2997 }
2998
3002 NEFORCE_CONSTEXPR20 basic_string&
3003 uppercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_uppercase<CharT>))) {
3004 _NEFORCE transform(begin(), end(), begin(), _NEFORCE to_uppercase<CharT>);
3005 return *this;
3006 }
3007
3011 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string lowercase() const {
3012 basic_string tmp(*this);
3013 _NEFORCE transform(tmp.begin(), tmp.end(), tmp.begin(), _NEFORCE to_lowercase<CharT>);
3014 return move(tmp);
3015 }
3016
3020 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string uppercase() const {
3021 basic_string tmp(*this);
3022 _NEFORCE transform(tmp.begin(), tmp.end(), tmp.begin(), _NEFORCE to_uppercase<CharT>);
3023 return move(tmp);
3024 }
3025
3030 NEFORCE_CONSTEXPR20 void swap(basic_string& other) noexcept {
3031 if (_NEFORCE addressof(other) == this) {
3032 return;
3033 }
3034#ifdef NEFORCE_USING_SSO
3035 _NEFORCE swap(storage_, other.storage_);
3036 _NEFORCE swap(size_pair_, other.size_pair_);
3037#else
3038 _NEFORCE swap(data_, other.data_);
3039 _NEFORCE swap(size_, other.size_);
3040 _NEFORCE swap(capacity_pair_, other.capacity_pair_);
3041#endif
3042 }
3043
3045 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool less_than(const basic_string& rhs) const noexcept {
3046 return compare(rhs) < 0;
3047 }
3048
3050 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_t to_hash() const noexcept {
3051 const size_t byte_len = length() * sizeof(CharT);
3052#ifdef NEFORCE_ARCH_BITS_64
3053 return static_cast<size_t>(_NEFORCE XXH64(data(), byte_len));
3054#else
3055 return static_cast<size_t>(_NEFORCE XXH32(data(), byte_len));
3056#endif
3057 }
3058};
3059
3060#ifdef NEFORCE_STANDARD_17
3061template <typename Iterator, typename Alloc = allocator<iter_value_t<Iterator>>>
3062basic_string(Iterator, Iterator, Alloc = Alloc())
3063 -> basic_string<iter_value_t<Iterator>, char_traits<iter_value_t<Iterator>>, Alloc>;
3064
3065template <typename CharT, typename Traits, typename Alloc = allocator<CharT>>
3066explicit basic_string(basic_string_view<CharT, Traits>, const Alloc& = Alloc()) -> basic_string<CharT, Traits, Alloc>;
3067
3068template <typename CharT, typename Traits, typename Alloc = allocator<CharT>>
3069basic_string(basic_string_view<CharT, Traits>, typename allocator_traits<Alloc>::size_type,
3070 typename allocator_traits<Alloc>::size_type, const Alloc& = Alloc()) -> basic_string<CharT, Traits, Alloc>;
3071#endif
3072
3073template <typename CharT, typename Traits, typename Alloc>
3074NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string<CharT, Traits, Alloc>& lhs,
3075 const basic_string<CharT, Traits, Alloc>& rhs) {
3076 basic_string<CharT, Traits, Alloc> tmp(lhs);
3077 tmp.append(rhs);
3078 return _NEFORCE move(tmp);
3079}
3080
3081template <typename CharT, typename Traits, typename Alloc>
3082NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const CharT* lhs,
3083 const basic_string<CharT, Traits, Alloc>& rhs) {
3084 basic_string<CharT, Traits, Alloc> tmp(lhs);
3085 tmp.append(rhs);
3086 return _NEFORCE move(tmp);
3087}
3088template <typename CharT, typename Traits, typename Alloc>
3089NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string<CharT, Traits, Alloc>& lhs,
3090 const CharT* rhs) {
3091 basic_string<CharT, Traits, Alloc> tmp(lhs);
3092 tmp.append(rhs);
3093 return _NEFORCE move(tmp);
3094}
3095
3096template <typename CharT, typename Traits, typename Alloc>
3097NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string_view<CharT, Traits>& lhs,
3098 const basic_string<CharT, Traits, Alloc>& rhs) {
3099 basic_string<CharT, Traits, Alloc> tmp(lhs);
3100 tmp.append(rhs);
3101 return _NEFORCE move(tmp);
3102}
3103template <typename CharT, typename Traits, typename Alloc>
3104NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string<CharT, Traits, Alloc>& lhs,
3105 const basic_string_view<CharT, Traits>& rhs) {
3106 basic_string<CharT, Traits, Alloc> tmp(lhs);
3107 tmp.append(rhs);
3108 return _NEFORCE move(tmp);
3109}
3110
3111template <typename CharT, typename Traits, typename Alloc>
3112NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(CharT lhs,
3113 const basic_string<CharT, Traits, Alloc>& rhs) {
3114 basic_string<CharT, Traits, Alloc> tmp(1, lhs);
3115 tmp.append(rhs);
3116 return _NEFORCE move(tmp);
3117}
3118template <typename CharT, typename Traits, typename Alloc>
3119NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string<CharT, Traits, Alloc>& lhs,
3120 CharT rhs) {
3121 basic_string<CharT, Traits, Alloc> tmp(lhs);
3122 tmp.append(1, rhs);
3123 return _NEFORCE move(tmp);
3124}
3125
3126template <typename CharT, typename Traits, typename Alloc>
3127NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(basic_string<CharT, Traits, Alloc>&& lhs,
3128 const basic_string<CharT, Traits, Alloc>& rhs) {
3129 return _NEFORCE move(lhs.append(rhs));
3130}
3131template <typename CharT, typename Traits, typename Alloc>
3132NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string<CharT, Traits, Alloc>& lhs,
3133 basic_string<CharT, Traits, Alloc>&& rhs) {
3134 basic_string<CharT, Traits, Alloc> tmp(lhs);
3135 tmp.append(_NEFORCE move(rhs));
3136 return _NEFORCE move(tmp);
3137}
3138
3139template <typename CharT, typename Traits, typename Alloc>
3140NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(basic_string<CharT, Traits, Alloc>&& lhs,
3141 basic_string<CharT, Traits, Alloc>&& rhs) {
3142 basic_string<CharT, Traits, Alloc> tmp(_NEFORCE move(lhs));
3143 if (_NEFORCE addressof(lhs) != _NEFORCE addressof(rhs)) {
3144 tmp.append(_NEFORCE move(rhs));
3145 } else {
3146 tmp.append(lhs);
3147 }
3148 return _NEFORCE move(tmp);
3149}
3150
3151template <typename CharT, typename Traits, typename Alloc>
3152NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const CharT* lhs,
3153 basic_string<CharT, Traits, Alloc>&& rhs) {
3154 basic_string<CharT, Traits, Alloc> tmp(lhs);
3155 tmp.append(_NEFORCE move(rhs));
3156 return _NEFORCE move(tmp);
3157}
3158template <typename CharT, typename Traits, typename Alloc>
3159NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(basic_string<CharT, Traits, Alloc>&& lhs,
3160 const CharT* rhs) {
3161 return _NEFORCE move(lhs.append(rhs));
3162}
3163
3164template <typename CharT, typename Traits, typename Alloc>
3165NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(CharT lhs, basic_string<CharT, Traits, Alloc>&& rhs) {
3166 basic_string<CharT, Traits, Alloc> tmp(1, lhs);
3167 tmp.append(_NEFORCE move(rhs));
3168 return _NEFORCE move(tmp);
3169}
3170template <typename CharT, typename Traits, typename Alloc>
3171NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(basic_string<CharT, Traits, Alloc>&& lhs, CharT rhs) {
3172 return _NEFORCE move(lhs.append(rhs));
3173}
3174
3175template <typename CharT, typename Traits, typename Alloc>
3176NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const CharT* const lhs,
3177 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3178 return rhs.equal_to(lhs);
3179}
3180template <typename CharT, typename Traits, typename Alloc>
3181NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const basic_string<CharT, Traits, Alloc>& lhs,
3182 const CharT* const rhs) noexcept {
3183 return lhs.equal_to(rhs);
3184}
3185template <typename CharT, typename Traits, typename Alloc>
3186NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const basic_string_view<CharT, Traits>& lhs,
3187 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3188 return rhs.equal_to(lhs);
3189}
3190template <typename CharT, typename Traits, typename Alloc>
3191NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const basic_string<CharT, Traits, Alloc>& lhs,
3192 const basic_string_view<CharT, Traits>& rhs) noexcept {
3193 return lhs.equal_to(rhs);
3194}
3195
3196template <typename CharT, typename Traits, typename Alloc>
3197NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const CharT* const lhs,
3198 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3199 return !(lhs == rhs);
3200}
3201template <typename CharT, typename Traits, typename Alloc>
3202NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const basic_string<CharT, Traits, Alloc>& lhs,
3203 const CharT* const rhs) noexcept {
3204 return !(lhs == rhs);
3205}
3206template <typename CharT, typename Traits, typename Alloc>
3207NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const basic_string_view<CharT, Traits>& lhs,
3208 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3209 return !(lhs == rhs);
3210}
3211template <typename CharT, typename Traits, typename Alloc>
3212NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const basic_string<CharT, Traits, Alloc>& lhs,
3213 const basic_string_view<CharT, Traits>& rhs) noexcept {
3214 return !(lhs == rhs);
3215}
3216
3217template <typename CharT, typename Traits, typename Alloc>
3218NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const CharT* const lhs,
3219 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3220 return 0 < rhs.compare(lhs);
3221}
3222template <typename CharT, typename Traits, typename Alloc>
3223NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const basic_string<CharT, Traits, Alloc>& lhs,
3224 const CharT* const rhs) noexcept {
3225 return lhs.compare(rhs) < 0;
3226}
3227template <typename CharT, typename Traits, typename Alloc>
3228NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const basic_string_view<CharT, Traits>& lhs,
3229 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3230 return 0 < rhs.compare(lhs);
3231}
3232template <typename CharT, typename Traits, typename Alloc>
3233NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const basic_string<CharT, Traits, Alloc>& lhs,
3234 const basic_string_view<CharT, Traits>& rhs) noexcept {
3235 return lhs.compare(rhs) < 0;
3236}
3237
3238template <typename CharT, typename Traits, typename Alloc>
3239NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const CharT* const lhs,
3240 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3241 return rhs < lhs;
3242}
3243template <typename CharT, typename Traits, typename Alloc>
3244NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const basic_string<CharT, Traits, Alloc>& lhs,
3245 const CharT* const rhs) noexcept {
3246 return rhs < lhs;
3247}
3248template <typename CharT, typename Traits, typename Alloc>
3249NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const basic_string_view<CharT, Traits>& lhs,
3250 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3251 return rhs < lhs;
3252}
3253template <typename CharT, typename Traits, typename Alloc>
3254NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const basic_string<CharT, Traits, Alloc>& lhs,
3255 const basic_string_view<CharT, Traits>& rhs) noexcept {
3256 return rhs < lhs;
3257}
3258
3259template <typename CharT, typename Traits, typename Alloc>
3260NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const CharT* const lhs,
3261 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3262 return !(lhs > rhs);
3263}
3264template <typename CharT, typename Traits, typename Alloc>
3265NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const basic_string<CharT, Traits, Alloc>& lhs,
3266 const CharT* const rhs) noexcept {
3267 return !(lhs > rhs);
3268}
3269template <typename CharT, typename Traits, typename Alloc>
3270NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const basic_string_view<CharT, Traits>& lhs,
3271 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3272 return !(lhs > rhs);
3273}
3274template <typename CharT, typename Traits, typename Alloc>
3275NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const basic_string<CharT, Traits, Alloc>& lhs,
3276 const basic_string_view<CharT, Traits>& rhs) noexcept {
3277 return !(lhs > rhs);
3278}
3279
3280template <typename CharT, typename Traits, typename Alloc>
3281NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const CharT* const lhs,
3282 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3283 return !(rhs < lhs);
3284}
3285template <typename CharT, typename Traits, typename Alloc>
3286NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const basic_string<CharT, Traits, Alloc>& lhs,
3287 const CharT* const rhs) noexcept {
3288 return !(rhs < lhs);
3289}
3290template <typename CharT, typename Traits, typename Alloc>
3291NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const basic_string_view<CharT, Traits>& lhs,
3292 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3293 return !(rhs < lhs);
3294}
3295template <typename CharT, typename Traits, typename Alloc>
3296NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const basic_string<CharT, Traits, Alloc>& lhs,
3297 const basic_string_view<CharT, Traits>& rhs) noexcept {
3298 return !(rhs < lhs);
3299}
3300
3301#ifndef NEFORCE_STANDARD_17
3302# ifdef NEFORCE_USING_SSO
3303template <typename CharT, typename Traits, typename Alloc>
3304constexpr size_t basic_string<CharT, Traits, Alloc>::sso_buffer_bytes;
3305template <typename CharT, typename Traits, typename Alloc>
3306constexpr size_t basic_string<CharT, Traits, Alloc>::sso_buffer_size;
3307template <typename CharT, typename Traits, typename Alloc>
3308constexpr size_t basic_string<CharT, Traits, Alloc>::sso_capacity;
3309template <typename CharT, typename Traits, typename Alloc>
3310constexpr size_t basic_string<CharT, Traits, Alloc>::long_flag;
3311# endif
3312template <typename CharT, typename Traits, typename Alloc>
3313constexpr size_t basic_string<CharT, Traits, Alloc>::npos;
3314#endif
3315
3316
3317#ifndef NEFORCE_COMPILER_CLANG_CL
3318extern template class basic_string<char>;
3319extern template class basic_string<wchar_t>;
3320# ifdef NEFORCE_STANDARD_20
3321extern template class basic_string<char8_t>;
3322# endif
3323extern template class basic_string<char16_t>;
3324extern template class basic_string<char32_t>;
3325#endif
3326 // String
3328
3329NEFORCE_END_NAMESPACE__
3330#endif // NEFORCE_CORE_STRING_BASIC_STRING_HPP__
分配器特性
字符集工具类
基本字符串视图模板
constexpr size_type length() const noexcept
获取字符串长度
constexpr bool empty() const noexcept
检查是否为空
基础字符串模板
constexpr view_type view() const noexcept
constexpr basic_string & assign(const basic_string &other)
赋值另一个字符串
constexpr basic_string & replace(iterator first, iterator last, const basic_string &other)
替换迭代器范围为另一个字符串
constexpr basic_string(view_type view, const size_type n)
从字符串视图构造(指定长度)
constexpr bool ends_with(const_pointer str) const noexcept
检查是否以C风格字符串结尾
constexpr basic_string(const basic_string &other, size_type position, size_type n)
从子串构造(指定长度)
constexpr size_type length() const noexcept
获取字符串长度
basic_string_iterator< false, basic_string > iterator
迭代器类型
constexpr basic_string repeat(size_type n) const noexcept
重复当前字符串n次
constexpr basic_string & append(view_type view, size_type n)
追加字符串视图的指定长度
constexpr size_type rfind(const CharT *str, const size_type off, const size_type n) const noexcept
从后向前查找指定长度的子串
constexpr basic_string & assign(const view_type &view)
赋值字符串视图
constexpr iterator end() noexcept
constexpr size_type rfind(const CharT value, const size_type n=npos) const noexcept
从后向前查找字符
constexpr basic_string & operator=(std::initializer_list< value_type > ilist)
初始化列表赋值运算符
constexpr void swap(basic_string &other) noexcept
交换两个字符串
constexpr size_t to_hash() const noexcept
计算哈希值
constexpr bool starts_with(view_type view) const noexcept
检查是否以字符串视图开头
constexpr size_type find_first_not_of(const charset &cs, const size_type off=0) const noexcept
查找第一个不在 charset 中的字符
constexpr basic_string & replace(const size_type position, const size_type n1, const_pointer str, const size_type n2)
替换子串为指定长度的字符数组
ptrdiff_t difference_type
差值类型
constexpr size_type max_size() const noexcept
获取最大可能大小
constexpr const_reference front() const noexcept
常量访问第一个字符
constexpr basic_string & append(const basic_string &other, size_type position)
追加另一个字符串的子串
constexpr basic_string & append(const basic_string &other, size_type position, size_type n)
追加另一个字符串的子串
constexpr reverse_iterator rend() noexcept
获取反向结束迭代器
constexpr basic_string & operator=(const basic_string &other)
拷贝赋值运算符
constexpr basic_string & replace(const size_type position, const size_type n, const basic_string &other)
替换子串为另一个字符串
constexpr size_type rfind(const CharT *str, const size_type off=npos) const noexcept
从后向前查找C风格字符串
constexpr basic_string(const basic_string &other, size_type position)
从子串构造
constexpr basic_string & trim_right() noexcept
去除右侧空白字符
constexpr void resize(size_type n, value_type value)
调整大小
constexpr pointer data() noexcept
获取数据指针
constexpr void pop_back() noexcept
删除末尾字符
constexpr basic_string lowercase() const
转换为小写
constexpr basic_string(const basic_string &other)
拷贝构造函数
constexpr size_type rfind(const view_type &view, const size_type off=npos) const noexcept
从后向前查找字符串视图
constexpr int compare(const basic_string &other) const noexcept
比较另一个字符串
constexpr basic_string & trim() noexcept
去除两侧空白字符
constexpr int compare_ignore_case(const_pointer str) const noexcept
忽略大小写比较另一个字符串
constexpr basic_string(basic_string &&other) noexcept
移动构造函数
constexpr bool ends_with(view_type view) const noexcept
检查是否以字符串视图结尾
constexpr basic_string & replace(iterator first, iterator last, const_pointer str)
替换迭代器范围为C风格字符串
constexpr const_reference operator[](const size_type n) const noexcept
常量下标访问操作符
constexpr size_type find_first_of(const charset &cs, const size_type off=0) const noexcept
查找第一个出现在 charset 中的字符
constexpr size_type find(const CharT *str, const size_type off=0) const noexcept
查找C风格字符串
constexpr iterator insert(iterator position, Iterator first, Iterator last)
插入迭代器范围
constexpr size_type find(const CharT value, const size_type n=0) const noexcept
查找字符
constexpr bool contains(value_type value) const noexcept
检查是否包含指定字符
constexpr int compare(const size_type off, const size_type n, const CharT *str, size_type count) const
比较子串与指定长度的字符数组
constexpr basic_string & uppercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_uppercase< CharT >)))
转换为大写
constexpr bool equal_to(const CharT *str) const noexcept
与C风格字符串相等比较
constexpr int compare(const view_type &view) const noexcept
比较字符串视图
constexpr size_type find(const basic_string &other, const size_type n=0) const noexcept
查找子串
constexpr basic_string & assign(std::initializer_list< value_type > ilist)
赋值初始化列表
constexpr basic_string & trim_if(const charset &cs) noexcept
根据 charset 去除两侧字符
constexpr void push_back(value_type value)
在末尾插入字符
constexpr basic_string & assign(const_pointer str, const size_type n)
赋值字符数组的指定长度
constexpr basic_string & append(Iterator first, Iterator last)
追加迭代器范围
constexpr basic_string substr(const size_type off=0, const size_type count=npos) const
获取子串
constexpr size_type find_last_not_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找最后一个不在指定字符数组中的字符
constexpr basic_string & replace(const size_type position, const size_type n, const_pointer str)
替换子串为C风格字符串
constexpr const_reference at(const size_type n) const noexcept
带边界检查的常量访问
constexpr size_type find_last_not_of(const CharT value, const size_type off=npos) const noexcept
查找最后一个不等于指定字符的位置
constexpr iterator begin() noexcept
constexpr bool ends_with(const basic_string &other) const noexcept
检查是否以另一个字符串结尾
constexpr const_reverse_iterator rend() const noexcept
获取常量反向结束迭代器
constexpr basic_string & operator+=(view_type view)
追加字符串视图
constexpr basic_string(size_type n, int64_t value)
构造函数,指定大小和64位整数值
constexpr const_reverse_iterator rbegin() const noexcept
获取常量反向起始迭代器
constexpr size_type find_last_of(const charset &cs, const size_type off=npos) const noexcept
查找最后一个出现在 charset 中的字符
constexpr void shrink_to_fit()
收缩容量以适应当前大小
constexpr basic_string & replace(iterator first, iterator last, const_pointer str, const size_type n)
替换迭代器范围为指定长度的字符数组
const CharT * const_pointer
常量指针类型
constexpr const_reference back() const noexcept
常量访问最后一个字符
constexpr basic_string(view_type view)
从字符串视图构造
constexpr basic_string & operator+=(const basic_string &other)
追加另一个字符串
constexpr basic_string & assign(const_pointer str)
赋值C风格字符串
constexpr int compare_ignore_case(const view_type view) const noexcept
忽略大小写三路比较
constexpr size_type copy(pointer dest, const size_type count, size_type position=0) const
复制字符到目标缓冲区
constexpr size_type find_first_not_of(const CharT value, const size_type off=0) const noexcept
查找第一个不等于指定字符的位置
constexpr size_type find_last_of(const basic_string &other, const size_type off=npos) const noexcept
查找最后一个出现在字符集合中的字符
constexpr bool less_than(const basic_string &rhs) const noexcept
小于比较操作符
constexpr basic_string & trim_left() noexcept
去除左侧空白字符
constexpr iterator insert(iterator position, value_type value)
constexpr basic_string & trim_left_if(Pred pred)
constexpr bool starts_with(const basic_string &other) const noexcept
检查是否以另一个字符串开头
constexpr size_type find_last_not_of(const CharT *str, const size_type off=npos) const noexcept
查找最后一个不在C风格字符串中的字符
constexpr basic_string & trim_right_if(Pred pred)
constexpr basic_string & trim_left_if(const charset &cs) noexcept
根据 charset 去除左侧字符
constexpr size_type rfind(const view_type &view, const size_type off, const size_type count) const noexcept
从后向前查找指定长度的字符串视图
constexpr bool empty() const noexcept
检查是否为空
constexpr basic_string(size_type n, int32_t value)
构造函数,指定大小和32位整数值
constexpr basic_string & append(value_type value)
追加单个字符
constexpr bool contains(view_type view) const noexcept
检查是否包含字符串视图
constexpr reverse_iterator rbegin() noexcept
获取反向起始迭代器
constexpr size_type find_first_not_of(const CharT *str, const size_type off=0) const noexcept
查找第一个不在C风格字符串中的字符
_NEFORCE reverse_iterator< iterator > reverse_iterator
反向迭代器类型
constexpr const_reverse_iterator crend() const noexcept
_NEFORCE reverse_iterator< const_iterator > const_reverse_iterator
常量反向迭代器类型
constexpr basic_string & append(size_type n, value_type value)
constexpr iterator erase(iterator position) noexcept
删除指定位置的字符
constexpr size_type find_last_not_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找最后一个不在字符串视图中的字符
size_t size_type
大小类型
constexpr size_type find_last_of(const CharT value, const size_type off=npos) const noexcept
查找最后一个等于指定字符的位置
constexpr int compare(const size_type off, const size_type n, const CharT *str) const
比较子串与C风格字符串
constexpr size_type find_first_not_of(const basic_string &other, const size_type off=0) const noexcept
查找第一个不在字符集合中的字符
constexpr const_iterator cbegin() const noexcept
basic_string_view< CharT, Traits > view_type
字符串视图类型
constexpr basic_string(Iterator first, Iterator last)
从迭代器范围构造
constexpr basic_string & operator+=(std::initializer_list< value_type > ilist)
追加初始化列表
constexpr size_type find_last_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找最后一个出现在字符串视图中的字符
constexpr basic_string(const_pointer str, const size_type n)
从字符数组构造(指定长度)
constexpr basic_string & assign(const size_type n, value_type value)
赋值多个相同字符
constexpr vector< basic_string > split(const charset &delimiters, const bool skip_empty=true) const
使用 charset 分割字符串
constexpr reference back() noexcept
访问最后一个字符
constexpr size_type find_first_of(const view_type &view, const size_type off=0) const noexcept
查找第一个出现在字符串视图中的字符
constexpr int compare(const size_type off, const size_type n, const basic_string &other, const size_type roff, const size_type count) const
比较子串与另一个字符串的子串
constexpr size_type find_last_not_of(const charset &cs, const size_type off=npos) const noexcept
查找最后一个不在 charset 中的字符
constexpr bool equal_to(const view_type view) const noexcept
与字符串视图相等比较
constexpr basic_string & assign(basic_string &&other)
赋值移动字符串
constexpr size_type find_first_not_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找第一个不在字符串视图中的字符
constexpr basic_string & operator=(view_type view)
字符串视图赋值运算符
constexpr bool contains(const basic_string &other) const noexcept
检查是否包含另一个字符串
constexpr basic_string & operator+=(const value_type value)
追加单个字符
constexpr size_type find_first_not_of(const view_type &view, const size_type off=0) const noexcept
查找第一个不在字符串视图中的字符
Alloc allocator_type
分配器类型
constexpr size_type capacity() const noexcept
获取容量
constexpr basic_string & operator+=(const_pointer str)
追加C风格字符串
constexpr basic_string & erase(size_type position=0, size_type n=npos) noexcept
删除指定范围内的字符
constexpr const_iterator end() const noexcept
获取常量结束迭代器
constexpr basic_string(size_type n, value_type value)
构造函数,指定大小和填充字符
CharT * pointer
指针类型
constexpr const_reverse_iterator crbegin() const noexcept
constexpr basic_string & append(const basic_string &other)
追加另一个字符串
constexpr basic_string & trim_if(Predicate pred)
根据谓词去除两侧字符
constexpr size_type size() const noexcept
获取字符数
constexpr size_type find_first_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找第一个出现在字符串视图中的字符
constexpr basic_string()
默认构造函数
constexpr size_type find_last_of(const view_type &view, const size_type off=npos) const noexcept
查找最后一个出现在字符串视图中的字符
constexpr basic_string head(const size_type count=npos) const
获取头部子串
constexpr size_type count(value_type value, const size_type position=0) const noexcept
constexpr basic_string & lowercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase< CharT >)))
转换为小写
constexpr basic_string(std::initializer_list< value_type > ilist)
从初始化列表构造
constexpr size_type find(const view_type &view, const size_type off, const size_type count) const noexcept
查找指定长度的字符串视图
constexpr iterator erase(iterator first, iterator last) noexcept
删除迭代器范围
const CharT & const_reference
常量引用类型
basic_string_iterator< true, basic_string > const_iterator
常量迭代器类型
constexpr size_type find_first_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找第一个出现在指定字符数组中的字符
constexpr basic_string & append(basic_string &&other)
追加移动字符串
constexpr size_type find_first_not_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找第一个不在指定字符数组中的字符
constexpr basic_string & append(view_type view)
追加字符串视图
constexpr iterator erase(iterator first, const size_type n) noexcept
删除指定数量的字符
constexpr basic_string & replace(const size_type position1, const size_type n1, const basic_string &str, const size_type position2, const size_type n2=npos)
替换子串为另一个字符串的子串
constexpr view_type view(const size_type off, size_type count=npos) const noexcept
获取子串视图
constexpr bool starts_with(const_pointer str) const noexcept
检查是否以C风格字符串开头
constexpr size_type find_last_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找最后一个出现在指定字符数组中的字符
constexpr bool starts_with(const value_type value) const noexcept
检查是否以指定字符开头
static constexpr size_type npos
constexpr void resize(const size_type n)
调整大小(默认填充0)
constexpr size_type find_first_of(const CharT value, const size_type off=0) const noexcept
查找第一个等于指定字符的位置
Traits traits_type
字符特征类型
constexpr size_type find_last_of(const CharT *str, const size_type off=npos) const noexcept
查找最后一个出现在C风格字符串中的字符
static constexpr basic_string join(const vector< view_type > &vec, const view_type delimiter)
连接字符串视图
constexpr const_iterator begin() const noexcept
获取常量起始迭代器
constexpr reference at(const size_type n) noexcept
带边界检查的访问
constexpr basic_string & replace(const size_type position, const size_type n1, const size_type n2, const value_type value)
替换子串为多个相同字符
constexpr basic_string & append(const_pointer str)
追加C风格字符串
constexpr void reverse() noexcept
反转字符串
constexpr basic_string & assign(Iterator first, Iterator last)
赋值迭代器范围
constexpr vector< basic_string > split(const view_type delimiters, const bool skip_empty=true) const
分割字符串
constexpr basic_string(size_type n)
构造函数,指定大小
constexpr size_type find_first_of(const CharT *str, const size_type off=0) const noexcept
查找第一个出现在C风格字符串中的字符
constexpr basic_string & operator=(basic_string &&other) noexcept
移动赋值运算符
constexpr int compare_ignore_case(const basic_string &str) const noexcept
忽略大小写与C风格字符串三路比较
constexpr size_type rfind(const basic_string &other, const size_type off=npos) const noexcept
从后向前查找子串
constexpr bool contains(const_pointer str) const noexcept
检查是否包含C风格字符串
constexpr basic_string & append(basic_string &&other, size_type position, size_type n)
追加移动字符串的子串
constexpr const_pointer data() const noexcept
获取常量数据指针
constexpr basic_string & replace(iterator first, iterator last, const size_type n, const value_type value)
替换迭代器范围为多个相同字符
constexpr size_type find_last_not_of(const basic_string &other, const size_type off=npos) const noexcept
查找最后一个不在字符集合中的字符
constexpr bool equal_to(const basic_string &other) const noexcept
相等比较
constexpr reference operator[](const size_type n) noexcept
下标访问操作符
constexpr basic_string & replace(iterator first, iterator last, Iterator first2, Iterator last2)
替换迭代器范围为另一个迭代器范围
constexpr basic_string & operator=(const_pointer str)
C风格字符串赋值运算符
constexpr basic_string & operator+=(basic_string &&other)
追加移动字符串
constexpr size_type find(const view_type &view, const size_type off=0) const noexcept
查找字符串视图
constexpr basic_string & append(std::initializer_list< value_type > ilist)
追加初始化列表
constexpr basic_string(const_pointer str)
从C风格字符串构造
constexpr size_type find_first_of(const basic_string &other, const size_type off=0) const noexcept
查找第一个出现在字符集合中的字符
constexpr size_type find(const CharT *str, const size_type off, const size_type count) const noexcept
查找指定长度的子串
constexpr basic_string & trim_right_if(const charset &cs) noexcept
根据 charset 去除右侧字符
constexpr ~basic_string()
析构函数
constexpr void clear() noexcept
constexpr bool ends_with(value_type value) const noexcept
检查是否以指定字符结尾
constexpr size_type find_last_not_of(const view_type &view, const size_type off=npos) const noexcept
查找最后一个不在字符串视图中的字符
static constexpr basic_string join(const vector< basic_string > &vec, const view_type delimiter)
连接字符串
constexpr void reserve(const size_type n)
预留容量
constexpr basic_string & append(basic_string &&other, size_type position)
追加移动字符串的子串
constexpr int compare(const CharT *str) const noexcept
比较C风格字符串
CharT & reference
引用类型
constexpr int compare(const size_type off, const size_type n, const basic_string &other) const
比较子串与另一个字符串
constexpr basic_string tail(const size_type off=0) const
获取尾部子串
constexpr basic_string uppercase() const
转换为大写
constexpr const_iterator cend() const noexcept
constexpr reference front() noexcept
访问第一个字符
constexpr basic_string & append(const_pointer str, size_type n)
追加字符数组的指定长度
constexpr basic_string & insert(size_type position, size_type n, value_type value)
在指定位置插入多个相同字符
static constexpr charset ascii_space() noexcept
ASCII 空白字符集
constexpr bool empty() const noexcept
检查字符集是否为空
constexpr bool empty() const noexcept
检查是否为空
constexpr size_type size() const noexcept
获取当前元素数量
constexpr void push_back(const T &value)
在末尾拷贝插入元素
压缩对实现
constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr bool is_standard_layout_v
is_standard_layout的便捷变量模板
constexpr bool is_array_v
is_array的便捷变量模板
constexpr CharT to_lowercase(const CharT c) noexcept
将字符转换为小写
constexpr CharT to_uppercase(const CharT c) noexcept
将字符转换为大写
constexpr size_t char_traits_rfind(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
从后向前查找子序列
constexpr size_t char_traits_find_not_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
查找第一个不等于指定字符的位置
constexpr int char_traits_compare(const char_traits_ptr_t< Traits > lhs, const size_t lh_size, const char_traits_ptr_t< Traits > rhs, const size_t rh_size) noexcept
比较两个字符序列(三路比较)
constexpr size_t char_traits_find_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
在字符序列中查找单个字符
constexpr size_t char_traits_find_first_not_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找第一个不在给定集合中的字符(char_traits特化版本)
constexpr size_t char_traits_find(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
在字符序列中查找子序列
constexpr size_t char_traits_find_last_not_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找最后一个不在给定集合中的字符(char_traits特化版本)
constexpr bool char_traits_equal(const char_traits_ptr_t< Traits > lhs, const size_t lh_size, const char_traits_ptr_t< Traits > rhs, const size_t rh_size) noexcept
比较两个字符序列是否相等
constexpr size_t char_traits_find_first_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找第一个出现在给定集合中的字符(char_traits特化版本)
constexpr size_t char_traits_find_last_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找最后一个出现在给定集合中的字符(char_traits特化版本)
constexpr size_t char_traits_rfind_not_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
查找最后一个不等于指定字符的位置
constexpr size_t char_traits_rfind_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
从后向前查找单个字符
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
constexpr T clamp(const T &value, const T &lower, const T &upper, Compare comp) noexcept(noexcept(comp(value, lower)))
将值限制在指定范围内
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
long int64_t
64位有符号整数类型
int int32_t
32位有符号整数类型
bool operator!=(const function< Res(Args...)> &f, nullptr_t np) noexcept
不等于空指针比较
bool operator==(const function< Res(Args...)> &f, nullptr_t np) noexcept
等于空指针比较
constexpr uint32_t XXH32(const void *input, size_t len, uint32_t seed=0) noexcept
XXH32 哈希算法
constexpr uint64_t XXH64(const void *input, size_t len, uint64_t seed=0) noexcept
XXH64 哈希算法
constexpr void destroy(T *pointer) noexcept(is_nothrow_destructible_v< T >)
销毁单个对象
constexpr iter_difference_t< Iterator > distance(Iterator first, Iterator last)
计算两个迭代器之间的距离
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr normal_iterator< Iterator > operator+(iter_difference_t< normal_iterator< Iterator > > n, const normal_iterator< Iterator > &iter) noexcept
加法运算符
uint64_t size_t
无符号大小类型
int64_t ptrdiff_t
指针差类型
constexpr void iter_swap(Iterator1 a, Iterator2 b) noexcept(noexcept(_NEFORCE swap(*a, *b)))
交换迭代器指向的元素
constexpr Iterator2 replace_copy(Iterator1 first, Iterator1 last, Iterator2 result, const T &old_value, const T &new_value)
替换并复制元素
constexpr Iterator2 transform(Iterator1 first, Iterator1 last, Iterator2 result, UnaryOperation op) noexcept(noexcept(++first) &&noexcept(++result) &&noexcept(*result=op(*first)))
对范围元素应用一元变换
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
constexpr bool is_allocator_v
is_allocator的便捷变量模板
constexpr decltype(auto) size(const Container &cont) noexcept(noexcept(cont.size()))
获取容器的大小
constexpr decltype(auto) end(Container &cont) noexcept(noexcept(cont.end()))
获取容器的结束迭代器
constexpr decltype(auto) data(Container &cont) noexcept(noexcept(cont.data()))
获取容器的底层数据指针
constexpr decltype(auto) begin(Container &cont) noexcept(noexcept(cont.begin()))
获取容器的起始迭代器
constexpr bool is_trivial_v
is_trivial的便捷变量模板
constexpr bool is_same_v
is_same的便捷变量模板
typename conditional< Test, T1, T2 >::type conditional_t
conditional的便捷别名
constexpr Iterator2 uninitialized_copy_n(Iterator1 first, size_t count, Iterator2 result)
复制指定数量的元素到未初始化内存
constexpr Iterator2 uninitialized_copy(Iterator1 first, Iterator1 last, Iterator2 result)
复制元素到未初始化内存
移位和修改算法
字符串视图类型别名和实用函数
static constexpr char_type * assign(char_type *const str, const size_t count, const char_type chr) noexcept
将字符序列中的每个字符设置为指定值
static constexpr int compare(const char_type *lhs, const char_type *rhs, size_t count) noexcept
比较两个字符序列
static constexpr char_type * move(char_type *dest, const char_type *srcs, const size_t count) noexcept
移动字符序列
static constexpr size_t length(const char_type *str) noexcept
计算字符串长度
static constexpr char_type * copy(char_type *dest, const char_type *srcs, const size_t count) noexcept
复制字符序列
static constexpr bool eq(const char_type lhs, const char_type rhs) noexcept
相等比较
typename container_type::difference_type difference_type
差值类型
typename container_type::value_type value_type
值类型
constexpr difference_type distance_to(const basic_string_iterator &other) const noexcept
计算距离操作
constexpr bool less_than(const basic_string_iterator &rhs) const noexcept
小于比较
constexpr pointer base() const noexcept
获取底层指针
constexpr void increment() noexcept
递增操作
constexpr void decrement() noexcept
递减操作
constexpr reference operator[](difference_type n) const noexcept
下标访问操作符
constexpr void advance(difference_type off) noexcept
前进操作
conditional_t< IsConst, typename container_type::const_pointer, typename container_type::pointer > pointer
指针类型
constexpr bool equal_to(const basic_string_iterator &rhs) const noexcept
相等比较
contiguous_iterator_tag iterator_category
迭代器类别
typename container_type::size_type size_type
大小类型
conditional_t< IsConst, typename container_type::const_reference, typename container_type::reference > reference
引用类型
constexpr reference dereference() const noexcept
解引用操作
constexpr const container_type * container() const noexcept
获取关联容器
压缩对主模板,使用EBCO优化
constexpr compressed_pair & get_base() &noexcept
获取基类引用
通用接口,同时具备可比较和可哈希功能
迭代器接口模板
动态大小数组容器