diff --git a/stl/inc/xstring b/stl/inc/xstring index a6ed776bbf3..b98faf0abf1 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -292,6 +292,11 @@ public: } static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { +#if _HAS_CXX20 + if (_STD is_constant_evaluated()) { + return _Primary_char_traits::assign(_Left, _Right); + } +#endif // _HAS_CXX20 _Left = _Right; } @@ -431,6 +436,11 @@ public: } static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { +#if _HAS_CXX20 + if (_STD is_constant_evaluated()) { + return _Primary_char_traits::assign(_Left, _Right); + } +#endif // _HAS_CXX20 _Left = _Right; } @@ -2778,10 +2788,7 @@ public: _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); _Tidy_init(); } -#endif // _HAS_CXX20 -public: -#if _HAS_CXX20 _NODISCARD bool _Move_assign_from_buffer(_Elem* const _Right, const size_type _Size, const size_type _Res) { // Move assign from a buffer, used exclusively by basic_stringbuf; returns _Large_string_engaged() _Tidy_deallocate(); @@ -2840,9 +2847,6 @@ public: // intentionally slams into noexcept on OOM, TRANSITION, VSO-466800 _Mypair._Myval2._Orphan_all(); _Mypair._Myval2._Reload_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Al), _GET_PROXY_ALLOCATOR(_Alty, _Right_al)); - _Pocma(_Al, _Right_al); - _Take_contents(_Right); - return *this; } } else if constexpr (_Pocma_val == _Pocma_values::_No_propagate_allocators) { if (_Al != _Right_al) { @@ -2854,7 +2858,6 @@ public: _Tidy_deallocate(); _Pocma(_Al, _Right_al); _Take_contents(_Right); - return *this; } @@ -2865,7 +2868,7 @@ public: private: void _Memcpy_val_from(const basic_string& _Right) noexcept { - _STL_INTERNAL_CHECK(_Can_memcpy_val); // TRANSITION, if constexpr + _STL_INTERNAL_CHECK(_Can_memcpy_val); const auto _My_data_mem = reinterpret_cast(_STD addressof(_Mypair._Myval2)) + _Memcpy_val_offset; const auto _Right_data_mem = @@ -3052,11 +3055,10 @@ public: const auto _New_size = _Right._Mypair._Myval2._Mysize; const auto _New_capacity = _Calculate_growth(_New_size, 0, _Right.max_size()); auto _Right_al_non_const = _Right_al; - const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity); // throws + const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity + 1); // throws #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to - // avoid UB + if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB _Traits::assign(_Unfancy(_New_ptr), _New_size + 1, _Elem()); } #endif // _HAS_CXX20 @@ -4114,23 +4116,22 @@ public: _Pocs(_Getal(), _Right._Getal()); #if _ITERATOR_DEBUG_LEVEL != 0 - const bool _My_large = _Mypair._Myval2._Large_string_engaged(); - const bool _Right_large = _Right._Mypair._Myval2._Large_string_engaged(); - if (!_My_large) { - _Mypair._Myval2._Orphan_all(); - } + auto& _My_data = _Mypair._Myval2; + auto& _Right_data = _Right._Mypair._Myval2; - if (!_Right_large) { - _Right._Mypair._Myval2._Orphan_all(); + if (!_My_data._Large_string_engaged()) { + _My_data._Orphan_all(); } - if (_My_large || _Right_large) { - _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); + if (!_Right_data._Large_string_engaged()) { + _Right_data._Orphan_all(); } + + _My_data._Swap_proxy_and_iterators(_Right_data); #endif // _ITERATOR_DEBUG_LEVEL != 0 - } - _Swap_data(_Right); + _Swap_data(_Right); + } } #if _HAS_CXX17 diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index 14586098029..4781b71f252 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -85,6 +85,11 @@ constexpr auto get_cat() { } } +template +constexpr auto get_cat_view() { + return basic_string_view{get_cat()}; +} + template constexpr auto get_dog() { if constexpr (is_same_v) { @@ -102,6 +107,11 @@ constexpr auto get_dog() { } } +template +constexpr auto get_dog_view() { + return basic_string_view{get_dog()}; +} + template constexpr auto get_no_needle() { if constexpr (is_same_v) { @@ -165,11 +175,72 @@ constexpr bool equalRanges(const Range1& range1, const Range2& range2) noexcept #endif // !__cpp_lib_concepts } +template +class MyAlloc { +private: + size_t _id; + + [[nodiscard]] constexpr size_t equal_id() const noexcept { + if constexpr (is_always_equal::value) { + return 10; + } else { + return _id; + } + } + +public: + [[nodiscard]] constexpr size_t id() const noexcept { + return _id; + } + + using value_type = CharType; + + using propagate_on_container_copy_assignment = POCCA; + using propagate_on_container_move_assignment = POCMA; + using propagate_on_container_swap = POCS; + using is_always_equal = EQUAL; + + constexpr explicit MyAlloc(const size_t off) : _id(off) {} + + template + constexpr MyAlloc(const MyAlloc& other) noexcept : _id(other.id()) {} + + template + [[nodiscard]] constexpr bool operator==(const MyAlloc& other) const noexcept { + return equal_id() == other.equal_id(); + } + + [[nodiscard]] constexpr CharType* allocate(const size_t numElements) { + return allocator{}.allocate(numElements + equal_id()) + equal_id(); + } + + constexpr void deallocate(CharType* const first, const size_t numElements) noexcept { + allocator{}.deallocate(first - equal_id(), numElements + equal_id()); + } +}; + +template +using StationaryAlloc = MyAlloc; +template +using CopyAlloc = MyAlloc; +template +using CopyEqualAlloc = MyAlloc; +template +using MoveAlloc = MyAlloc; +template +using MoveEqualAlloc = MyAlloc; +template +using SwapAlloc = MyAlloc; +template +using SwapEqualAlloc = MyAlloc; + template constexpr bool test_interface() { -#ifndef __EDG__ // TRANSITION, VSO-1273296 using str = basic_string; +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // constructors // range constructors str literal_constructed{get_literal_input()}; @@ -225,6 +296,9 @@ constexpr bool test_interface() { assert(equalRanges(conversion_start_length_constructed, "llo"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // allocator constructors allocator alloc; @@ -273,6 +347,9 @@ constexpr bool test_interface() { assert(equalRanges(conversion_start_length_constructed, "llo"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // assignment operator str literal_constructed = get_literal_input(); @@ -303,6 +380,9 @@ constexpr bool test_interface() { assert(equalRanges(conversion_assigned, literal_constructed)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // assign str literal_constructed = get_literal_input(); @@ -419,6 +499,9 @@ constexpr bool test_interface() { assert(char_traits::length(cs) == literal_constructed.size()); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // iterators str literal_constructed = get_literal_input(); const str const_literal_constructed = get_literal_input(); @@ -550,6 +633,9 @@ constexpr bool test_interface() { assert(cleared.capacity() == str{get_literal_input()}.capacity()); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // insert str insert_char = get_literal_input(); const CharType to_be_inserted = CharType{','}; @@ -627,6 +713,9 @@ constexpr bool test_interface() { assert(equalRanges(insert_iter_count_char, "Hellooooo fluffy kittens"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // erase str erase_pos_count = get_literal_input(); erase_pos_count.erase(0, 6); @@ -673,6 +762,9 @@ constexpr bool test_interface() { assert(pushed.back() == CharType{'y'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // append const str literal_constructed = get_literal_input(); @@ -718,6 +810,9 @@ constexpr bool test_interface() { assert(equalRanges(append_conversion_start_length, "bbllo"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // operator+= str literal_constructed = get_literal_input(); @@ -743,6 +838,9 @@ constexpr bool test_interface() { assert(equalRanges(plus_conversion, "bbHello fluffy kittens"sv)); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // compare const str first = get_literal_input(); const str second = get_cat(); @@ -857,6 +955,9 @@ constexpr bool test_interface() { assert(comp_pos_count_conversion_pos_count_greater == 1); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // starts_with const str starts = get_literal_input(); const str input_string_true = starts.substr(0, 5); @@ -872,6 +973,9 @@ constexpr bool test_interface() { assert(!input_string_false.starts_with(get_literal_input())); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // ends_with const str ends = get_literal_input(); const str input_string_true = ends.substr(5); @@ -888,6 +992,9 @@ constexpr bool test_interface() { } #if _HAS_CXX23 +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // contains const str hello_fluffy_kittens = get_literal_input(); // "Hello fluffy kittens" constexpr auto kitten_ptr = get_cat(); // "kitten" @@ -903,6 +1010,9 @@ constexpr bool test_interface() { } #endif // _HAS_CXX23 +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // replace const str input = get_dog(); @@ -992,6 +1102,9 @@ constexpr bool test_interface() { assert(equalRanges(replaced_pos_count_conversion_pos_count, "dfluffy"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // substr const str input = get_literal_input(); @@ -1014,6 +1127,9 @@ constexpr bool test_interface() { assert(equalRanges(copy_count_pos, "fluffy"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // resize str resized = get_literal_input(); resized.resize(3); @@ -1021,9 +1137,16 @@ constexpr bool test_interface() { resized.resize(6, CharType{'a'}); assert(equalRanges(resized, "Helaaa"sv)); + + // ensure we grow properly from small string + resized.resize(26, CharType{'a'}); + assert(equalRanges(resized, "Helaaaaaaaaaaaaaaaaaaaaaaa"sv)); } #if _HAS_CXX23 +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // resize_and_overwrite constexpr basic_string_view hello_fluffy_kittens = get_view_input(); constexpr basic_string_view hello = hello_fluffy_kittens.substr(0, 5); @@ -1140,6 +1263,9 @@ constexpr bool test_interface() { assert(equalRanges(first, expected_second)); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // find const str input = get_literal_input(); const str needle = get_cat(); @@ -1198,6 +1324,9 @@ constexpr bool test_interface() { assert(find_convertible_pos == str::npos); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // rfind const str input = get_literal_input(); const str needle = get_cat(); @@ -1484,6 +1613,9 @@ constexpr bool test_interface() { assert(find_last_not_of_convertible_pos == str::npos); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // operator+ const str first = get_cat(); const str second = get_dog(); @@ -1525,6 +1657,9 @@ constexpr bool test_interface() { assert(equalRanges(op_char_rstr, "!dog"sv)); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // comparison str first(get_view_input()); str second(get_view_input()); @@ -1608,12 +1743,17 @@ constexpr bool test_interface() { basic_string_view sv = s; assert(equalRanges(sv, "Hello fluffy kittens"sv)); } -#endif // __EDG__ + return true; } constexpr bool test_udls() { -#ifndef __EDG__ // TRANSITION, VSO-1273296 +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return true; + } +#endif // ^^^ workaround ^^^ + assert(equalRanges("purr purr"s, "purr purr"sv)); #ifdef __cpp_char8_t assert(equalRanges(u8"purr purr"s, "purr purr"sv)); @@ -1621,7 +1761,7 @@ constexpr bool test_udls() { assert(equalRanges(u"purr purr"s, "purr purr"sv)); assert(equalRanges(U"purr purr"s, "purr purr"sv)); assert(equalRanges(L"purr purr"s, "purr purr"sv)); -#endif // __EDG__ + return true; } @@ -1634,7 +1774,6 @@ struct CharLikeType { template constexpr bool test_iterators() { -#ifndef __EDG__ // TRANSITION, VSO-1273296 using str = basic_string; str literal_constructed = get_literal_input(); @@ -1648,6 +1787,9 @@ constexpr bool test_iterators() { cit = cit2; } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // op-> basic_string> bs{CharType{'x'}}; auto it = bs.begin(); @@ -1659,6 +1801,9 @@ constexpr bool test_iterators() { assert(cc == CharType{'x'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // increment auto it = literal_constructed.begin(); assert(*++it == CharType{'e'}); @@ -1671,6 +1816,9 @@ constexpr bool test_iterators() { assert(*cit == CharType{'l'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // advance auto it = literal_constructed.begin() + 2; assert(*it == CharType{'l'}); @@ -1687,6 +1835,9 @@ constexpr bool test_iterators() { assert(*cit == CharType{'f'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // decrement auto it = literal_constructed.end(); assert(*--it == CharType{'s'}); @@ -1699,6 +1850,9 @@ constexpr bool test_iterators() { assert(*cit == CharType{'n'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // advance back auto it = literal_constructed.end() - 2; assert(*it == CharType{'n'}); @@ -1741,6 +1895,9 @@ constexpr bool test_iterators() { assert((it3 <=> it1) == strong_ordering::greater); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // access const auto it = literal_constructed.begin() + 2; it[2] = CharType{'l'}; @@ -1749,14 +1906,13 @@ constexpr bool test_iterators() { const auto cit = literal_constructed.cbegin() + 2; assert(cit[2] == CharType{'l'}); } -#endif // __EDG__ + return true; } template constexpr bool test_growth() { using str = basic_string; -#ifndef __EDG__ // TRANSITION, VSO-1273296 { str v(1007, CharType{'a'}); @@ -1797,6 +1953,9 @@ constexpr bool test_growth() { assert(v.capacity() == 1510); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1811,6 +1970,9 @@ constexpr bool test_growth() { assert(v.capacity() == 1510); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1829,6 +1991,9 @@ constexpr bool test_growth() { } } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1841,6 +2006,9 @@ constexpr bool test_growth() { assert(v.capacity() == 1510); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1856,60 +2024,374 @@ constexpr bool test_growth() { assert(v.capacity() == 8015); } } -#endif // __EDG__ + return true; } -int main() { - test_interface(); -#ifdef __cpp_char8_t - test_interface(); -#endif // __cpp_char8_t - test_interface(); - test_interface(); - test_interface(); +template +constexpr void test_copy_ctor() { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ - test_udls(); + using Str = basic_string, StationaryAlloc>; - test_iterators(); -#ifdef __cpp_char8_t - test_iterators(); -#endif // __cpp_char8_t - test_iterators(); - test_iterators(); - test_iterators(); + { // Allocated + Str range_constructed(get_view_input(), StationaryAlloc{11}); + Str copy_constructed(range_constructed); + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == 11); + assert(copy_constructed.get_allocator().id() == 11); + } - test_growth(); -#ifdef __cpp_char8_t - test_growth(); -#endif // __cpp_char8_t - test_growth(); - test_growth(); - test_growth(); + { // SSO + Str range_constructed_sso(get_cat_view(), StationaryAlloc{11}); + Str copy_constructed_sso(range_constructed_sso); + assert(equalRanges(range_constructed_sso, get_cat_view())); + assert(equalRanges(copy_constructed_sso, get_cat_view())); + assert(range_constructed_sso.get_allocator().id() == 11); + assert(copy_constructed_sso.get_allocator().id() == 11); + } +} - static_assert(test_interface()); -#ifdef __cpp_char8_t - static_assert(test_interface()); -#endif // __cpp_char8_t - static_assert(test_interface()); - static_assert(test_interface()); - static_assert(test_interface()); +template +constexpr void test_copy_alloc_ctor(const size_t id1, const size_t id2) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ - static_assert(test_udls()); + using Str = basic_string, StationaryAlloc>; - static_assert(test_iterators()); -#ifdef __cpp_char8_t - static_assert(test_iterators()); -#endif // __cpp_char8_t - static_assert(test_iterators()); - static_assert(test_iterators()); - static_assert(test_iterators()); + { // Allocated + Str range_constructed(get_view_input(), StationaryAlloc{id1}); + Str copy_constructed(range_constructed, StationaryAlloc{id2}); + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_constructed.get_allocator().id() == id2); + } + + { // SSO + Str range_constructed_sso(get_cat_view(), StationaryAlloc{id1}); + Str copy_constructed_sso(range_constructed_sso, StationaryAlloc{id2}); + assert(equalRanges(range_constructed_sso, get_cat_view())); + assert(equalRanges(copy_constructed_sso, get_cat_view())); + assert(range_constructed_sso.get_allocator().id() == id1); + assert(copy_constructed_sso.get_allocator().id() == id2); + } +} + +template +constexpr void test_copy_assign(const size_t id1, const size_t id2, const size_t id3) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + + using Str = basic_string, Alloc>; + + { // Allocated to SSO + Str range_constructed(get_view_input(), Alloc{id1}); + Str copy_assigned(get_cat_view(), Alloc{id2}); + + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } + + { // SSO to SSO + Str range_constructed(get_dog_view(), Alloc{id1}); + Str copy_assigned(get_cat_view(), Alloc{id2}); + + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_dog_view())); + assert(equalRanges(copy_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } + + { // SSO to Allocated + Str range_constructed(get_dog_view(), Alloc{id1}); + Str copy_assigned(get_view_input(), Alloc{id2}); - static_assert(test_growth()); + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_dog_view())); + assert(equalRanges(copy_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } + + { // Allocated to Allocated + Str range_constructed(get_view_input(), Alloc{id1}); + Str copy_assigned(get_view_input(), Alloc{id2}); + copy_assigned.resize(30, 'a'); + + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } +} + +template +constexpr void test_move_ctor() { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + + using Str = basic_string, StationaryAlloc>; + + { // Allocated + // Iterators are taken over if the allocators are equal and source is large + Str range_constructed(get_view_input(), StationaryAlloc{11}); + const auto test_it = range_constructed.begin(); + Str move_constructed(move(range_constructed)); + + assert(test_it == move_constructed.begin()); + assert(range_constructed.empty()); + assert(equalRanges(move_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == 11); + assert(move_constructed.get_allocator().id() == 11); + } + + { // SSO + Str range_constructed(get_cat_view(), StationaryAlloc{11}); + Str move_constructed(move(range_constructed)); + + assert(range_constructed.empty()); + assert(equalRanges(move_constructed, get_cat_view())); + assert(range_constructed.get_allocator().id() == 11); + assert(move_constructed.get_allocator().id() == 11); + } +} + +template +constexpr void test_move_alloc_ctor(const size_t id1, const size_t id2) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + + using Str = basic_string, StationaryAlloc>; + + { // Allocated + // Iterators are taken over if the allocators are equal and source is large + Str range_constructed(get_view_input(), StationaryAlloc{id1}); + const auto test_it = range_constructed.begin(); + Str move_constructed(move(range_constructed), StationaryAlloc{id2}); + + assert(id1 != id2 || test_it == move_constructed.begin()); + assert((id1 == id2) == range_constructed.empty()); + assert(equalRanges(move_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_constructed.get_allocator().id() == id2); + } + + { // SSO + Str range_constructed(get_cat_view(), StationaryAlloc{id1}); + Str move_constructed(move(range_constructed), StationaryAlloc{id2}); + + assert((id1 == id2) == range_constructed.empty()); + assert(equalRanges(move_constructed, get_cat_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_constructed.get_allocator().id() == id2); + } +} + +template +constexpr void test_move_assign(const size_t id1, const size_t id2, const size_t id3) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + + using Str = basic_string, Alloc>; + // Iterators are taken over if the allocators are equal and source is large + + { // Allocated to SSO + Str range_constructed(get_view_input(), Alloc{id1}); + const auto test_it = range_constructed.begin(); + Str move_assigned(get_cat_view(), Alloc{id2}); + + move_assigned = move(range_constructed); + assert(id1 != id3 || test_it == move_assigned.begin()); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } + + { // SSO to SSO + Str range_constructed(get_dog_view(), Alloc{id1}); + Str move_assigned(get_cat_view(), Alloc{id2}); + + move_assigned = move(range_constructed); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } + + { // SSO to Allocated + Str range_constructed(get_dog_view(), Alloc{id1}); + Str move_assigned(get_view_input(), Alloc{id2}); + + move_assigned = move(range_constructed); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } + + { // Allocated to Allocated + Str range_constructed(get_view_input(), Alloc{id1}); + Str move_assigned(get_view_input(), Alloc{id2}); + move_assigned.resize(30, 'a'); + const auto test_it = range_constructed.begin(); + + move_assigned = move(range_constructed); + assert(id1 != id3 || test_it == move_assigned.begin()); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } +} + +template +constexpr void test_swap(const size_t id1, const size_t id2) { + using Str = basic_string, Alloc>; + { // Allocated to SSO + Str lhs(get_view_input(), Alloc{id1}); + Str rhs(get_cat_view(), Alloc{id2}); + const auto lhs_begin = lhs.begin(); + + lhs.swap(rhs); + assert(lhs_begin == rhs.begin()); + + assert(equalRanges(lhs, get_cat_view())); + assert(equalRanges(rhs, get_view_input())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } + + { // SSO to SSO + Str lhs(get_dog_view(), Alloc{id1}); + Str rhs(get_cat_view(), Alloc{id2}); + + lhs.swap(rhs); + assert(equalRanges(lhs, get_cat_view())); + assert(equalRanges(rhs, get_dog_view())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } + + { // SSO to Allocated + Str lhs(get_dog_view(), Alloc{id1}); + Str rhs(get_view_input(), Alloc{id2}); + const auto rhs_begin = rhs.begin(); + + lhs.swap(rhs); + assert(rhs_begin == lhs.begin()); + + assert(equalRanges(lhs, get_view_input())); + assert(equalRanges(rhs, get_dog_view())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } + +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ + { // Allocated to Allocated + Str lhs(get_view_input(), Alloc{id1}); + Str rhs(get_view_input(), Alloc{id2}); + rhs.resize(30, 'a'); + const auto lhs_begin = lhs.begin(); + const auto rhs_begin = rhs.begin(); + + Str expected_lhs = rhs; + + lhs.swap(rhs); + assert(lhs_begin == rhs.begin()); + assert(rhs_begin == lhs.begin()); + + assert(equalRanges(lhs, expected_lhs)); + assert(equalRanges(rhs, get_view_input())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } +} + +template +constexpr bool test_allocator_awareness() { + test_copy_ctor(); + test_copy_alloc_ctor(11, 11); // equal allocators + test_copy_alloc_ctor(11, 22); // non-equal allocators + test_copy_assign>(11, 11, 11); // non-POCCA, equal allocators + test_copy_assign>(11, 22, 22); // non-POCCA, non-equal allocators + test_copy_assign>(11, 11, 11); // POCCA, equal allocators + test_copy_assign>(11, 22, 11); // POCCA, non-equal allocators + test_copy_assign>(11, 22, 11); // POCCA, always-equal allocators + + test_move_ctor(); + test_move_alloc_ctor(11, 11); // equal allocators + test_move_alloc_ctor(11, 22); // non-equal allocators + + test_move_assign>(11, 11, 11); // non-POCMA, equal allocators + test_move_assign>(11, 22, 22); // non-POCMA, non-equal allocators + test_move_assign>(11, 11, 11); // POCMA, equal allocators + test_move_assign>(11, 22, 11); // POCMA, non-equal allocators + test_move_assign>(11, 22, 11); // POCMA, always-equal allocators + + test_swap>(11, 11); // non-POCS, equal allocators + // UNDEFINED BEHAVIOR, NOT TESTED - non-POCS, non-equal allocators + test_swap>(11, 11); // POCS, equal allocators + test_swap>(11, 22); // POCS, non-equal allocators + test_swap>(11, 22); // POCS, always-equal allocators + + return true; +} + +template +constexpr void test_all() { + test_interface(); + test_iterators(); + test_growth(); + test_allocator_awareness(); + + static_assert(test_interface()); + static_assert(test_iterators()); + static_assert(test_growth()); + static_assert(test_allocator_awareness()); +} + +int main() { + test_all(); #ifdef __cpp_char8_t - static_assert(test_growth()); + test_all(); #endif // __cpp_char8_t - static_assert(test_growth()); - static_assert(test_growth()); - static_assert(test_growth()); + test_all(); + test_all(); + test_all(); + + test_udls(); + static_assert(test_udls()); }