78 using allocator_traits = std::allocator_traits<Allocator>;
81 using value_type =
typename traits_type::char_type;
83 using size_type =
typename allocator_traits::size_type;
84 using difference_type =
typename allocator_traits::difference_type;
85 using reference = value_type&;
86 using const_reference =
const value_type&;
87 using pointer =
typename allocator_traits::pointer;
88 using const_pointer =
typename allocator_traits::const_pointer;
89 using iterator = pointer;
90 using const_iterator = const_pointer;
91 using reverse_iterator = std::reverse_iterator<iterator>;
92 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
93 using sview_type = std::basic_string_view<Char, Traits>;
95 constexpr static size_type npos =
static_cast<size_t>(-1);
98 constexpr static auto _terminator = value_type();
100 PLUGIFY_NO_UNIQUE_ADDRESS
105#if PLUGIFY_COMPILER_CLANG
108#elif PLUGIFY_COMPILER_GCC
110#elif PLUGIFY_COMPILER_MSVC
115 template<
typename CharT, std::
size_t = sizeof(CharT)>
120 template<
typename CharT>
121 struct padding<
CharT, 1> {
128 struct sso_size : padding<value_type> {
129 PLUGIFY_PACK(
struct {
135 static constexpr int char_bit = std::numeric_limits<uint8_t>::digits + std::numeric_limits<uint8_t>::is_signed;
136 static_assert(char_bit == 8,
"assumes an 8 bit byte.");
141 PLUGIFY_PACK(
struct {
142 size_type cap :
sizeof(size_type) * char_bit - 1;
143 size_type is_long : 1;
147 static constexpr size_type min_cap = (
sizeof(long_data) - 1) /
sizeof(value_type) > 2 ? (
sizeof(long_data) - 1) /
sizeof(value_type) : 2;
150 value_type data[min_cap];
156 static_assert(
sizeof(short_data) == (
sizeof(value_type) * (min_cap + 1)),
"short has an unexpected size.");
157 static_assert(
sizeof(short_data) ==
sizeof(long_data),
"short and long layout structures must be the same size");
164 constexpr static bool fits_in_sso(size_type size)
noexcept {
165 return size < min_cap;
168 constexpr void long_init()
noexcept {
170 set_long_data(
nullptr);
175 constexpr void short_init()
noexcept {
180 constexpr void default_init(size_type size)
noexcept {
181 if (fits_in_sso(size))
187 constexpr auto& get_long_data()
noexcept {
188 return _storage._long.data;
191 constexpr const auto& get_long_data()
const noexcept {
192 return _storage._long.data;
195 constexpr auto& get_short_data()
noexcept {
196 return _storage._short.data;
199 constexpr const auto& get_short_data()
const noexcept {
200 return _storage._short.data;
203 constexpr void set_short_size(size_type size)
noexcept {
204 _storage._short.size.spare_size = min_cap - (size & 0x7F);
207 constexpr size_type get_short_size()
const noexcept {
208 return min_cap - _storage._short.size.spare_size;
211 constexpr void set_long_size(size_type size)
noexcept {
212 _storage._long.size = size;
215 constexpr size_type get_long_size()
const noexcept {
216 return _storage._long.size;
219 constexpr void set_long_cap(size_type cap)
noexcept {
220 _storage._long.cap = (cap & 0x7FFFFFFFFFFFFFFF);
223 constexpr size_type get_long_cap()
const noexcept {
224 return _storage._long.cap;
227 constexpr void set_long_data(value_type* data)
noexcept {
228 _storage._long.data = data;
231 constexpr bool is_long()
const noexcept {
232 return _storage._long.is_long ==
true;
235 constexpr void set_long(
bool is_long)
noexcept {
236 _storage._long.is_long = is_long;
239 constexpr void set_size(size_type size)
noexcept {
243 set_short_size(size);
246 constexpr sview_type view()
const noexcept {
247 return sview_type(data(), size());
254 auto old_len = get_long_size();
272 constexpr void deallocate() {
274 if (
auto&
buffer = get_long_data();
buffer !=
nullptr) {
275 allocator_traits::deallocate(_allocator,
buffer, get_long_cap() + 1);
281 constexpr void grow_to(size_type
new_cap) {
282 if (is_long() ==
true) {
287 auto buffer = allocator_traits::allocate(_allocator,
new_cap + 1);
288 auto len = get_short_size();
290 Traits::copy(
buffer, get_short_data(),
len);
291 Traits::assign(
buffer[
len], _terminator);
299 constexpr void null_terminate() {
303 Traits::assign(
buffer[size()], _terminator);
306 constexpr bool addr_in_range(const_pointer ptr)
const noexcept {
307 if (std::is_constant_evaluated())
310 return data() <= ptr && ptr <= data() + size();
314 constexpr void internal_replace_impl(
const F&
func, size_type pos, size_type
oldcount, size_type
count) {
315 auto cap = capacity();
332 constexpr void internal_replace(size_type pos, const_pointer
str, size_type
oldcount, size_type
count) {
333 if (addr_in_range(
str)) {
340 constexpr void internal_replace(size_type pos, value_type
ch, size_type
oldcount, size_type
count) {
341 internal_replace_impl([&]() { Traits::assign(data() + pos,
count,
ch); }, pos,
oldcount,
count);
345 constexpr void internal_insert_impl(
const F&
func, size_type pos, size_type
count) {
349 auto cap = capacity();
356 Traits::move(data() + pos +
count, data() + pos,
sz - pos);
363 constexpr void internal_insert(size_type pos, const_pointer
str, size_type
count) {
364 if (addr_in_range(
str)) {
366 internal_insert_impl([&]() { Traits::copy(data() + pos,
rstr.data(),
count); }, pos,
count);
368 internal_insert_impl([&]() { Traits::copy(data() + pos,
str,
count); }, pos,
count);
371 constexpr void internal_insert(size_type pos, value_type
ch, size_type
count) {
372 internal_insert_impl([&]() { Traits::assign(data() + pos,
count,
ch); }, pos,
count);
376 constexpr void internal_append_impl(
const F&
func, size_type
count) {
380 auto cap = capacity();
392 constexpr void internal_append(const_pointer
str, size_type
count) {
393 if (addr_in_range(
str)) {
395 internal_append_impl([&](size_type pos) { Traits::copy(data() + pos,
rstr.data(),
count); },
count);
397 internal_append_impl([&](size_type pos) { Traits::copy(data() + pos,
str,
count); },
count);
400 constexpr void internal_append(value_type
ch, size_type
count) {
401 internal_append_impl([&](size_type pos) { Traits::assign(data() + pos,
count,
ch); },
count);
405 constexpr void internal_assign_impl(
const F&
func, size_type size,
bool copy_old) {
406 if (fits_in_sso(size)) {
407 if (is_long() ==
true) {
412 set_short_size(size);
413 func(get_short_data());
416 if (is_long() ==
false)
418 if (get_long_cap() < size)
421 func(get_long_data());
427 constexpr void internal_assign(const_pointer
str, size_type size,
bool copy_old =
false) {
428 if (addr_in_range(
str)) {
430 internal_assign_impl([&](
auto data) { Traits::copy(data,
rstr.data(), size); }, size,
copy_old);
432 internal_assign_impl([&](
auto data) { Traits::copy(data,
str, size); }, size,
copy_old);
435 constexpr void internal_assign(value_type
ch, size_type
count,
bool copy_old =
false) {
442 PLUGIFY_ASSERT(size <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
443 if (fits_in_sso(size))
447 reallocate(size,
false);
452 constexpr basic_string()
noexcept(std::is_nothrow_default_constructible<Allocator>::value)
462 PLUGIFY_ASSERT(
count <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
468 PLUGIFY_ASSERT(pos <=
str.size(),
"plg::basic_string::basic_string(): pos out of range", std::out_of_range);
470 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
471 internal_assign(
str.data() + pos,
len);
478 PLUGIFY_ASSERT(
count <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
485 template<std::input_iterator InputIterator>
489 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
490 internal_assign(const_pointer(
first),
len);
496 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
497 internal_assign(
str.data(),
len);
503 : _allocator(std::move(
str._allocator)), _storage(std::move(
str._storage)) {
509 if constexpr (allocator_traits::is_always_equal::value) {
510 std::swap(_storage,
str._storage);
512 if (!
str.is_long() || get_allocator() ==
str.get_allocator()) {
513 std::swap(_storage,
str._storage);
515 internal_assign(
str.data(),
str.size());
525 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
526 internal_assign(const_pointer(
list.begin()),
len);
529 template<
typename Type>
530 requires (std::is_convertible_v<const Type&, sview_type>)
533 auto sv = sview_type(
t);
534 PLUGIFY_ASSERT(pos <=
sv.length(),
"plg::basic_string::basic_string(): pos out of range", std::out_of_range);
537 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
538 internal_assign(
ssv.data(),
len);
541 template<
typename Type>
542 requires (std::is_convertible_v<const Type&, sview_type> &&
543 !std::is_convertible_v<const Type&, const Char*>)
547 auto len =
sv.length();
548 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::basic_string(): constructed string size would exceed max_size()", std::length_error);
549 internal_assign(
sv.data(),
len);
554 PLUGIFY_ASSERT(pos <=
str.size(),
"plg::basic_string::basic_string(): pos out of range", std::out_of_range);
561#if __cplusplus > 202002L
565#if PLUGIFY_STRING_CONTAINERS_RANGES
566 template<detail::
string_compatible_range<Char> Range>
580 allocator_traits::propagate_on_container_move_assignment::value ||
581 allocator_traits::is_always_equal::value) {
582 return assign(std::move(
str));
586 return assign(
str, Traits::length(
str));
590 return assign(std::addressof(
ch), 1);
594 return assign(
list.begin(),
list.size());
597 template<
typename Type>
598 requires (std::is_convertible_v<const Type&, sview_type> &&
599 !std::is_convertible_v<const Type&, const Char*>)
605#if __cplusplus > 202002L
606 constexpr basic_string& operator=(std::nullptr_t) =
delete;
610 PLUGIFY_ASSERT(
count <= max_size(),
"plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error);
616 PLUGIFY_ASSERT(pos <=
str.size(),
"plg::basic_string::assign(): pos out of range", std::out_of_range);
617 internal_assign(
str.data(), std::min(
count,
str.size() - pos));
625 if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) {
626 if constexpr (!allocator_traits::is_always_equal::value) {
627 if (get_allocator() !=
str.get_allocator()) {
632 _allocator =
str._allocator;
635 internal_assign(
str.data(),
str.size());
640 allocator_traits::propagate_on_container_move_assignment::value ||
641 allocator_traits::is_always_equal::value) {
645 if constexpr (allocator_traits::propagate_on_container_move_assignment::value) {
646 if constexpr (!allocator_traits::is_always_equal::value) {
647 if (get_allocator() !=
str.get_allocator()) {
652 _allocator = std::move(
str._allocator);
655 if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) {
658 std::swap(_storage,
str._storage);
660 if (get_allocator() ==
str.get_allocator()) {
663 std::swap(_storage,
str._storage);
665 internal_assign(
str.data(),
str.size());
673 PLUGIFY_ASSERT(
count <= max_size(),
"plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error);
679 return assign(
str, Traits::length(
str));
682 template<std::input_iterator InputIterator>
684 auto len =
static_cast<size_type
>(std::distance(
first,
last));
685 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error);
686 internal_assign(const_pointer(
first),
len);
692 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error);
693 internal_assign(const_pointer(
list.begin()),
len);
697 template<
typename Type>
698 requires (std::is_convertible_v<const Type&, sview_type> &&
699 !std::is_convertible_v<const Type&, const Char*>)
702 return assign(
sv.data(),
sv.length());
705 template<
typename Type>
706 requires (std::is_convertible_v<const Type&, sview_type> &&
707 !std::is_convertible_v<const Type&, const Char*>)
709 auto sv = sview_type(
t).substr(pos,
count);
710 auto len =
sv.length();
711 PLUGIFY_ASSERT(
len <= max_size(),
"plg::basic_string::assign(): resulted string size would exceed max_size()", std::length_error);
712 return assign(
sv.data(),
len);
715#if PLUGIFY_STRING_CONTAINERS_RANGES
716 template<detail::
string_compatible_range<Char> Range>
718 auto str =
basic_string(std::from_range, std::forward<Range>(range), _allocator);
719 PLUGIFY_ASSERT(
str.size() <= max_size(),
"plg::basic_string::assign_range(): resulted string size would exceed max_size()", std::length_error);
720 return assign(std::move(
str));
728 constexpr reference operator[](size_type pos) {
732 constexpr const_reference operator[](size_type pos)
const {
736 constexpr reference at(size_type pos) {
737 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::at(): pos out of range", std::out_of_range);
741 constexpr const_reference at(size_type pos)
const {
742 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::at(): pos out of range", std::out_of_range);
746 constexpr reference front() {
747 PLUGIFY_ASSERT(!empty(),
"plg::basic_string::front(): vector is empty", std::length_error);
751 constexpr const_reference front()
const {
752 PLUGIFY_ASSERT(!empty(),
"plg::basic_string::front(): vector is empty", std::length_error);
756 constexpr reference back() {
757 PLUGIFY_ASSERT(!empty(),
"plg::basic_string::back(): vector is empty", std::length_error);
758 return data()[size() - 1];
761 constexpr const_reference back()
const {
762 PLUGIFY_ASSERT(!empty(),
"plg::basic_string::back(): vector is empty", std::length_error);
763 return data()[size() - 1];
766 constexpr const value_type* data()
const noexcept {
767 return is_long() ? get_long_data() : get_short_data();
770 constexpr value_type* data()
noexcept {
771 return is_long() ? get_long_data() : get_short_data();
774 constexpr const value_type* c_str()
const noexcept {
778 constexpr operator sview_type()
const noexcept {
782 constexpr iterator begin()
noexcept {
786 constexpr const_iterator begin()
const noexcept {
790 constexpr const_iterator cbegin()
const noexcept {
794 constexpr iterator end()
noexcept {
795 return data() + size();
798 constexpr const_iterator end()
const noexcept {
799 return data() + size();
802 constexpr const_iterator cend()
const noexcept {
803 return data() + size();
806 constexpr reverse_iterator rbegin()
noexcept {
807 return reverse_iterator(end());
810 constexpr const_reverse_iterator rbegin()
const noexcept {
811 return const_reverse_iterator(end());
814 constexpr const_reverse_iterator crbegin()
const noexcept {
815 return const_reverse_iterator(cend());
818 constexpr reverse_iterator rend()
noexcept {
819 return reverse_iterator(begin());
822 constexpr const_reverse_iterator rend()
const noexcept {
823 return const_reverse_iterator(begin());
826 constexpr const_reverse_iterator crend()
const noexcept {
827 return const_reverse_iterator(cbegin());
830 constexpr bool empty()
const noexcept {
834 constexpr size_type size()
const noexcept {
835 return is_long() ? get_long_size() : get_short_size();
838 constexpr size_type length()
const noexcept {
842 constexpr size_type max_size()
const noexcept {
849 return (allocator_traits::max_size(_allocator) - 1) / 2;
852 constexpr size_type capacity()
const noexcept {
853 return is_long() ? get_long_cap() : min_cap;
856 constexpr void reserve(size_type cap) {
857 PLUGIFY_ASSERT(cap <= max_size(),
"plg::basic_string::reserve(): allocated memory size would exceed max_size()", std::length_error);
858 if (cap <= capacity())
861 auto new_cap = std::max(cap, size());
872 constexpr void shrink_to_fit() {
873 if (is_long() ==
false)
876 reallocate(size(),
true);
879 constexpr void clear()
noexcept {
884 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
885 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::insert(): pos out of range", std::out_of_range);
886 insert(std::next(cbegin(), pos),
count,
ch);
891 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::insert(): pos out of range", std::out_of_range);
892 auto len = Traits::length(
str);
893 PLUGIFY_ASSERT(size() +
len <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
894 internal_insert(pos,
str,
len);
899 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
900 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::insert(): pos out of range", std::out_of_range);
906 PLUGIFY_ASSERT(size() +
str.size() <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
907 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::insert(): pos out of range", std::out_of_range);
908 internal_insert(pos, const_pointer(
str.data()),
str.size());
913 PLUGIFY_ASSERT(pos <= size() &&
pos_str <=
str.size(),
"plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range);
915 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
919 constexpr iterator insert(const_iterator pos, value_type
ch) {
920 return insert(pos, 1,
ch);
923 constexpr iterator insert(const_iterator pos, size_type
count, value_type
ch) {
924 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
925 auto spos = std::distance(cbegin(), pos);
927 return std::next(begin(),
spos);
930 template<std::input_iterator InputIterator>
932 auto spos = std::distance(cbegin(), pos);
933 auto len =
static_cast<size_type
>(std::distance(
first,
last));
934 PLUGIFY_ASSERT(size() +
len <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
936 return std::next(begin(),
spos);
939 constexpr iterator insert(const_iterator pos, std::initializer_list<value_type>
list) {
940 PLUGIFY_ASSERT(size() +
list.size() <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
941 auto spos = std::distance(cbegin(), pos);
942 internal_insert(
spos, const_pointer(
list.begin()),
list.size());
943 return std::next(begin(),
spos);
946 template<
typename Type>
947 requires (std::is_convertible_v<const Type&, sview_type> &&
948 !std::is_convertible_v<const Type&, const Char*>)
950 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::insert(): pos out of range", std::out_of_range);
952 PLUGIFY_ASSERT(size() +
sv.length() <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
953 internal_insert(pos, const_pointer(
sv.data()),
sv.length());
957 template<
typename Type>
958 requires (std::is_convertible_v<const Type&, sview_type> &&
959 !std::is_convertible_v<const Type&, const Char*>)
961 auto sv = sview_type(
t);
962 PLUGIFY_ASSERT(pos <= size() &&
pos_str <=
sv.length(),
"plg::basic_string::insert(): pos or pos_str out of range", std::out_of_range);
964 PLUGIFY_ASSERT(size() +
ssv.length() <= max_size(),
"plg::basic_string::insert(): resulted string size would exceed max_size()", std::length_error);
965 internal_insert(pos, const_pointer(
ssv.data()),
ssv.length());
969#if PLUGIFY_STRING_CONTAINERS_RANGES
970 template<detail::
string_compatible_range<Char> Range>
972 auto str =
basic_string(std::from_range, std::forward<Range>(range), _allocator);
973 PLUGIFY_ASSERT(size() +
str.size() <= max_size(),
"plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error);
974 return insert(pos - begin(),
str);
982 PLUGIFY_ASSERT(pos <=
sz,
"plg::basic_string::erase(): pos out of range", std::out_of_range);
997 constexpr iterator erase(const_iterator
position) {
998 auto pos = std::distance(cbegin(),
position);
1000 return begin() + pos;
1003 constexpr iterator erase(const_iterator
first, const_iterator
last) {
1004 auto pos = std::distance(cbegin(),
first);
1007 return begin() + pos;
1010 constexpr void push_back(value_type
ch) {
1011 PLUGIFY_ASSERT(size() + 1 <= max_size(),
"plg::basic_string::push_back(): resulted string size would exceed max_size()", std::length_error);
1015 constexpr void pop_back() {
1020 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1026 PLUGIFY_ASSERT(size() +
str.size() <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1027 internal_append(
str.data(),
str.size());
1032 PLUGIFY_ASSERT(pos <=
str.size(),
"plg::basic_string::append(): pos out of range", std::out_of_range);
1034 PLUGIFY_ASSERT(size() +
ssv.length() <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1035 internal_append(
ssv.data(),
ssv.length());
1040 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1046 auto len = Traits::length(
str);
1047 PLUGIFY_ASSERT(size() +
len <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1051 template<std::input_iterator InputIterator>
1053 auto len =
static_cast<size_type
>(std::distance(
first,
last));
1054 PLUGIFY_ASSERT(size() +
len <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1055 internal_append(const_pointer(
first),
len);
1060 PLUGIFY_ASSERT(size() +
list.size() <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1061 internal_append(const_pointer(
list.begin()),
list.size());
1065 template<
typename Type>
1066 requires (std::is_convertible_v<const Type&, sview_type> &&
1067 !std::is_convertible_v<const Type&, const Char*>)
1070 PLUGIFY_ASSERT(size() +
sv.length() <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1071 internal_append(
sv.data(),
sv.size());
1075 template<
typename Type>
1076 requires (std::is_convertible_v<const Type&, sview_type> &&
1077 !std::is_convertible_v<const Type&, const Char*>)
1080 PLUGIFY_ASSERT(pos <=
sv.length(),
"plg::basic_string::append(): pos out of range", std::out_of_range);
1082 PLUGIFY_ASSERT(size() +
ssv.length() <= max_size(),
"plg::basic_string::append(): resulted string size would exceed max_size()", std::length_error);
1083 internal_append(
ssv.data(),
ssv.length());
1087#if PLUGIFY_STRING_CONTAINERS_RANGES
1088 template<detail::
string_compatible_range<Char> Range>
1090 auto str =
basic_string(std::from_range, std::forward<Range>(range), _allocator);
1091 PLUGIFY_ASSERT(size() +
str.size() <= max_size(),
"plg::basic_string::insert_range(): resulted string size would exceed max_size()", std::length_error);
1109 constexpr basic_string& operator+=(std::initializer_list<value_type>
list) {
1110 return append(
list);
1113 template<
typename Type>
1114 requires (std::is_convertible_v<const Type&, sview_type> &&
1115 !std::is_convertible_v<const Type&, const Char*>)
1117 return append(sview_type(
t));
1121 return view().compare(
str.view());
1132 constexpr int compare(
const value_type*
str)
const {
1133 return view().compare(
str);
1136 constexpr int compare(size_type
pos1, size_type
count1,
const value_type*
str)
const {
1140 constexpr int compare(size_type
pos1, size_type
count1,
const value_type*
str, size_type
count2)
const {
1144 template<
typename Type>
1145 requires (std::is_convertible_v<const Type&, sview_type> &&
1146 !std::is_convertible_v<const Type&, const Char*>)
1147 constexpr int compare(
const Type&
t)
const noexcept(
noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>)) {
1148 return view().compare(sview_type(
t));
1151 template<
typename Type>
1152 requires (std::is_convertible_v<const Type&, sview_type> &&
1153 !std::is_convertible_v<const Type&, const Char*>)
1154 constexpr int compare(size_type
pos1, size_type
count1,
const Type&
t)
const {
1155 return view().compare(
pos1,
count1, sview_type(
t));
1158 template<
typename Type>
1159 requires (std::is_convertible_v<const Type&, sview_type> &&
1160 !std::is_convertible_v<const Type&, const Char*>)
1165 constexpr bool starts_with(sview_type
sv)
const noexcept {
1166 return view().starts_with(
sv);
1169 constexpr bool starts_with(
Char ch)
const noexcept {
1170 return view().starts_with(
ch);
1173 constexpr bool starts_with(
const Char*
str)
const {
1174 return view().starts_with(
str);
1177 constexpr bool ends_with(sview_type
sv)
const noexcept {
1178 return view().ends_with(
sv);
1181 constexpr bool ends_with(
Char ch)
const noexcept {
1182 return view().ends_with(
ch);
1185 constexpr bool ends_with(
const Char*
str)
const {
1186 return view().ends_with(
str);
1189 constexpr bool contains(sview_type
sv)
const noexcept {
1190 return view().contains(
sv);
1193 constexpr bool contains(
Char ch)
const noexcept {
1194 return view().contains(
ch);
1197 constexpr bool contains(
const Char*
str)
const {
1198 return view().contains(
str);
1202 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::replace(): pos out of range", std::out_of_range);
1207 auto pos = std::distance(cbegin(),
first);
1213 PLUGIFY_ASSERT(pos <= size() &&
pos2 <=
str.size(),
"plg::basic_string::replace(): pos or pos_str out of range", std::out_of_range);
1216 return replace(pos,
count,
ssv.data(),
ssv.length());
1219 template<std::input_iterator InputIterator>
1225 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::replace(): pos out of range", std::out_of_range);
1227 PLUGIFY_ASSERT(size() -
count +
count2 <= max_size(),
"plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error);
1233 auto pos = std::distance(cbegin(),
first);
1239 return replace(pos,
count,
str, Traits::length(
str));
1247 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::replace(): pos out of range", std::out_of_range);
1249 PLUGIFY_ASSERT(size() -
count +
count2 <= max_size(),
"plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error);
1255 auto pos = std::distance(cbegin(),
first);
1258 PLUGIFY_ASSERT(size() -
count +
count2 <= max_size(),
"plg::basic_string::replace(): resulted string size would exceed max_size()", std::length_error);
1259 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::replace(): pos out of range", std::out_of_range);
1268 template<
typename Type>
1269 requires (std::is_convertible_v<const Type&, sview_type> &&
1270 !std::is_convertible_v<const Type&, const Char*>)
1272 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::replace(): pos out of range", std::out_of_range);
1274 return replace(pos,
count,
sv.data(),
sv.length());
1277 template<
typename Type>
1278 requires (std::is_convertible_v<const Type&, sview_type> &&
1279 !std::is_convertible_v<const Type&, const Char*>)
1285 template<
typename Type>
1286 requires (std::is_convertible_v<const Type&, sview_type> &&
1287 !std::is_convertible_v<const Type&, const Char*>)
1289 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::replace(): pos out of range", std::out_of_range);
1291 return replace(pos,
count,
sv.data(),
sv.length());
1294#if PLUGIFY_STRING_CONTAINERS_RANGES
1295 template<detail::
string_compatible_range<Char> Range>
1297 auto str =
basic_string(std::from_range, std::forward<Range>(range), _allocator);
1302 constexpr basic_string substr(size_type pos = 0, size_type
count = npos)
const {
1303 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::substr(): pos out of range", std::out_of_range);
1307 constexpr size_type copy(value_type*
str, size_type
count, size_type pos = 0)
const {
1308 PLUGIFY_ASSERT(pos <= size(),
"plg::basic_string::copy(): pos out of range", std::out_of_range);
1309 return view().copy(
str,
count, pos);
1312 constexpr void resize(size_type
count, value_type
ch) {
1313 PLUGIFY_ASSERT(size() +
count <= max_size(),
"plg::basic_string::resize(): resulted string size would exceed max_size()", std::length_error);
1314 auto cap = capacity();
1327 constexpr void resize(size_type
count) {
1328 resize(
count, _terminator);
1331 template<
typename Operation>
1332 constexpr void resize_and_overwrite(size_type,
Operation) {
1333 static_assert(detail::dependent_false<Char>,
"plg::basic_string::resize_and_overwrite(count, op) not implemented!");
1336 constexpr void swap(
basic_string& other)
noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value) {
1338 if constexpr (allocator_traits::propagate_on_container_swap::value) {
1339 swap(_allocator, other._allocator);
1341 swap(_storage, other._storage);
1344 constexpr size_type find(
const basic_string&
str, size_type pos = 0)
const noexcept {
1345 return view().find(sview_type(
str), pos);
1348 constexpr size_type find(
const value_type*
str, size_type pos, size_type
count)
const noexcept {
1349 return view().find(
str, pos,
count);
1352 constexpr size_type find(
const value_type*
str, size_type pos = 0)
const noexcept {
1353 return view().find(
str, pos);
1356 constexpr size_type find(value_type
ch, size_type pos = 0)
const noexcept {
1357 return view().find(
ch, pos);
1360 template<
typename Type>
1361 requires (std::is_convertible_v<const Type&, sview_type> &&
1362 !std::is_convertible_v<const Type&, const Char*>)
1363 constexpr size_type find(
const Type&
t, size_type pos = 0)
const noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>) {
1364 return view().find(sview_type(
t), pos);
1367 constexpr size_type rfind(
const basic_string&
str, size_type pos = npos)
const noexcept {
1368 return view().rfind(sview_type(
str), pos);
1371 constexpr size_type rfind(
const value_type*
str, size_type pos, size_type
count)
const noexcept {
1372 return view().rfind(
str, pos,
count);
1375 constexpr size_type rfind(
const value_type*
str, size_type pos = npos)
const noexcept {
1376 return view().rfind(
str, pos);
1379 constexpr size_type rfind(value_type
ch, size_type pos = npos)
const noexcept {
1380 return view().rfind(
ch, pos);
1383 template<
typename Type>
1384 requires (std::is_convertible_v<const Type&, sview_type> &&
1385 !std::is_convertible_v<const Type&, const Char*>)
1386 constexpr size_type rfind(
const Type&
t, size_type pos = npos)
const noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>) {
1387 return view().rfind(sview_type(
t), pos);
1390 constexpr size_type find_first_of(
const basic_string&
str, size_type pos = 0)
const noexcept {
1391 return view().find_first_of(sview_type(
str), pos);
1394 constexpr size_type find_first_of(
const value_type*
str, size_type pos, size_type
count)
const noexcept {
1395 return view().find_first_of(
str, pos,
count);
1398 constexpr size_type find_first_of(
const value_type*
str, size_type pos = 0)
const noexcept {
1399 return view().find_first_of(
str, pos);
1402 constexpr size_type find_first_of(value_type
ch, size_type pos = 0)
const noexcept {
1403 return view().find_first_of(
ch, pos);
1406 template<
typename Type>
1407 requires (std::is_convertible_v<const Type&, sview_type> &&
1408 !std::is_convertible_v<const Type&, const Char*>)
1409 constexpr size_type find_first_of(
const Type&
t, size_type pos = 0)
const noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>) {
1410 return view().find_first_of(sview_type(
t), pos);
1413 constexpr size_type find_first_not_of(
const basic_string&
str, size_type pos = 0)
const noexcept {
1414 return view().find_first_not_of(sview_type(
str), pos);
1417 constexpr size_type find_first_not_of(
const value_type*
str, size_type pos, size_type
count)
const noexcept {
1418 return view().find_first_not_of(
str, pos,
count);
1421 constexpr size_type find_first_not_of(
const value_type*
str, size_type pos = 0)
const noexcept {
1422 return view().find_first_not_of(
str, pos);
1425 constexpr size_type find_first_not_of(value_type
ch, size_type pos = 0)
const noexcept {
1426 return view().find_first_not_of(
ch, pos);
1429 template<
typename Type>
1430 requires (std::is_convertible_v<const Type&, sview_type> &&
1431 !std::is_convertible_v<const Type&, const Char*>)
1432 constexpr size_type find_first_not_of(
const Type&
t, size_type pos = 0)
const noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>) {
1433 return view().find_first_not_of(sview_type(
t), pos);
1436 constexpr size_type find_last_of(
const basic_string&
str, size_type pos = npos)
const noexcept {
1437 return view().find_last_of(sview_type(
str), pos);
1440 constexpr size_type find_last_of(
const value_type*
str, size_type pos, size_type
count)
const noexcept {
1441 return view().find_last_of(
str, pos,
count);
1444 constexpr size_type find_last_of(
const value_type*
str, size_type pos = npos)
const noexcept {
1445 return view().find_last_of(
str, pos);
1448 constexpr size_type find_last_of(value_type
ch, size_type pos = npos)
const noexcept {
1449 return view().find_last_of(
ch, pos);
1452 template<
typename Type>
1453 requires (std::is_convertible_v<const Type&, sview_type> &&
1454 !std::is_convertible_v<const Type&, const Char*>)
1455 constexpr size_type find_last_of(
const Type&
t, size_type pos = npos)
const noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>) {
1456 return view().find_last_of(sview_type(
t), pos);
1459 constexpr size_type find_last_not_of(
const basic_string&
str, size_type pos = npos)
const noexcept {
1460 return view().find_last_not_of(sview_type(
str), pos);
1463 constexpr size_type find_last_not_of(
const value_type*
str, size_type pos, size_type
count)
const noexcept {
1464 return view().find_last_not_of(
str, pos,
count);
1467 constexpr size_type find_last_not_of(
const value_type*
str, size_type pos = npos)
const noexcept {
1468 return view().find_last_not_of(
str, pos);
1471 constexpr size_type find_last_not_of(value_type
ch, size_type pos = npos)
const noexcept {
1472 return view().find_last_not_of(
ch, pos);
1475 template<
typename Type>
1476 requires (std::is_convertible_v<const Type&, sview_type> &&
1477 !std::is_convertible_v<const Type&, const Char*>)
1478 constexpr size_type find_last_not_of(
const Type&
t, size_type pos = npos)
const noexcept(std::is_nothrow_convertible_v<const Type&, sview_type>) {
1479 return view().find_last_not_of(sview_type(
t), pos);
1486 auto buffer = ret.data();
1489 ret.null_terminate();
1494 return std::move(
lhs.append(
rhs));
1498 return std::move(
rhs.insert(0,
lhs));
1502 return std::move(
lhs.append(
rhs));
1509 auto buffer = ret.data();
1512 ret.null_terminate();
1517 return std::move(
rhs.insert(0,
lhs));
1523 auto buffer = ret.data();
1526 ret.null_terminate();
1532 return std::move(
rhs);
1539 auto buffer = ret.data();
1542 ret.null_terminate();
1547 return std::move(
lhs.append(
rhs));
1553 auto buffer = ret.data();
1556 ret.null_terminate();
1562 return std::move(
lhs);