NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
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 = cend() - 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).second + 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
1048 NEFORCE_CONSTEXPR20 basic_string(const_pointer str) { construct_from_ptr(str, 0, traits_type::length(str)); }
1049
1055 NEFORCE_CONSTEXPR20 basic_string(const_pointer str, const size_type n) { construct_from_ptr(str, 0, n); }
1056
1062 NEFORCE_CONSTEXPR20 basic_string& operator=(const_pointer str) {
1063 const size_type len = traits_type::length(str);
1064#ifdef NEFORCE_USING_SSO
1065 if (len < sso_capacity) {
1066 if (is_long()) {
1067 destroy_long();
1068 }
1069 traits_type::copy(storage_.short_, str, len);
1070 traits_type::assign(storage_.short_ + len, 1, value_type());
1071 size_pair_.value = len;
1072 } else {
1073 if (is_long() && storage_.long_.cap >= len + 1) {
1074 traits_type::copy(storage_.long_.ptr, str, len);
1075 traits_type::assign(storage_.long_.ptr + len, 1, value_type());
1076 size_pair_.value = len | long_flag;
1077 return *this;
1078 }
1079
1080 if (is_long()) {
1081 destroy_long();
1082 }
1083 const size_type new_cap = len + 1;
1084 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
1085 traits_type::copy(new_ptr, str, len);
1086 traits_type::assign(new_ptr + len, 1, value_type());
1087
1088 storage_.long_.ptr = new_ptr;
1089 storage_.long_.cap = new_cap;
1090 size_pair_.value = len | long_flag;
1091 }
1092#else
1093 if (capacity_pair_.value < len) {
1094 pointer new_buffer = capacity_pair_.get_base().allocate(len + 1);
1095 capacity_pair_.get_base().deallocate(data_);
1096 data_ = new_buffer;
1097 capacity_pair_.value = len + 1;
1098 }
1099 traits_type::copy(data_, str, len);
1100 size_ = len;
1101 traits_type::assign(data_ + size_, 1, value_type());
1102#endif
1103 return *this;
1104 }
1105
1112 template <typename Iterator, enable_if_t<!is_convertible_v<Iterator, value_type>, int> = 0>
1113 NEFORCE_CONSTEXPR20 basic_string(Iterator first, Iterator last) {
1114 construct_from_iter(first, last);
1115 }
1116
1121 NEFORCE_CONSTEXPR20 basic_string(std::initializer_list<value_type> ilist) :
1122 basic_string(ilist.begin(), ilist.end()) {}
1123
1129 NEFORCE_CONSTEXPR20 basic_string& operator=(std::initializer_list<value_type> ilist) {
1130 clear();
1131 insert(begin(), ilist.begin(), ilist.end());
1132 return *this;
1133 }
1134
1138 NEFORCE_CONSTEXPR20 ~basic_string() { destroy_buffer(); }
1139
1144 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 iterator begin() noexcept { return {data(), this}; }
1145
1150 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 iterator end() noexcept { return {data() + size(), this}; }
1151
1156 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator begin() const noexcept { return cbegin(); }
1157
1162 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator end() const noexcept { return cend(); }
1163
1168 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator cbegin() const noexcept { return {data(), this}; }
1169
1174 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_iterator cend() const noexcept { return {data() + size(), this}; }
1175
1180 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
1181
1186 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
1187
1192 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator rbegin() const noexcept { return crbegin(); }
1193
1198 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator rend() const noexcept { return crend(); }
1199
1204 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator crbegin() const noexcept {
1205 return const_reverse_iterator(cend());
1206 }
1207
1212 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reverse_iterator crend() const noexcept {
1214 }
1215
1220 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type size() const noexcept {
1221#ifdef NEFORCE_USING_SSO
1222 return size_pair_.value & ~long_flag;
1223#else
1224 return size_;
1225#endif
1226 }
1227
1232 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type max_size() const noexcept { return npos; }
1233
1238 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type capacity() const noexcept {
1239#ifdef NEFORCE_USING_SSO
1240 return is_long() ? storage_.long_.cap : sso_buffer_size;
1241#else
1242 return capacity_pair_.value;
1243#endif
1244 }
1245
1250 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type length() const noexcept { return size(); }
1251
1256 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool empty() const noexcept { return size() == 0; }
1257
1262 NEFORCE_CONSTEXPR20 void reserve(const size_type n) {
1263 NEFORCE_DEBUG_VERIFY(n < max_size(), "basic_string reserve index out of range.");
1264 const size_type new_cap = n + 1;
1265 if (new_cap <= capacity()) {
1266 return;
1267 }
1268
1269#ifdef NEFORCE_USING_SSO
1270 if (!is_long()) {
1271 switch_to_long(new_cap);
1272 } else {
1273 pointer new_ptr = size_pair_.get_base().allocate(new_cap);
1274 traits_type::move(new_ptr, storage_.long_.ptr, size());
1275 traits_type::assign(new_ptr + size(), 1, value_type());
1276 destroy_long();
1277 storage_.long_.ptr = new_ptr;
1278 storage_.long_.cap = new_cap;
1279 }
1280#else
1281 pointer new_buffer = capacity_pair_.get_base().allocate(new_cap);
1282 traits_type::move(new_buffer, data_, size_);
1283 capacity_pair_.get_base().deallocate(data_, capacity_pair_.value);
1284
1285 data_ = new_buffer;
1286 capacity_pair_.value = new_cap;
1287 traits_type::assign(data_ + size_, 1, value_type());
1288#endif
1289 }
1290
1296 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference operator[](const size_type n) noexcept {
1297 NEFORCE_DEBUG_VERIFY(n <= size(), "basic_string [] index out of range.");
1298 return *(data() + n);
1299 }
1300
1306 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference operator[](const size_type n) const noexcept {
1307 NEFORCE_DEBUG_VERIFY(n <= size(), "basic_string [] index out of range.");
1308 return *(data() + n);
1309 }
1310
1316 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference at(const size_type n) noexcept { return (*this)[n]; }
1317
1323 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference at(const size_type n) const noexcept { return (*this)[n]; }
1324
1329 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference front() noexcept {
1330 NEFORCE_DEBUG_VERIFY(!empty(), "front called on empty basic_string");
1331 return *data();
1332 }
1333
1338 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference front() const noexcept {
1339 NEFORCE_DEBUG_VERIFY(!empty(), "front called on empty basic_string");
1340 return *data();
1341 }
1342
1347 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 reference back() noexcept {
1348 NEFORCE_DEBUG_VERIFY(!empty(), "back called on empty basic_string");
1349 return *(data() + size() - 1);
1350 }
1351
1356 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_reference back() const noexcept {
1357 NEFORCE_DEBUG_VERIFY(!empty(), "back called on empty basic_string");
1358 return *(data() + size() - 1);
1359 }
1360
1365 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 pointer data() noexcept {
1366#ifdef NEFORCE_USING_SSO
1367 if (!is_long()) {
1368 return storage_.short_;
1369 }
1370 return storage_.long_.ptr;
1371#else
1372 return data_;
1373#endif
1374 }
1375
1380 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 const_pointer data() const noexcept {
1381#ifdef NEFORCE_USING_SSO
1382 if (!is_long()) {
1383 return storage_.short_;
1384 }
1385 return storage_.long_.ptr;
1386#else
1387 return data_;
1388#endif
1389 }
1390
1397 NEFORCE_CONSTEXPR20 iterator insert(iterator position, value_type value) {
1398#ifdef NEFORCE_USING_SSO
1399 const size_type offset = position - begin();
1400 if (!is_long() && size() + 1 < sso_buffer_size) {
1401 pointer p = storage_.short_ + offset;
1402 traits_type::move(p + 1, p, size() - offset);
1403 *p = value;
1404 ++size_pair_.value;
1405 traits_type::assign(storage_.short_ + size(), 1, value_type());
1406 return iterator(p, this);
1407 }
1408 return basic_string::reallocate_fill(position, 1, value);
1409#else
1410 if (size_ == capacity_pair_.value) {
1411 return basic_string::reallocate_fill(position, 1, value);
1412 }
1413
1414 size_type offset = position - begin();
1415 pointer p = data_ + offset;
1416 size_type chars_after = size_ - offset;
1417 if (chars_after > 0) {
1418 traits_type::move(p + 1, p, chars_after);
1419 }
1420
1421 *p = value;
1422 ++size_;
1423 traits_type::assign(data_ + size_, 1, value_type());
1424 return iterator(p, this);
1425#endif
1426 }
1427
1435 NEFORCE_CONSTEXPR20 basic_string& insert(size_type position, size_type n, value_type value) {
1436 insert(begin() + position, n, value);
1437 return *this;
1438 }
1439
1440 NEFORCE_CONSTEXPR20 iterator insert(iterator position, size_type n, value_type value) {
1441 if (n == 0) {
1442 return position;
1443 }
1444
1445#ifdef NEFORCE_USING_SSO
1446 if (!is_long() && size() + n < sso_buffer_size) {
1447 const size_type offset = position - begin();
1448 pointer p = storage_.short_ + offset;
1449 traits_type::move(p + n, p, size() - offset);
1450 traits_type::assign(p, n, value);
1451 size_pair_.value = size() + n;
1452 traits_type::assign(storage_.short_ + size(), 1, value_type());
1453 return iterator(p, this);
1454 }
1455
1456 return basic_string::reallocate_fill(position, n, value);
1457#else
1458 if (capacity_pair_.value - size_ < n) {
1459 return basic_string::reallocate_fill(position, n, value);
1460 }
1461
1462 const size_type offset = position - begin();
1463 pointer p = data_ + offset;
1464 const size_type chars_after = size_ - offset;
1465
1466 if (chars_after > 0) {
1467 traits_type::move(p + n, p, chars_after);
1468 }
1469 traits_type::assign(p, n, value);
1470
1471 size_ += n;
1472 traits_type::assign(data_ + size_, 1, value_type());
1473 return iterator(p, this);
1474#endif
1475 }
1476
1485 template <typename Iterator>
1486 NEFORCE_CONSTEXPR20 iterator insert(iterator position, Iterator first, Iterator last) {
1487 const size_type len = _NEFORCE distance(first, last);
1488 if (len == 0) {
1489 return position;
1490 }
1491
1492#ifdef NEFORCE_USING_SSO
1493 if (!is_long() && size() + len < sso_buffer_size) {
1494 const size_type offset = position - begin();
1495 pointer p = storage_.short_ + offset;
1496 traits_type::move(p + len, p, size() - offset);
1497 for (size_type i = 0; i < len; ++i) {
1498 p[i] = *first++;
1499 }
1500 size_pair_.value = size() + len;
1501 traits_type::assign(storage_.short_ + size(), 1, value_type());
1502 return iterator(p, this);
1503 }
1504 return basic_string::reallocate_copy(position, first, last);
1505#else
1506 if (capacity_pair_.value - size_ < len) {
1507 return basic_string::reallocate_copy(position, first, last);
1508 }
1509
1510 const size_type offset = position - begin();
1511 pointer p = data_ + offset;
1512 const size_type chars_after = size_ - offset;
1513
1514 if (chars_after > 0) {
1515 traits_type::move(p + len, p, chars_after);
1516 }
1517 pointer curr = p;
1518 for (Iterator it = first; it != last; ++it, ++curr) {
1519 *curr = *it;
1520 }
1521
1522 size_ += len;
1523 traits_type::assign(data_ + size_, 1, value_type());
1524 return position;
1525#endif
1526 }
1527
1532 NEFORCE_CONSTEXPR20 void push_back(value_type value) { append(1, value); }
1533
1537 NEFORCE_CONSTEXPR20 void pop_back() noexcept {
1538 NEFORCE_DEBUG_VERIFY(!empty(), "pop_back called on empty basic_string");
1539#ifdef NEFORCE_USING_SSO
1540 const size_type new_size = size() - 1;
1541 if (is_long()) {
1542 size_pair_.value = new_size | long_flag;
1543 traits_type::assign(storage_.long_.ptr + new_size, 1, value_type());
1544 } else {
1545 size_pair_.value = new_size;
1546 traits_type::assign(storage_.short_ + new_size, 1, value_type());
1547 }
1548#else
1549 --size_;
1550 traits_type::assign(data_ + size_, 1, value_type());
1551#endif
1552 }
1553
1560 NEFORCE_CONSTEXPR20 basic_string& append(size_type n, value_type value) {
1561 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1562 if (n == 0) {
1563 return *this;
1564 }
1565
1566#ifdef NEFORCE_USING_SSO
1567 if (!is_long() && size() + n < sso_buffer_size) {
1568 pointer p = storage_.short_ + size();
1569 traits_type::assign(p, n, value);
1570 size_pair_.value = size() + n;
1571 traits_type::assign(storage_.short_ + size(), 1, value_type());
1572 return *this;
1573 }
1574
1575 const size_type old_size = size();
1576 if (is_long() && storage_.long_.cap >= old_size + n + 1) {
1577 pointer p = storage_.long_.ptr + old_size;
1578 traits_type::assign(p, n, value);
1579 size_pair_.value = (old_size + n) | long_flag;
1580 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1581 return *this;
1582 }
1583
1584 reallocate(n);
1585 pointer p = data() + old_size;
1586 traits_type::assign(p, n, value);
1587 size_pair_.value = (old_size + n) | (is_long() ? long_flag : 0);
1589#else
1590 if (capacity_pair_.value - size_ <= n) {
1591 reallocate(n);
1592 }
1593 traits_type::assign(data_ + size_, n, value);
1594 size_ += n;
1595 traits_type::assign(data_ + size_, 1, value_type());
1596#endif
1597 return *this;
1598 }
1599
1605 NEFORCE_CONSTEXPR20 basic_string& append(value_type value) { return append(1, value); }
1606
1614 NEFORCE_CONSTEXPR20 basic_string& append(const basic_string& other, size_type position, size_type n) {
1615 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1616 if (n == 0) {
1617 return *this;
1618 }
1619 n = _NEFORCE min(n, other.size() - position);
1620 return basic_string::append(other.data() + position, n);
1621 }
1622
1628 NEFORCE_CONSTEXPR20 basic_string& append(const basic_string& other) { return append(other, 0, other.size()); }
1629
1636 NEFORCE_CONSTEXPR20 basic_string& append(const basic_string& other, size_type position) {
1637 return append(other, position, other.size() - position);
1638 }
1639
1647 NEFORCE_CONSTEXPR20 basic_string& append(basic_string&& other, size_type position, size_type n) {
1648 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1649 if (n == 0) {
1650 return *this;
1651 }
1652 n = _NEFORCE min(n, other.size() - position);
1653 basic_string::append(other.data() + position, n);
1654 other.clear();
1655 return *this;
1656 }
1657
1663 NEFORCE_CONSTEXPR20 basic_string& append(basic_string&& other) {
1664 const size_type len = other.size();
1665 return basic_string::append(_NEFORCE move(other), 0, len);
1666 }
1667
1674 NEFORCE_CONSTEXPR20 basic_string& append(basic_string&& other, size_type position) {
1675 const size_type len = other.size();
1676 return basic_string::append(_NEFORCE move(other), position, len - position);
1677 }
1678
1685 NEFORCE_CONSTEXPR20 basic_string& append(view_type view, size_type n) { return append(view.data(), n); }
1686
1692 NEFORCE_CONSTEXPR20 basic_string& append(view_type view) { return append(view.data(), view.size()); }
1693
1700 NEFORCE_CONSTEXPR20 basic_string& append(const_pointer str, size_type n) {
1701 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1702 if (n == 0) {
1703 return *this;
1704 }
1705
1706#ifdef NEFORCE_USING_SSO
1707 const size_type old_size = size();
1708 if (!is_long() && old_size + n < sso_buffer_size) {
1709 traits_type::copy(storage_.short_ + old_size, str, n);
1710 size_pair_.value = old_size + n;
1711 traits_type::assign(storage_.short_ + size(), 1, value_type());
1712 return *this;
1713 }
1714
1715 if (is_long() && storage_.long_.cap >= old_size + n + 1) {
1716 traits_type::copy(storage_.long_.ptr + old_size, str, n);
1717 size_pair_.value = (old_size + n) | long_flag;
1718 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1719 return *this;
1720 }
1721
1722 reallocate(n);
1723 traits_type::copy(data() + old_size, str, n);
1724 size_pair_.value = (old_size + n) | long_flag;
1726#else
1727 if (capacity_pair_.value - size_ <= n) {
1728 reallocate(n);
1729 }
1730 traits_type::copy(data_ + size_, str, n);
1731 size_ += n;
1732 traits_type::assign(data_ + size_, 1, value_type());
1733#endif
1734 return *this;
1735 }
1736
1742 NEFORCE_CONSTEXPR20 basic_string& append(const_pointer str) { return append(str, traits_type::length(str)); }
1743
1751 template <typename Iterator, enable_if_t<is_iter_v<Iterator>, int> = 0>
1752 NEFORCE_CONSTEXPR20 basic_string& append(Iterator first, Iterator last) {
1753 const size_type n = _NEFORCE distance(first, last);
1754 NEFORCE_DEBUG_VERIFY(size() + n < max_size(), "basic_string append iterator out of ranges.");
1755 if (n == 0) {
1756 return *this;
1757 }
1758
1759#ifdef NEFORCE_USING_SSO
1760 const size_type old_size = size();
1761 if (!is_long() && old_size + n < sso_buffer_size) {
1762 pointer p = storage_.short_ + old_size;
1763 for (size_type i = 0; i < n; ++i) {
1764 p[i] = *first++;
1765 }
1766 size_pair_.value = old_size + n;
1767 traits_type::assign(storage_.short_ + size(), 1, value_type());
1768 return *this;
1769 }
1770
1771 if (is_long() && storage_.long_.cap >= old_size + n + 1) {
1772 pointer p = storage_.long_.ptr + old_size;
1773 for (size_type i = 0; i < n; ++i) {
1774 p[i] = *first++;
1775 }
1776 size_pair_.value = (old_size + n) | long_flag;
1777 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1778 return *this;
1779 }
1780
1781 reallocate(n);
1782 pointer p = data() + old_size;
1783 for (size_type i = 0; i < n; ++i) {
1784 p[i] = *first++;
1785 }
1786 size_pair_.value = (old_size + n) | long_flag;
1788#else
1789 if (capacity_pair_.value - size_ <= n) {
1790 reallocate(n);
1791 }
1792 _NEFORCE uninitialized_copy_n(first, n, data_ + size_);
1793 size_ += n;
1794 traits_type::assign(data_ + size_, 1, value_type());
1795#endif
1796 return *this;
1797 }
1798
1804 NEFORCE_CONSTEXPR20 basic_string& append(std::initializer_list<value_type> ilist) {
1805 return append(ilist.begin(), ilist.end());
1806 }
1807
1809 NEFORCE_CONSTEXPR20 basic_string& operator+=(const basic_string& other) { return basic_string::append(other); }
1810
1812 NEFORCE_CONSTEXPR20 basic_string& operator+=(basic_string&& other) {
1813 return basic_string::append(_NEFORCE move(other));
1814 }
1815
1817 NEFORCE_CONSTEXPR20 basic_string& operator+=(const value_type value) { return basic_string::append(value); }
1818
1820 NEFORCE_CONSTEXPR20 basic_string& operator+=(const_pointer str) { return basic_string::append(str); }
1821
1823 NEFORCE_CONSTEXPR20 basic_string& operator+=(std::initializer_list<value_type> ilist) {
1824 return basic_string::append(ilist);
1825 }
1826
1829
1835 NEFORCE_CONSTEXPR20 basic_string& assign(const basic_string& other) { return *this = other; }
1836
1842 NEFORCE_CONSTEXPR20 basic_string& assign(basic_string&& other) { return *this = _NEFORCE move(other); }
1843
1849 NEFORCE_CONSTEXPR20 basic_string& assign(const_pointer str) { return *this = str; }
1850
1857 NEFORCE_CONSTEXPR20 basic_string& assign(const_pointer str, const size_type n) {
1858 clear();
1859 return append(str, n);
1860 }
1861
1868 NEFORCE_CONSTEXPR20 basic_string& assign(const size_type n, value_type value) {
1869 clear();
1870 return append(n, value);
1871 }
1872
1880 template <typename Iterator>
1881 NEFORCE_CONSTEXPR20 basic_string& assign(Iterator first, Iterator last) {
1882 clear();
1883 return append(first, last);
1884 }
1885
1891 NEFORCE_CONSTEXPR20 basic_string& assign(std::initializer_list<value_type> ilist) { return *this = ilist; }
1892
1898 NEFORCE_CONSTEXPR20 basic_string& assign(const view_type& view) { return *this = view; }
1899
1905 NEFORCE_CONSTEXPR20 iterator erase(iterator position) noexcept {
1906 NEFORCE_DEBUG_VERIFY(position != end(), "erase: cannot erase end() iterator");
1907
1908#ifdef NEFORCE_USING_SSO
1909 const size_type offset = position - begin();
1910 pointer p = data() + offset;
1911 const size_type chars_after = size() - offset - 1;
1912 if (chars_after > 0) {
1913 traits_type::move(p, p + 1, chars_after);
1914 }
1915 if (is_long()) {
1916 size_pair_.value = (size() - 1) | long_flag;
1917 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1918 } else {
1919 size_pair_.value = size() - 1;
1920 traits_type::assign(storage_.short_ + size(), 1, value_type());
1921 }
1922#else
1923 pointer ptr = &*position;
1924 const size_type chars_after = end() - position - 1;
1925 if (chars_after > 0) {
1926 traits_type::move(ptr, ptr + 1, chars_after);
1927 }
1928
1929 --size_;
1930 traits_type::assign(data_ + size_, 1, value_type());
1931#endif
1932 return position;
1933 }
1934
1941 NEFORCE_CONSTEXPR20 basic_string& erase(size_type position = 0, size_type n = npos) noexcept {
1942 if (position >= size()) {
1943 return *this;
1944 }
1945 n = _NEFORCE min(n, size() - position);
1946 basic_string::erase(begin() + position, n);
1947 return *this;
1948 }
1949
1956 NEFORCE_CONSTEXPR20 iterator erase(iterator first, const size_type n) noexcept {
1957 if (n == 0) {
1958 return first;
1959 }
1960 iterator last = first + _NEFORCE min(n, static_cast<size_type>(end() - first));
1961 return erase(first, last);
1962 }
1963
1970 NEFORCE_CONSTEXPR20 iterator erase(iterator first, iterator last) noexcept {
1971 if (first == last) {
1972 return first;
1973 }
1974
1975 const size_type erase_count = last - first;
1976
1977#ifdef NEFORCE_USING_SSO
1978 const size_type offset = first - begin();
1979 pointer p = data() + offset;
1980 const size_type chars_after = end() - last;
1981 if (chars_after > 0) {
1982 traits_type::move(p, p + erase_count, chars_after);
1983 }
1984 if (is_long()) {
1985 size_pair_.value = (size() - erase_count) | long_flag;
1986 traits_type::assign(storage_.long_.ptr + size(), 1, value_type());
1987 } else {
1988 size_pair_.value = size() - erase_count;
1989 traits_type::assign(storage_.short_ + size(), 1, value_type());
1990 }
1991#else
1992 const size_type chars_after = end() - last;
1993
1994 if (chars_after > 0) {
1995 pointer p_first = data_ + (first - begin());
1996 pointer p_last = data_ + (last - begin());
1997 traits_type::move(p_first, p_last, chars_after);
1998 }
1999
2000 size_ -= erase_count;
2001 traits_type::assign(data_ + size_, 1, value_type());
2002#endif
2003 return first;
2004 }
2005
2006
2012 NEFORCE_CONSTEXPR20 void resize(size_type n, value_type value) {
2013 if (n < size()) {
2014 basic_string::erase(begin() + n, end());
2015 } else {
2016 basic_string::append(n - size(), value);
2017 }
2018 }
2019
2024 NEFORCE_CONSTEXPR20 void resize(const size_type n) { basic_string::resize(n, value_type()); }
2025
2029 NEFORCE_CONSTEXPR20 void clear() noexcept {
2030#ifdef NEFORCE_USING_SSO
2031 if (is_long()) {
2032 destroy_long();
2033 traits_type::assign(storage_.short_, 1, value_type());
2034 size_pair_.value = 0;
2035 } else {
2036 traits_type::assign(storage_.short_, 1, value_type());
2037 size_pair_.value = 0;
2038 }
2039#else
2040 size_ = 0;
2041 traits_type::assign(data_ + size_, 1, value_type());
2042#endif
2043 }
2044
2048 NEFORCE_CONSTEXPR20 void shrink_to_fit() {
2049#ifdef NEFORCE_USING_SSO
2050 if (!is_long()) {
2051 return;
2052 }
2053 const size_type len = size();
2054 if (len < sso_capacity) {
2055 CharT tmp[sso_buffer_size];
2056 traits_type::copy(tmp, storage_.long_.ptr, len);
2057 traits_type::assign(tmp + len, 1, value_type());
2058 destroy_long();
2059 traits_type::copy(storage_.short_, tmp, len + 1);
2060 size_pair_.value = len;
2061 } else {
2062 if (storage_.long_.cap > len + 1) {
2063 pointer new_ptr = size_pair_.get_base().allocate(len + 1);
2064 traits_type::move(new_ptr, storage_.long_.ptr, len);
2065 traits_type::assign(new_ptr + len, 1, value_type());
2066 destroy_long();
2067 storage_.long_.ptr = new_ptr;
2068 storage_.long_.cap = len + 1;
2069 size_pair_.value = len | long_flag;
2070 }
2071 }
2072#else
2073 const size_type new_cap = size_ + 1;
2074 if (new_cap >= capacity_pair_.value) {
2075 return;
2076 }
2077
2078 basic_string temp;
2079 temp.reserve(new_cap);
2080 temp.append(*this);
2081 basic_string::swap(temp);
2082#endif
2083 }
2084
2090 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string repeat(size_type n) const noexcept {
2091 basic_string result;
2092 result.reserve(size() * n);
2093 while (n-- != 0U) {
2094 result += *this;
2095 }
2096 return _NEFORCE move(result);
2097 }
2098
2105 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string substr(const size_type off = 0,
2106 const size_type count = npos) const {
2107 NEFORCE_DEBUG_VERIFY(off <= size(), "basic_string index out of ranges.");
2108 const size_type clamp = _NEFORCE min(count, size() - off);
2109 return basic_string(data() + off, clamp);
2110 }
2111
2117 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string head(const size_type count = npos) const {
2118 return substr(0, count);
2119 }
2120
2126 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string tail(const size_type off = 0) const { return substr(off); }
2127
2132 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 view_type view() const noexcept { return view_type(data(), size()); }
2133
2140 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 view_type view(const size_type off, size_type count = npos) const noexcept {
2141 NEFORCE_DEBUG_VERIFY(off <= size(), "basic_string index out of ranges.");
2142 count = _NEFORCE min(count, size() - off);
2143 return view_type(data() + off, count);
2144 }
2145
2153 NEFORCE_CONSTEXPR20 size_type copy(pointer dest, const size_type count, size_type position = 0) const {
2154 NEFORCE_DEBUG_VERIFY(position <= size(), "basic_string copy position out of range");
2155 const size_type len = _NEFORCE min(count, size() - position);
2156 traits_type::copy(dest, data() + position, len);
2157 return len;
2158 }
2159
2165 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const basic_string& other) const noexcept {
2166 return compare(other.view());
2167 }
2168
2176 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n,
2177 const basic_string& other) const {
2178 return view(off, n).compare(other.view());
2179 }
2180
2190 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n, const basic_string& other,
2191 const size_type roff, const size_type count) const {
2192 return view(off, n).compare(other.view(roff, count));
2193 }
2194
2200 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const CharT* str) const noexcept {
2201 return compare(view_type(str));
2202 }
2203
2209 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const view_type& view) const noexcept {
2210 return char_traits_compare<traits_type>(data(), size(), view.data(), view.size());
2211 }
2212
2220 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n, const CharT* str) const {
2221 return view(off, n).compare(view_type(str));
2222 }
2223
2232 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare(const size_type off, const size_type n, const CharT* str,
2233 size_type count) const {
2234 return view(off, n).compare(view_type(str, count));
2235 }
2236
2242 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare_ignore_case(const view_type view) const noexcept {
2243 const size_type min_len = _NEFORCE min(size(), view.size());
2244 for (size_type i = 0; i < min_len; ++i) {
2245 const auto lc = _NEFORCE to_lowercase(data()[i]);
2246 const auto rc = _NEFORCE to_lowercase(view.data()[i]);
2247 if (lc != rc) {
2248 return (lc < rc) ? -1 : 1;
2249 }
2250 }
2251 if (size() < view.size()) {
2252 return -1;
2253 }
2254 if (size() > view.size()) {
2255 return 1;
2256 }
2257 return 0;
2258 }
2259
2265 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare_ignore_case(const_pointer str) const noexcept {
2266 return this->compare_ignore_case(view_type(str));
2267 }
2268
2274 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 int compare_ignore_case(const basic_string& str) const noexcept {
2275 return this->compare_ignore_case(str.view());
2276 }
2277
2279 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n, const basic_string& other) {
2280 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2281 return replace_copy(begin() + position, n, other.data(), other.size());
2282 }
2283
2285 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const basic_string& other) {
2286 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2287 "basic_string replace iterator out of ranges.");
2288 return replace_copy(first, last - first, other.data(), other.size());
2289 }
2290
2292 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n, const_pointer str) {
2293 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2294 return replace_copy({data() + position, this}, n, str, traits_type::length(str));
2295 }
2296
2298 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const_pointer str) {
2299 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2300 "basic_string replace iterator out of ranges.");
2301 return replace_copy(first, last - first, str, traits_type::length(str));
2302 }
2303
2305 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n1, const_pointer str,
2306 const size_type n2) {
2307 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2308 return replace_copy({data() + position, this}, n1, str, n2);
2309 }
2310
2312 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const_pointer str, const size_type n) {
2313 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2314 "basic_string replace iterator out of ranges.");
2315 return replace_copy(first, last - first, str, n);
2316 }
2317
2319 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position, const size_type n1, const size_type n2,
2320 const value_type value) {
2321 NEFORCE_DEBUG_VERIFY(position < size(), "basic_string index out of ranges.");
2322 return replace_fill({data() + position, this}, n1, n2, value);
2323 }
2324
2326 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, const size_type n,
2327 const value_type value) {
2328 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2329 "basic_string replace iterator out of ranges.");
2330 return replace_fill(first, static_cast<size_type>(last - first), n, value);
2331 }
2332
2334 NEFORCE_CONSTEXPR20 basic_string& replace(const size_type position1, const size_type n1, const basic_string& str,
2335 const size_type position2, const size_type n2 = npos) {
2336 NEFORCE_DEBUG_VERIFY(position1 < size(), "basic_string index out of ranges.");
2337 NEFORCE_DEBUG_VERIFY(position2 < size(), "basic_string index out of ranges.");
2338 return replace_copy({data() + position1, this}, n1, str.data() + position2, n2);
2339 }
2340
2342 template <typename Iterator>
2343 NEFORCE_CONSTEXPR20 basic_string& replace(iterator first, iterator last, Iterator first2, Iterator last2) {
2344 NEFORCE_DEBUG_VERIFY(begin() <= first && last <= end() && first <= last,
2345 "basic_string replace iterator out of ranges.");
2346 return replace_copy(first, last, first2, last2);
2347 }
2348
2352 NEFORCE_CONSTEXPR20 void reverse() noexcept {
2353 if (size() < 2) {
2354 return;
2355 }
2356
2357 for (iterator first = begin(), last = end(); first < last;) {
2358 _NEFORCE iter_swap(first++, --last);
2359 }
2360 }
2361
2363 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const basic_string& other,
2364 const size_type n = 0) const noexcept {
2365 return (char_traits_find<Traits>) (data(), size(), n, other.data(), other.size());
2366 }
2367
2369 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const CharT value, const size_type n = 0) const noexcept {
2370 return (char_traits_find_char<Traits>) (data(), size(), n, value);
2371 }
2372
2374 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const CharT* str, const size_type off,
2375 const size_type count) const noexcept {
2376 return (char_traits_find<Traits>) (data(), size(), off, str, count);
2377 }
2378
2380 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const CharT* str, const size_type off = 0) const noexcept {
2381 return (char_traits_find<Traits>) (data(), size(), off, str, Traits::length(str));
2382 }
2383
2385 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const view_type& view, const size_type off,
2386 const size_type count) const noexcept {
2387 return (char_traits_find<Traits>) (data(), size(), off, view.data(), count);
2388 }
2389
2391 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find(const view_type& view,
2392 const size_type off = 0) const noexcept {
2393 return _NEFORCE char_traits_find<Traits>(data(), size(), off, view.data(), view.size());
2394 }
2395
2397 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const basic_string& other,
2398 const size_type off = npos) const noexcept {
2399 return (char_traits_rfind<Traits>) (data(), size(), off, other.data(), other.size());
2400 }
2401
2403 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const CharT value, const size_type n = npos) const noexcept {
2404 return (char_traits_rfind_char<Traits>) (data(), size(), n, value);
2405 }
2406
2408 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const CharT* str, const size_type off,
2409 const size_type n) const noexcept {
2410 return (char_traits_rfind<Traits>) (data(), size(), off, str, n);
2411 }
2412
2414 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const CharT* str, const size_type off = npos) const noexcept {
2415 return (char_traits_rfind<Traits>) (data(), size(), off, str, Traits::length(str));
2416 }
2417
2419 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const view_type& view, const size_type off,
2420 const size_type count) const noexcept {
2421 return (char_traits_rfind<Traits>) (data(), size(), off, view.data(), count);
2422 }
2423
2425 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type rfind(const view_type& view,
2426 const size_type off = npos) const noexcept {
2427 return (char_traits_rfind<Traits>) (data(), size(), off, view.data(), view.size());
2428 }
2429
2431 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const basic_string& other,
2432 const size_type off = 0) const noexcept {
2433 return (char_traits_find_first_of<Traits>) (data(), size(), off, other.data(), other.size());
2434 }
2435
2437 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const CharT value,
2438 const size_type off = 0) const noexcept {
2439 return (char_traits_find_char<Traits>) (data(), size(), off, value);
2440 }
2441
2443 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const CharT* str, const size_type off,
2444 const size_type n) const noexcept {
2445 return (char_traits_find_first_of<Traits>) (data(), size(), off, str, n);
2446 }
2447
2449 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const CharT* str,
2450 const size_type off = 0) const noexcept {
2451 return (char_traits_find_first_of<Traits>) (data(), size(), off, str, Traits::length(str));
2452 }
2453
2455 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const view_type& view, const size_type off,
2456 const size_type n) const noexcept {
2457 return (char_traits_find_first_of<Traits>) (data(), size(), off, view.data(), n);
2458 }
2459
2461 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_of(const view_type& view,
2462 const size_type off = 0) const noexcept {
2463 return (char_traits_find_first_of<Traits>) (data(), size(), off, view.data(), view.size());
2464 }
2465
2467 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const basic_string& other,
2468 const size_type off = npos) const noexcept {
2469 return (char_traits_find_last_of<Traits>) (data(), size(), off, other.data(), other.size());
2470 }
2471
2473 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const CharT value,
2474 const size_type off = npos) const noexcept {
2475 return (char_traits_rfind_char<Traits>) (data(), size(), off, value);
2476 }
2477
2479 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const CharT* str, const size_type off,
2480 const size_type n) const noexcept {
2481 return (char_traits_find_last_of<Traits>) (data(), size(), off, str, n);
2482 }
2483
2485 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const CharT* str,
2486 const size_type off = npos) const noexcept {
2487 return (char_traits_find_last_of<Traits>) (data(), size(), off, str, Traits::length(str));
2488 }
2489
2491 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const view_type& view, const size_type off,
2492 const size_type n) const noexcept {
2493 return (char_traits_find_last_of<Traits>) (data(), size(), off, view.data(), n);
2494 }
2495
2497 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_of(const view_type& view,
2498 const size_type off = npos) const noexcept {
2499 return (char_traits_find_last_of<Traits>) (data(), size(), off, view.data(), view.size());
2500 }
2501
2503 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const basic_string& other,
2504 const size_type off = 0) const noexcept {
2505 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, other.data(), other.size());
2506 }
2507
2509 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const CharT value,
2510 const size_type off = 0) const noexcept {
2511 return (char_traits_find_not_char<Traits>) (data(), size(), off, value);
2512 }
2513
2515 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const CharT* str, const size_type off,
2516 const size_type n) const noexcept {
2517 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, str, n);
2518 }
2519
2521 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const CharT* str,
2522 const size_type off = 0) const noexcept {
2523 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, str, Traits::length(str));
2524 }
2525
2527 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const view_type& view, const size_type off,
2528 const size_type n) const noexcept {
2529 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, view.data(), n);
2530 }
2531
2533 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_first_not_of(const view_type& view,
2534 const size_type off = 0) const noexcept {
2535 return (char_traits_find_first_not_of<Traits>) (data(), size(), off, view.data(), view.size());
2536 }
2537
2539 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const basic_string& other,
2540 const size_type off = npos) const noexcept {
2541 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, other.data(), other.size());
2542 }
2543
2545 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const CharT value,
2546 const size_type off = npos) const noexcept {
2547 return (char_traits_rfind_not_char<Traits>) (data(), size(), off, value);
2548 }
2549
2551 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const CharT* str, const size_type off,
2552 const size_type n) const noexcept {
2553 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, str, n);
2554 }
2555
2557 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const CharT* str,
2558 const size_type off = npos) const noexcept {
2559 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, str, Traits::length(str));
2560 }
2561
2563 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const view_type& view, const size_type off,
2564 const size_type n) const noexcept {
2565 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, view.data(), n);
2566 }
2567
2569 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type find_last_not_of(const view_type& view,
2570 const size_type off = npos) const noexcept {
2571 return (char_traits_find_last_not_of<Traits>) (data(), size(), off, view.data(), view.size());
2572 }
2573
2580 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type count(value_type value,
2581 const size_type position = 0) const noexcept {
2582 size_type n = 0;
2583 for (size_type idx = position; idx < size(); ++idx) {
2584 if (*(data() + idx) == value) {
2585 ++n;
2586 }
2587 }
2588 return n;
2589 }
2590
2592 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(const basic_string& other) const noexcept {
2593 return other.size() <= size() && traits_type::compare(data(), other.data(), other.size()) == 0;
2594 }
2595
2597 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(view_type view) const noexcept {
2598 return view.size() <= size() && traits_type::compare(data(), view.data(), view.size()) == 0;
2599 }
2600
2602 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(const value_type value) const noexcept {
2603 return !empty() && traits_type::eq(front(), value);
2604 }
2605
2607 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool starts_with(const_pointer str) const noexcept {
2608 return starts_with(view_type(str));
2609 }
2610
2612 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(const basic_string& other) const noexcept {
2613 const size_type other_size = other.size();
2614 return other_size <= size() &&
2615 traits_type::compare(data() + size() - other_size, other.data(), other_size) == 0;
2616 }
2617
2619 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(view_type view) const noexcept {
2620 const size_type view_size = view.size();
2621 return view_size <= size() && traits_type::compare(data() + size() - view_size, view.data(), view_size) == 0;
2622 }
2623
2625 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(value_type value) const noexcept {
2626 return !empty() && traits_type::eq(back(), value);
2627 }
2628
2630 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool ends_with(const_pointer str) const noexcept {
2631 return ends_with(view_type(str));
2632 }
2633
2635 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(const basic_string& other) const noexcept {
2636 return find(other) != npos;
2637 }
2638
2640 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(view_type view) const noexcept { return find(view) != npos; }
2641
2643 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(value_type value) const noexcept { return find(value) != npos; }
2644
2646 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool contains(const_pointer str) const noexcept { return find(str) != npos; }
2647
2652 NEFORCE_CONSTEXPR20 basic_string& trim_left() noexcept {
2653 return trim_left_if([](value_type value) { return _NEFORCE is_space(value); });
2654 }
2655
2660 NEFORCE_CONSTEXPR20 basic_string& trim_right() noexcept {
2661 return trim_right_if([](value_type value) { return _NEFORCE is_space(value); });
2662 }
2663
2668 NEFORCE_CONSTEXPR20 basic_string& trim() noexcept { return trim_left().trim_right(); }
2669
2676 template <typename Pred>
2677 NEFORCE_CONSTEXPR20 basic_string& trim_left_if(Pred pred) {
2678 if (empty()) {
2679 return *this;
2680 }
2681
2682 iterator it = begin();
2683 while (it != end() && pred(*it)) {
2684 ++it;
2685 }
2686 if (it != begin()) {
2687 basic_string::erase(begin(), it - begin());
2688 }
2689
2690 return *this;
2691 }
2692
2699 template <typename Pred>
2700 NEFORCE_CONSTEXPR20 basic_string& trim_right_if(Pred pred) {
2701 if (empty()) {
2702 return *this;
2703 }
2704
2705 reverse_iterator rit = rbegin();
2706 while (rit != rend() && pred(*rit)) {
2707 ++rit;
2708 }
2709 if (rit != rbegin()) {
2710 basic_string::erase(end() - (rit - rbegin()), end());
2711 }
2712
2713 return *this;
2714 }
2715
2722 template <typename Predicate>
2723 NEFORCE_CONSTEXPR20 basic_string& trim_if(Predicate pred) {
2724 return trim_left_if(pred).trim_right_if(pred);
2725 }
2726
2732 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const basic_string& other) const noexcept {
2733 return equal_to(other.view());
2734 }
2735
2741 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const view_type view) const noexcept {
2742 return _NEFORCE char_traits_equal<Traits>(data(), size(), view.data(), view.size());
2743 }
2744
2750 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool equal_to(const CharT* str) const noexcept {
2751 return equal_to(view_type(str));
2752 }
2753
2757 NEFORCE_CONSTEXPR20 basic_string&
2758 lowercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase<CharT>))) {
2759 _NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase<CharT>);
2760 return *this;
2761 }
2762
2766 NEFORCE_CONSTEXPR20 basic_string&
2767 uppercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_uppercase<CharT>))) {
2768 _NEFORCE transform(begin(), end(), begin(), _NEFORCE to_uppercase<CharT>);
2769 return *this;
2770 }
2771
2776 NEFORCE_CONSTEXPR20 void swap(basic_string& other) noexcept {
2777 if (_NEFORCE addressof(other) == this) {
2778 return;
2779 }
2780#ifdef NEFORCE_USING_SSO
2781 _NEFORCE swap(storage_, other.storage_);
2782 _NEFORCE swap(size_pair_, other.size_pair_);
2783#else
2784 _NEFORCE swap(data_, other.data_);
2785 _NEFORCE swap(size_, other.size_);
2786 _NEFORCE swap(capacity_pair_, other.capacity_pair_);
2787#endif
2788 }
2789
2791 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool less_than(const basic_string& rhs) const noexcept {
2792 return compare(rhs) < 0;
2793 }
2794
2796 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_t to_hash() const noexcept {
2797 return _NEFORCE FNV_hash_string(data(), size());
2798 }
2799};
2800
2801#ifdef NEFORCE_STANDARD_17
2802template <typename Iterator, typename Alloc = allocator<iter_value_t<Iterator>>>
2803basic_string(Iterator, Iterator, Alloc = Alloc())
2804 -> basic_string<iter_value_t<Iterator>, char_traits<iter_value_t<Iterator>>, Alloc>;
2805
2806template <typename CharT, typename Traits, typename Alloc = allocator<CharT>>
2807explicit basic_string(basic_string_view<CharT, Traits>, const Alloc& = Alloc()) -> basic_string<CharT, Traits, Alloc>;
2808
2809template <typename CharT, typename Traits, typename Alloc = allocator<CharT>>
2810basic_string(basic_string_view<CharT, Traits>, typename allocator_traits<Alloc>::size_type,
2812#endif
2813
2814template <typename CharT, typename Traits, typename Alloc>
2818 tmp.append(rhs);
2819 return _NEFORCE move(tmp);
2820}
2821
2822template <typename CharT, typename Traits, typename Alloc>
2823NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const CharT* lhs,
2826 tmp.append(rhs);
2827 return _NEFORCE move(tmp);
2828}
2829template <typename CharT, typename Traits, typename Alloc>
2831 const CharT* rhs) {
2833 tmp.append(rhs);
2834 return _NEFORCE move(tmp);
2835}
2836
2837template <typename CharT, typename Traits, typename Alloc>
2838NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const basic_string_view<CharT, Traits>& lhs,
2841 tmp.append(rhs);
2842 return _NEFORCE move(tmp);
2843}
2844template <typename CharT, typename Traits, typename Alloc>
2846 const basic_string_view<CharT, Traits>& rhs) {
2848 tmp.append(rhs);
2849 return _NEFORCE move(tmp);
2850}
2851
2852template <typename CharT, typename Traits, typename Alloc>
2853NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(CharT lhs,
2856 tmp.append(rhs);
2857 return _NEFORCE move(tmp);
2858}
2859template <typename CharT, typename Traits, typename Alloc>
2861 CharT rhs) {
2863 tmp.append(1, rhs);
2864 return _NEFORCE move(tmp);
2865}
2866
2867template <typename CharT, typename Traits, typename Alloc>
2870 return _NEFORCE move(lhs.append(rhs));
2871}
2872template <typename CharT, typename Traits, typename Alloc>
2876 tmp.append(_NEFORCE move(rhs));
2877 return _NEFORCE move(tmp);
2878}
2879
2880template <typename CharT, typename Traits, typename Alloc>
2883 basic_string<CharT, Traits, Alloc> tmp(_NEFORCE move(lhs));
2884 if (_NEFORCE addressof(lhs) != _NEFORCE addressof(rhs)) {
2885 tmp.append(_NEFORCE move(rhs));
2886 } else {
2887 tmp.append(lhs);
2888 }
2889 return _NEFORCE move(tmp);
2890}
2891
2892template <typename CharT, typename Traits, typename Alloc>
2893NEFORCE_CONSTEXPR20 basic_string<CharT, Traits, Alloc> operator+(const CharT* lhs,
2896 tmp.append(_NEFORCE move(rhs));
2897 return _NEFORCE move(tmp);
2898}
2899template <typename CharT, typename Traits, typename Alloc>
2901 const CharT* rhs) {
2902 return _NEFORCE move(lhs.append(rhs));
2903}
2904
2905template <typename CharT, typename Traits, typename Alloc>
2908 tmp.append(_NEFORCE move(rhs));
2909 return _NEFORCE move(tmp);
2910}
2911template <typename CharT, typename Traits, typename Alloc>
2913 return _NEFORCE move(lhs.append(rhs));
2914}
2915
2916template <typename CharT, typename Traits, typename Alloc>
2917NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const CharT* const lhs,
2918 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2919 return rhs.equal_to(lhs);
2920}
2921template <typename CharT, typename Traits, typename Alloc>
2922NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const basic_string<CharT, Traits, Alloc>& lhs,
2923 const CharT* const rhs) noexcept {
2924 return lhs.equal_to(rhs);
2925}
2926template <typename CharT, typename Traits, typename Alloc>
2927NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const basic_string_view<CharT, Traits>& lhs,
2928 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2929 return rhs.equal_to(lhs);
2930}
2931template <typename CharT, typename Traits, typename Alloc>
2932NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator==(const basic_string<CharT, Traits, Alloc>& lhs,
2933 const basic_string_view<CharT, Traits>& rhs) noexcept {
2934 return lhs.equal_to(rhs);
2935}
2936
2937template <typename CharT, typename Traits, typename Alloc>
2938NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const CharT* const lhs,
2939 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2940 return !(lhs == rhs);
2941}
2942template <typename CharT, typename Traits, typename Alloc>
2943NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const basic_string<CharT, Traits, Alloc>& lhs,
2944 const CharT* const rhs) noexcept {
2945 return !(lhs == rhs);
2946}
2947template <typename CharT, typename Traits, typename Alloc>
2948NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const basic_string_view<CharT, Traits>& lhs,
2949 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2950 return !(lhs == rhs);
2951}
2952template <typename CharT, typename Traits, typename Alloc>
2953NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator!=(const basic_string<CharT, Traits, Alloc>& lhs,
2954 const basic_string_view<CharT, Traits>& rhs) noexcept {
2955 return !(lhs == rhs);
2956}
2957
2958template <typename CharT, typename Traits, typename Alloc>
2959NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const CharT* const lhs,
2960 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2961 return 0 < rhs.compare(lhs);
2962}
2963template <typename CharT, typename Traits, typename Alloc>
2964NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const basic_string<CharT, Traits, Alloc>& lhs,
2965 const CharT* const rhs) noexcept {
2966 return lhs.compare(rhs) < 0;
2967}
2968template <typename CharT, typename Traits, typename Alloc>
2969NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const basic_string_view<CharT, Traits>& lhs,
2970 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2971 return 0 < rhs.compare(lhs);
2972}
2973template <typename CharT, typename Traits, typename Alloc>
2974NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<(const basic_string<CharT, Traits, Alloc>& lhs,
2975 const basic_string_view<CharT, Traits>& rhs) noexcept {
2976 return lhs.compare(rhs) < 0;
2977}
2978
2979template <typename CharT, typename Traits, typename Alloc>
2980NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const CharT* const lhs,
2981 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2982 return rhs < lhs;
2983}
2984template <typename CharT, typename Traits, typename Alloc>
2985NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const basic_string<CharT, Traits, Alloc>& lhs,
2986 const CharT* const rhs) noexcept {
2987 return rhs < lhs;
2988}
2989template <typename CharT, typename Traits, typename Alloc>
2990NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const basic_string_view<CharT, Traits>& lhs,
2991 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
2992 return rhs < lhs;
2993}
2994template <typename CharT, typename Traits, typename Alloc>
2995NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>(const basic_string<CharT, Traits, Alloc>& lhs,
2996 const basic_string_view<CharT, Traits>& rhs) noexcept {
2997 return rhs < lhs;
2998}
2999
3000template <typename CharT, typename Traits, typename Alloc>
3001NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const CharT* const lhs,
3002 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3003 return !(lhs > rhs);
3004}
3005template <typename CharT, typename Traits, typename Alloc>
3006NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const basic_string<CharT, Traits, Alloc>& lhs,
3007 const CharT* const rhs) noexcept {
3008 return !(lhs > rhs);
3009}
3010template <typename CharT, typename Traits, typename Alloc>
3011NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const basic_string_view<CharT, Traits>& lhs,
3012 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3013 return !(lhs > rhs);
3014}
3015template <typename CharT, typename Traits, typename Alloc>
3016NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator<=(const basic_string<CharT, Traits, Alloc>& lhs,
3017 const basic_string_view<CharT, Traits>& rhs) noexcept {
3018 return !(lhs > rhs);
3019}
3020
3021template <typename CharT, typename Traits, typename Alloc>
3022NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const CharT* const lhs,
3023 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3024 return !(rhs < lhs);
3025}
3026template <typename CharT, typename Traits, typename Alloc>
3027NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const basic_string<CharT, Traits, Alloc>& lhs,
3028 const CharT* const rhs) noexcept {
3029 return !(rhs < lhs);
3030}
3031template <typename CharT, typename Traits, typename Alloc>
3032NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const basic_string_view<CharT, Traits>& lhs,
3033 const basic_string<CharT, Traits, Alloc>& rhs) noexcept {
3034 return !(rhs < lhs);
3035}
3036template <typename CharT, typename Traits, typename Alloc>
3037NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool operator>=(const basic_string<CharT, Traits, Alloc>& lhs,
3038 const basic_string_view<CharT, Traits>& rhs) noexcept {
3039 return !(rhs < lhs);
3040}
3041
3042#ifndef NEFORCE_STANDARD_17
3043# ifdef NEFORCE_USING_SSO
3044template <typename CharT, typename Traits, typename Alloc>
3046template <typename CharT, typename Traits, typename Alloc>
3048template <typename CharT, typename Traits, typename Alloc>
3050template <typename CharT, typename Traits, typename Alloc>
3052# endif
3053template <typename CharT, typename Traits, typename Alloc>
3055#endif
3056
3057
3058#ifndef NEFORCE_COMPILER_CLANG_CL
3059extern template class basic_string<char>;
3060extern template class basic_string<wchar_t>;
3061# ifdef NEFORCE_STANDARD_20
3062extern template class basic_string<char8_t>;
3063# endif
3064extern template class basic_string<char16_t>;
3065extern template class basic_string<char32_t>;
3066#endif
3067 // String
3069
3070NEFORCE_END_NAMESPACE__
3071#endif // NEFORCE_CORE_STRING_BASIC_STRING_HPP__
分配器特性
基本字符串视图模板
constexpr int compare(const basic_string_view view) const noexcept
比较字符串视图
基础字符串模板
Traits traits_type
字符特征类型
constexpr bool contains(view_type view) const noexcept
检查是否包含字符串视图
constexpr bool starts_with(view_type view) const noexcept
检查是否以字符串视图开头
CharT * pointer
指针类型
constexpr const_reverse_iterator rbegin() const noexcept
获取常量反向起始迭代器
constexpr basic_string & append(basic_string &&other, size_type position, size_type n)
追加移动字符串的子串
constexpr basic_string & append(const basic_string &other, size_type position)
追加另一个字符串的子串
constexpr bool empty() const noexcept
检查是否为空
constexpr basic_string & operator+=(basic_string &&other)
追加移动字符串
constexpr size_type find_last_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找最后一个出现在字符串视图中的字符
constexpr basic_string(std::initializer_list< value_type > ilist)
从初始化列表构造
constexpr basic_string & operator+=(const_pointer str)
追加C风格字符串
constexpr size_type find_first_not_of(const view_type &view, const size_type off=0) const noexcept
查找第一个不在字符串视图中的字符
constexpr size_type size() const noexcept
获取字符数
constexpr basic_string & replace(iterator first, iterator last, const size_type n, const value_type value)
替换迭代器范围为多个相同字符
constexpr const_reference front() const noexcept
常量访问第一个字符
constexpr size_type rfind(const basic_string &other, const size_type off=npos) const noexcept
从后向前查找子串
constexpr size_type find_last_of(const CharT value, const size_type off=npos) const noexcept
查找最后一个等于指定字符的位置
constexpr const_reverse_iterator crend() const noexcept
获取常量反向结束迭代器
constexpr size_type rfind(const view_type &view, const size_type off=npos) const noexcept
从后向前查找字符串视图
constexpr basic_string & append(basic_string &&other, size_type position)
追加移动字符串的子串
constexpr basic_string & trim() noexcept
去除两侧空白字符
constexpr basic_string & trim_left() noexcept
去除左侧空白字符
constexpr size_type find_first_of(const view_type &view, const size_type off=0) const noexcept
查找第一个出现在字符串视图中的字符
constexpr basic_string(size_type n, value_type value)
构造函数,指定大小和填充字符
constexpr bool ends_with(view_type view) const noexcept
检查是否以字符串视图结尾
constexpr int compare_ignore_case(const_pointer str) const noexcept
忽略大小写比较另一个字符串
constexpr const_pointer data() const noexcept
获取常量数据指针
constexpr basic_string & assign(const view_type &view)
赋值字符串视图
constexpr basic_string & append(const_pointer str, size_type n)
追加字符数组的指定长度
constexpr basic_string & append(size_type n, value_type value)
追加多个相同字符
constexpr basic_string & append(basic_string &&other)
追加移动字符串
ptrdiff_t difference_type
差值类型
constexpr size_type find_first_of(const CharT value, const size_type off=0) const noexcept
查找第一个等于指定字符的位置
CharT & reference
引用类型
constexpr basic_string(size_type n, int64_t value)
构造函数,指定大小和64位整数值
constexpr size_type find(const CharT value, const size_type n=0) const noexcept
查找字符
constexpr basic_string & trim_right() noexcept
去除右侧空白字符
constexpr basic_string(size_type n)
构造函数,指定大小
constexpr basic_string & replace(const size_type position, const size_type n, const basic_string &other)
替换子串为另一个字符串
constexpr bool contains(const_pointer str) const noexcept
检查是否包含C风格字符串
const CharT * const_pointer
常量指针类型
constexpr bool ends_with(const basic_string &other) const noexcept
检查是否以另一个字符串结尾
constexpr size_type find_first_not_of(const basic_string &other, const size_type off=0) const noexcept
查找第一个不在字符集合中的字符
constexpr void resize(size_type n, value_type value)
调整大小
constexpr basic_string & assign(Iterator first, Iterator last)
赋值迭代器范围
constexpr basic_string(view_type view)
从字符串视图构造
constexpr basic_string & uppercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_uppercase< CharT >)))
转换为大写
constexpr basic_string & assign(basic_string &&other)
赋值移动字符串
constexpr basic_string(const basic_string &other)
拷贝构造函数
constexpr basic_string & lowercase() noexcept(noexcept(_NEFORCE transform(begin(), end(), begin(), _NEFORCE to_lowercase< CharT >)))
转换为小写
constexpr iterator insert(iterator position, value_type value)
插入单个字符
constexpr size_type find_first_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 & operator+=(std::initializer_list< value_type > ilist)
追加初始化列表
constexpr size_type capacity() const noexcept
获取容量
constexpr bool equal_to(const CharT *str) const noexcept
与C风格字符串相等比较
constexpr basic_string head(const size_type count=npos) const
获取头部子串
constexpr void resize(const size_type n)
调整大小(默认填充0)
constexpr reference operator[](const size_type n) noexcept
下标访问操作符
constexpr basic_string & trim_right_if(Pred pred)
根据谓词去除右侧字符
constexpr int compare(const basic_string &other) const noexcept
比较另一个字符串
constexpr basic_string & assign(const_pointer str)
赋值C风格字符串
constexpr size_type find_first_not_of(const CharT *str, const size_type off=0) const noexcept
查找第一个不在C风格字符串中的字符
constexpr size_type find(const view_type &view, const size_type off, const size_type count) const noexcept
查找指定长度的字符串视图
basic_string_view< CharT, Traits > view_type
字符串视图类型
constexpr const_iterator cbegin() const noexcept
获取常量起始迭代器
constexpr size_type find_last_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找最后一个出现在指定字符数组中的字符
constexpr basic_string & trim_if(Predicate pred)
根据谓词去除两侧字符
constexpr size_type count(value_type value, const size_type position=0) const noexcept
constexpr ~basic_string()
析构函数
constexpr pointer data() 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 size_type find_first_not_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找第一个不在字符串视图中的字符
constexpr basic_string substr(const size_type off=0, const size_type count=npos) const
获取子串
constexpr reference back() noexcept
访问最后一个字符
constexpr void push_back(value_type value)
在末尾插入字符
constexpr const_reference at(const size_type n) const noexcept
带边界检查的常量访问
constexpr const_iterator end() const noexcept
获取常量结束迭代器
constexpr void reverse() noexcept
反转字符串
constexpr void shrink_to_fit()
收缩容量以适应当前大小
constexpr size_type find_last_of(const CharT *str, const size_type off=npos) const noexcept
查找最后一个出现在C风格字符串中的字符
constexpr basic_string(const basic_string &other, size_type position)
从子串构造
constexpr const_reverse_iterator rend() const noexcept
获取常量反向结束迭代器
constexpr basic_string & erase(size_type position=0, size_type n=npos) noexcept
删除指定范围内的字符
constexpr int compare(const size_type off, const size_type n, const CharT *str) const
比较子串与C风格字符串
constexpr basic_string & operator=(std::initializer_list< value_type > ilist)
初始化列表赋值运算符
constexpr bool equal_to(const basic_string &other) const noexcept
相等比较
constexpr basic_string & assign(std::initializer_list< value_type > ilist)
赋值初始化列表
constexpr int compare(const CharT *str) const noexcept
比较C风格字符串
constexpr const_reference operator[](const size_type n) const noexcept
常量下标访问操作符
constexpr int compare(const size_type off, const size_type n, const CharT *str, size_type count) const
比较子串与指定长度的字符数组
constexpr size_type find_last_not_of(const CharT *str, const size_type off=npos) const noexcept
查找最后一个不在C风格字符串中的字符
constexpr basic_string & replace(iterator first, iterator last, Iterator first2, Iterator last2)
替换迭代器范围为另一个迭代器范围
constexpr bool starts_with(const basic_string &other) const noexcept
检查是否以另一个字符串开头
constexpr view_type view(const size_type off, size_type count=npos) const noexcept
获取子串视图
constexpr size_type find_last_not_of(const CharT value, const size_type off=npos) const noexcept
查找最后一个不等于指定字符的位置
constexpr reference at(const size_type n) noexcept
带边界检查的访问
constexpr basic_string & replace(const size_type position, const size_type n, const_pointer str)
替换子串为C风格字符串
constexpr basic_string & append(Iterator first, Iterator last)
追加迭代器范围
constexpr iterator erase(iterator first, const size_type n) noexcept
删除指定数量的字符
constexpr bool ends_with(const_pointer str) const noexcept
检查是否以C风格字符串结尾
constexpr bool contains(value_type value) const noexcept
检查是否包含指定字符
constexpr basic_string & append(std::initializer_list< value_type > ilist)
追加初始化列表
constexpr void pop_back() noexcept
删除末尾字符
constexpr iterator end() noexcept
获取结束迭代器
constexpr bool contains(const basic_string &other) const noexcept
检查是否包含另一个字符串
constexpr basic_string(size_type n, int32_t value)
构造函数,指定大小和32位整数值
constexpr bool equal_to(const view_type view) const noexcept
与字符串视图相等比较
constexpr size_t to_hash() const noexcept
计算哈希值
constexpr basic_string & append(const basic_string &other)
追加另一个字符串
constexpr basic_string tail(const size_type off=0) const
获取尾部子串
constexpr const_reference back() const noexcept
常量访问最后一个字符
constexpr void clear() noexcept
清空字符串
constexpr basic_string & assign(const size_type n, value_type value)
赋值多个相同字符
constexpr basic_string & append(view_type view, size_type n)
追加字符串视图的指定长度
constexpr const_reverse_iterator crbegin() const noexcept
获取常量反向起始迭代器
constexpr size_type rfind(const CharT *str, const size_type off=npos) const noexcept
从后向前查找C风格字符串
constexpr size_type max_size() const noexcept
获取最大可能大小
constexpr iterator insert(iterator position, Iterator first, Iterator last)
插入迭代器范围
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_if(Pred pred)
根据谓词去除左侧字符
constexpr size_type find_last_not_of(const view_type &view, const size_type off, const size_type n) const noexcept
查找最后一个不在字符串视图中的字符
constexpr basic_string(view_type view, const size_type n)
从字符串视图构造(指定长度)
constexpr basic_string & replace(const size_type position, const size_type n1, const size_type n2, const value_type value)
替换子串为多个相同字符
constexpr void reserve(const size_type n)
预留容量
constexpr size_type copy(pointer dest, const size_type count, size_type position=0) const
复制字符到目标缓冲区
constexpr basic_string & append(const_pointer str)
追加C风格字符串
constexpr basic_string(const basic_string &other, size_type position, size_type n)
从子串构造(指定长度)
basic_string_iterator< false, basic_string > iterator
迭代器类型
constexpr size_type find_last_not_of(const view_type &view, const size_type off=npos) const noexcept
查找最后一个不在字符串视图中的字符
constexpr int compare(const view_type &view) const noexcept
比较字符串视图
constexpr iterator erase(iterator first, iterator last) noexcept
删除迭代器范围
constexpr reference front() noexcept
访问第一个字符
constexpr size_type find_first_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找第一个出现在指定字符数组中的字符
constexpr basic_string & insert(size_type position, size_type n, value_type value)
在指定位置插入多个相同字符
constexpr basic_string(Iterator first, Iterator last)
从迭代器范围构造
constexpr basic_string & operator=(basic_string &&other) noexcept
移动赋值运算符
constexpr basic_string & operator+=(const basic_string &other)
追加另一个字符串
size_t size_type
大小类型
constexpr basic_string & replace(const size_type position, const size_type n1, const_pointer str, const size_type n2)
替换子串为指定长度的字符数组
constexpr basic_string(basic_string &&other) noexcept
移动构造函数
constexpr size_type find_first_of(const basic_string &other, const size_type off=0) const noexcept
查找第一个出现在字符集合中的字符
constexpr int compare(const size_type off, const size_type n, const basic_string &other) const
比较子串与另一个字符串
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_first_of(const CharT *str, const size_type off=0) const noexcept
查找第一个出现在C风格字符串中的字符
constexpr size_type rfind(const CharT *str, const size_type off, const size_type n) const noexcept
从后向前查找指定长度的子串
constexpr size_type find_last_not_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找最后一个不在指定字符数组中的字符
constexpr size_type find_last_not_of(const basic_string &other, const size_type off=npos) const noexcept
查找最后一个不在字符集合中的字符
constexpr bool starts_with(const value_type value) const noexcept
检查是否以指定字符开头
const CharT & const_reference
常量引用类型
constexpr int compare_ignore_case(const basic_string &str) const noexcept
忽略大小写与C风格字符串三路比较
constexpr basic_string & operator+=(const value_type value)
追加单个字符
constexpr basic_string & append(value_type value)
追加单个字符
constexpr size_type length() const noexcept
获取字符串长度
constexpr size_type find(const CharT *str, const size_type off=0) const noexcept
查找C风格字符串
constexpr basic_string & operator=(view_type view)
字符串视图赋值运算符
constexpr size_type find(const view_type &view, const size_type off=0) const noexcept
查找字符串视图
constexpr basic_string & replace(iterator first, iterator last, const_pointer str, const size_type n)
替换迭代器范围为指定长度的字符数组
constexpr size_type find(const basic_string &other, const size_type n=0) const noexcept
查找子串
constexpr basic_string & assign(const basic_string &other)
赋值另一个字符串
constexpr basic_string(const_pointer str)
从C风格字符串构造
basic_string_iterator< true, basic_string > const_iterator
常量迭代器类型
constexpr basic_string & replace(iterator first, iterator last, const_pointer str)
替换迭代器范围为C风格字符串
constexpr size_type find(const CharT *str, const size_type off, const size_type count) const noexcept
查找指定长度的子串
constexpr basic_string & operator=(const_pointer str)
C风格字符串赋值运算符
constexpr basic_string & assign(const_pointer str, const size_type n)
赋值字符数组的指定长度
constexpr view_type view() const noexcept
constexpr const_iterator begin() const noexcept
获取常量起始迭代器
CharT value_type
值类型
constexpr size_type rfind(const CharT value, const size_type n=npos) const noexcept
从后向前查找字符
constexpr basic_string & operator=(const basic_string &other)
拷贝赋值运算符
constexpr int compare_ignore_case(const view_type view) const noexcept
忽略大小写三路比较
static constexpr size_type npos
constexpr size_type find_first_not_of(const CharT value, const size_type off=0) const noexcept
查找第一个不等于指定字符的位置
constexpr basic_string & operator+=(view_type view)
追加字符串视图
constexpr basic_string & append(view_type view)
追加字符串视图
constexpr basic_string & append(const basic_string &other, size_type position, size_type n)
追加另一个字符串的子串
constexpr reverse_iterator rend() noexcept
获取反向结束迭代器
constexpr const_iterator cend() const noexcept
获取常量结束迭代器
constexpr bool ends_with(value_type value) const noexcept
检查是否以指定字符结尾
constexpr void swap(basic_string &other) noexcept
交换两个字符串
constexpr size_type find_last_of(const view_type &view, const size_type off=npos) const noexcept
查找最后一个出现在字符串视图中的字符
constexpr iterator erase(iterator position) noexcept
删除指定位置的字符
constexpr basic_string repeat(size_type n) const noexcept
重复当前字符串n次
constexpr bool starts_with(const_pointer str) const noexcept
检查是否以C风格字符串开头
constexpr iterator begin() noexcept
获取起始迭代器
constexpr size_type find_first_not_of(const CharT *str, const size_type off, const size_type n) const noexcept
查找第一个不在指定字符数组中的字符
constexpr basic_string & replace(iterator first, iterator last, const basic_string &other)
替换迭代器范围为另一个字符串
constexpr reverse_iterator rbegin() noexcept
获取反向起始迭代器
_NEFORCE reverse_iterator< const_iterator > const_reverse_iterator
常量反向迭代器类型
Alloc allocator_type
分配器类型
constexpr size_type rfind(const view_type &view, const size_type off, const size_type count) const noexcept
从后向前查找指定长度的字符串视图
constexpr basic_string()
默认构造函数
_NEFORCE reverse_iterator< iterator > reverse_iterator
反向迭代器类型
压缩对实现
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_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_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_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_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 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 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 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(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 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_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 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 bool is_space(const CharT c) noexcept
检查字符是否为空白字符
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
constexpr T clamp(const T &value, const T &lower, const T &upper, Compare comp) noexcept(noexcept(comp(value, lower)))
将值限制在指定范围内
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
long long int64_t
64位有符号整数类型
int int32_t
32位有符号整数类型
constexpr size_t FNV_hash_string(const CharT *str, const size_t len) noexcept
字符串类型的FNV哈希
constexpr void destroy(T *pointer) noexcept(is_nothrow_destructible_v< T >)
销毁单个对象
constexpr bool is_iter_v
检查类型是否为迭代器
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
constexpr iter_difference_t< Iterator > distance(Iterator first, Iterator last)
计算两个迭代器之间的距离
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 Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
constexpr void iter_swap(Iterator1 a, Iterator2 b) noexcept(noexcept(_NEFORCE swap(*a, *b)))
交换迭代器指向的元素
void swap()=delete
删除无参数的swap重载
constexpr bool is_allocator_v
is_allocator的便捷变量模板
constexpr decltype(auto) data(Container &cont) noexcept(noexcept(cont.data()))
获取容器的底层数据指针
constexpr bool is_trivial_v
is_trivial的便捷变量模板
typename conditional< Test, T1, T2 >::type conditional_t
conditional的便捷别名
constexpr bool is_same_v
is_same的便捷变量模板
constexpr Iterator2 uninitialized_copy(Iterator1 first, Iterator1 last, Iterator2 result)
复制元素到未初始化内存
constexpr Iterator2 uninitialized_copy_n(Iterator1 first, size_t count, Iterator2 result)
复制指定数量的元素到未初始化内存
移位和修改算法
标准分配器
字符串视图类型别名和实用函数
typename real_size< Alloc, difference_type >::type size_type
大小类型
static constexpr int compare(const char_type *lhs, const char_type *rhs, size_t count) noexcept
比较两个字符序列
static constexpr char_type * assign(char_type *const str, const size_t count, const char_type chr) noexcept
将字符序列中的每个字符设置为指定值
static constexpr bool eq(const char_type lhs, const char_type rhs) noexcept
相等比较
static constexpr char_type * move(char_type *dest, const char_type *srcs, const size_t count) noexcept
移动字符序列
static constexpr char_type * copy(char_type *dest, const char_type *srcs, const size_t count) noexcept
复制字符序列
static constexpr size_t length(const char_type *str) noexcept
计算字符串长度
conditional_t< IsConst, typename container_type::const_pointer, typename container_type::pointer > pointer
指针类型
constexpr void advance(difference_type off) noexcept
前进操作
constexpr const container_type * container() const noexcept
获取关联容器
conditional_t< IsConst, typename container_type::const_reference, typename container_type::reference > reference
引用类型
constexpr reference dereference() const noexcept
解引用操作
contiguous_iterator_tag iterator_category
迭代器类别
constexpr void decrement() noexcept
递减操作
constexpr bool equal_to(const basic_string_iterator &rhs) const noexcept
相等比较
typename container_type::size_type size_type
大小类型
constexpr pointer base() const noexcept
获取底层指针
constexpr difference_type distance_to(const basic_string_iterator &other) const noexcept
计算距离操作
constexpr void increment() noexcept
递增操作
typename container_type::value_type value_type
值类型
String container_type
容器类型
constexpr bool less_than(const basic_string_iterator &rhs) const noexcept
小于比较
constexpr reference operator[](difference_type n) const noexcept
下标访问操作符
typename container_type::difference_type difference_type
差值类型
压缩对主模板,使用EBCO优化
constexpr compressed_pair & get_base() &noexcept
获取基类引用
连续迭代器标签
默认构造标签
通用接口,同时具备可比较和可哈希功能
constexpr bool operator<=(const T &rhs) const noexcept(noexcept(!(rhs.less_than(derived()))))
小于等于比较运算符
constexpr bool operator>=(const T &rhs) const noexcept(noexcept(!(derived().less_than(rhs))))
大于等于比较运算符
constexpr bool operator==(const T &rhs) const noexcept(noexcept(derived().equal_to(rhs)))
相等比较运算符
constexpr bool operator!=(const T &rhs) const noexcept(noexcept(!(derived().equal_to(rhs))))
不等比较运算符
constexpr bool operator>(const T &rhs) const noexcept(noexcept(rhs.less_than(derived())))
大于比较运算符
constexpr bool operator<(const T &rhs) const noexcept(noexcept(derived().less_than(rhs)))
小于比较运算符
迭代器接口模板
未初始化内存操作