From 90829a7c78b37b25d8d8b326d6e029656f7aa817 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 14:05:38 +0800 Subject: [PATCH 01/28] make string(const T*) and string(const T*, const Alloc&) adjacent --- stl/inc/xstring | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index b5ab9511a73..1de5901839a 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2536,14 +2536,14 @@ public: _Construct<_Construct_strategy::_From_ptr>(_Ptr, _Count); } - _CONSTEXPR20 basic_string(_In_z_ const _Elem* const _Ptr) : _Mypair(_Zero_then_variadic_args_t{}) { - _Construct<_Construct_strategy::_From_ptr>(_Ptr, _Convert_size(_Traits::length(_Ptr))); - } - #if _HAS_CXX23 basic_string(nullptr_t) = delete; #endif // _HAS_CXX23 + _CONSTEXPR20 basic_string(_In_z_ const _Elem* const _Ptr) : _Mypair(_Zero_then_variadic_args_t{}) { + _Construct<_Construct_strategy::_From_ptr>(_Ptr, _Convert_size(_Traits::length(_Ptr))); + } + #if _HAS_CXX17 template ::value, int> = 0> #endif // _HAS_CXX17 From cbaa0dbab9210549398e5b498fc180b8c56396ee Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 14:37:00 +0800 Subject: [PATCH 02/28] introduce _(De)allocate_from_al --- stl/inc/xstring | 61 ++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 1de5901839a..b6c1f9be4ed 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2589,19 +2589,26 @@ public: } private: - static constexpr void _Start_element_lifetimes(_Elem* const _Ptr, const size_type _Size) { + static constexpr pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { + _STL_INTERNAL_CHECK(_New_capacity >= _BUF_SIZE); + const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); // throws // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, // but likely more impactful to throughput. #if _HAS_CXX20 if (_STD is_constant_evaluated()) { - for (size_type _Idx = 0; _Idx < _Size; ++_Idx) { + _Elem* const _Ptr = _Unfancy(_Fancy_ptr); + for (size_type _Idx = 0; _Idx < _New_capacity + 1; ++_Idx) { _STD construct_at(_Ptr + _Idx); } } -#else // ^^^ C++20-or-later / pre-C++20 vvv - (void) _Ptr; - (void) _Size; #endif // _HAS_CXX20 + return _Fancy_ptr; + } + + static constexpr void _Deallocate_from_al( + _Alty& _Al, const pointer _Old_ptr, const size_type _Old_capacity) noexcept { + _STL_INTERNAL_CHECK(_Old_capacity >= _BUF_SIZE); + _Al.deallocate(_Old_ptr, _Old_capacity + 1); } enum class _Construct_strategy : uint8_t { _From_char, _From_ptr, _From_string }; @@ -2649,11 +2656,9 @@ private: _My_data._Myres = _BUF_SIZE - 1; const size_type _New_capacity = _Calculate_growth(_Count); - const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + const pointer _New_ptr = _Allocate_from_al(_Al,_New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); - _Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1); - _My_data._Mysize = _Count; _My_data._Myres = _New_capacity; if constexpr (_Strat == _Construct_strategy::_From_char) { @@ -2692,11 +2697,9 @@ private: if (_Count >= _BUF_SIZE) { const size_type _New_capacity = _Calculate_growth(_Count); - const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + const pointer _New_ptr = _Allocate_from_al(_Al,_New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); _My_data._Myres = _New_capacity; - - _Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1); } } @@ -2710,12 +2713,11 @@ private: const auto _Old_ptr = _My_data._Myptr(); const size_type _New_capacity = _Calculate_growth(_My_data._Mysize); - const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity)(); // throws - _Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1); _Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize); if (_My_data._Myres >= _BUF_SIZE) { // Need to deallocate old storage - _Al.deallocate(_My_data._Bx._Ptr, _My_data._Myres + 1); + _Deallocate_from_al(_Al, _My_data._Bx._Ptr, _My_data._Myres); _My_data._Bx._Ptr = _New_ptr; } else { _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); @@ -2793,11 +2795,9 @@ public: if (_New_capacity < _New_size) { _New_capacity = _Calculate_growth(_New_size, _BUF_SIZE - 1, max_size()); - const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws + const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); _Ptr = _Unfancy(_Fancyptr); _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); - - _Start_element_lifetimes(_Ptr, _New_capacity + 1); } _My_data._Mysize = _New_size; @@ -2866,9 +2866,8 @@ public: const auto _New_capacity = _Calculate_growth(_New_size, _BUF_SIZE - 1, _Max); auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws - const pointer _Fancyptr = _Getal().allocate(_New_capacity + 1); // throws + const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); // throws // nothrow hereafter - _Start_element_lifetimes(_Unfancy(_Fancyptr), _New_capacity + 1); _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; @@ -3169,9 +3168,7 @@ 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 + 1); // throws - - _Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1); + const auto _New_ptr = _Allocate_from_al(_Right_al_non_const, _New_capacity); // throws _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_Right._Mypair._Myval2._Bx._Ptr), _New_size + 1); _Tidy_deallocate(); @@ -3996,14 +3993,12 @@ public: const size_type _Target_capacity = (_STD min)(_My_data._Mysize | _ALLOC_MASK, max_size()); if (_Target_capacity < _My_data._Myres) { // worth shrinking, do it auto& _Al = _Getal(); - const pointer _New_ptr = _Al.allocate(_Target_capacity + 1); // throws + const pointer _New_ptr = _Allocate_from_al(_Al, _Target_capacity); // throws _ASAN_STRING_REMOVE(*this); - _Start_element_lifetimes(_Unfancy(_New_ptr), _Target_capacity + 1); - _My_data._Orphan_all(); _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_My_data._Bx._Ptr), _My_data._Mysize + 1); - _Al.deallocate(_My_data._Bx._Ptr, _My_data._Myres + 1); + _Deallocate_from_al(_Al, _My_data._Bx._Ptr, _My_data._Myres); _My_data._Bx._Ptr = _New_ptr; _My_data._Myres = _Target_capacity; _ASAN_STRING_CREATE(*this); @@ -4738,16 +4733,15 @@ private: const size_type _Old_capacity = _Mypair._Myval2._Myres; const size_type _New_capacity = _Calculate_growth(_New_size); auto& _Al = _Getal(); - const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws - _Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1); _Mypair._Myval2._Orphan_all(); _ASAN_STRING_REMOVE(*this); _Mypair._Myval2._Mysize = _New_size; _Mypair._Myval2._Myres = _New_capacity; _Fn(_Unfancy(_New_ptr), _New_size, _Args...); if (_BUF_SIZE <= _Old_capacity) { - _Al.deallocate(_Mypair._Myval2._Bx._Ptr, _Old_capacity + 1); + _Deallocate_from_al(_Al, _Mypair._Myval2._Bx._Ptr, _Old_capacity); _Mypair._Myval2._Bx._Ptr = _New_ptr; } else { _Construct_in_place(_Mypair._Myval2._Bx._Ptr, _New_ptr); @@ -4771,9 +4765,8 @@ private: const size_type _Old_capacity = _My_data._Myres; const size_type _New_capacity = _Calculate_growth(_New_size); auto& _Al = _Getal(); - const pointer _New_ptr = _Al.allocate(_New_capacity + 1); // throws + const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws - _Start_element_lifetimes(_Unfancy(_New_ptr), _New_capacity + 1); _My_data._Orphan_all(); _ASAN_STRING_REMOVE(*this); _My_data._Mysize = _New_size; @@ -4782,7 +4775,7 @@ private: if (_BUF_SIZE <= _Old_capacity) { const pointer _Old_ptr = _My_data._Bx._Ptr; _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); - _Al.deallocate(_Old_ptr, _Old_capacity + 1); + _Deallocate_from_al(_Al, _Old_ptr, _Old_capacity); _My_data._Bx._Ptr = _New_ptr; } else { _Fn(_Raw_new, _My_data._Bx._Buf, _Old_size, _Args...); @@ -4806,7 +4799,7 @@ private: _Destroy_in_place(_My_data._Bx._Ptr); _My_data._Activate_SSO_buffer(); _Traits::copy(_My_data._Bx._Buf, _Unfancy(_Ptr), _My_data._Mysize + 1); - _Al.deallocate(_Ptr, _My_data._Myres + 1); + _Deallocate_from_al(_Al, _Ptr, _My_data._Myres); _My_data._Myres = _BUF_SIZE - 1; } @@ -4835,7 +4828,7 @@ private: auto& _Al = _Getal(); _Destroy_in_place(_My_data._Bx._Ptr); _My_data._Activate_SSO_buffer(); - _Al.deallocate(_Ptr, _My_data._Myres + 1); + _Deallocate_from_al(_Al, _Ptr, _My_data._Myres); } _My_data._Mysize = 0; From 6f4cad30f5729ff472b345219de822cdcdaf8648 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 14:41:13 +0800 Subject: [PATCH 03/28] nit --- stl/inc/xstring | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index b6c1f9be4ed..37c3d679335 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2656,7 +2656,7 @@ private: _My_data._Myres = _BUF_SIZE - 1; const size_type _New_capacity = _Calculate_growth(_Count); - const pointer _New_ptr = _Allocate_from_al(_Al,_New_capacity); // throws + const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); _My_data._Mysize = _Count; @@ -2697,7 +2697,7 @@ private: if (_Count >= _BUF_SIZE) { const size_type _New_capacity = _Calculate_growth(_Count); - const pointer _New_ptr = _Allocate_from_al(_Al,_New_capacity); // throws + const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); _My_data._Myres = _New_capacity; } From 354890e97b8209ce9429f112d0d4b05dc08aae3b Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 14:50:24 +0800 Subject: [PATCH 04/28] nit --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 37c3d679335..d5f7ac4eabe 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2795,7 +2795,7 @@ public: if (_New_capacity < _New_size) { _New_capacity = _Calculate_growth(_New_size, _BUF_SIZE - 1, max_size()); - const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); + const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); // throws _Ptr = _Unfancy(_Fancyptr); _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); } From 29519613321ca70b8b785aa06475411d6f4720fe Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 15:12:14 +0800 Subject: [PATCH 05/28] introduce _SMALL_STRING_CAPACITY --- stl/inc/xstring | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index d5f7ac4eabe..d90b0b05129 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2221,6 +2221,7 @@ public: : sizeof(value_type) <= 4 ? 3 : sizeof(value_type) <= 8 ? 1 : 0; + static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; _CONSTEXPR20 value_type* _Myptr() noexcept { value_type* _Result = _Bx._Buf; @@ -2241,7 +2242,8 @@ public: } _CONSTEXPR20 bool _Large_string_engaged() const noexcept { - return _BUF_SIZE <= _Myres; + _STL_INTERNAL_CHECK(_Myres >= _SMALL_STRING_CAPACITY); + return _Myres != _SMALL_STRING_CAPACITY; } constexpr void _Activate_SSO_buffer() noexcept { @@ -2363,6 +2365,7 @@ public: private: static constexpr auto _BUF_SIZE = _Scary_val::_BUF_SIZE; static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; + static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; // When doing _String_val operations by memcpy, we are touching: // _String_val::_Bx::_Buf (type is array of _Elem) @@ -2422,7 +2425,7 @@ private: } #endif // _HAS_CXX20 // Don't annotate small strings; only annotate on the heap. - if (_Capacity == _BUF_SIZE - 1 || !_Asan_string_should_annotate) { + if (_Capacity == _SMALL_STRING_CAPACITY || !_Asan_string_should_annotate) { return; } @@ -2590,7 +2593,7 @@ public: private: static constexpr pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { - _STL_INTERNAL_CHECK(_New_capacity >= _BUF_SIZE); + _STL_INTERNAL_CHECK(_New_capacity > _SMALL_STRING_CAPACITY); const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); // throws // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, // but likely more impactful to throughput. @@ -2607,7 +2610,7 @@ private: static constexpr void _Deallocate_from_al( _Alty& _Al, const pointer _Old_ptr, const size_type _Old_capacity) noexcept { - _STL_INTERNAL_CHECK(_Old_capacity >= _BUF_SIZE); + _STL_INTERNAL_CHECK(_Old_capacity > _SMALL_STRING_CAPACITY); _Al.deallocate(_Old_ptr, _Old_capacity + 1); } @@ -2634,7 +2637,7 @@ private: if (_Count < _BUF_SIZE) { _My_data._Mysize = _Count; - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; if constexpr (_Strat == _Construct_strategy::_From_char) { _Traits::assign(_My_data._Bx._Buf, _Count, _Arg); @@ -2654,7 +2657,7 @@ private: return; } - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; const size_type _New_capacity = _Calculate_growth(_Count); const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); @@ -2688,7 +2691,7 @@ private: _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); _My_data._Mysize = 0; - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; if constexpr (is_same_v<_Size, size_type>) { if (_Count > max_size()) { @@ -2716,7 +2719,7 @@ private: const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity)(); // throws _Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize); - if (_My_data._Myres >= _BUF_SIZE) { // Need to deallocate old storage + if (_My_data._Large_string_engaged()) { // Need to deallocate old storage _Deallocate_from_al(_Al, _My_data._Bx._Ptr, _My_data._Myres); _My_data._Bx._Ptr = _New_ptr; } else { @@ -2787,14 +2790,14 @@ public: _STL_INTERNAL_CHECK(_Right_size <= max_size()); _STL_INTERNAL_CHECK(_Right_size <= max_size() - _Left_size); const auto _New_size = static_cast(_Left_size + _Right_size); - size_type _New_capacity = _BUF_SIZE - 1; + size_type _New_capacity = _SMALL_STRING_CAPACITY; auto& _My_data = _Mypair._Myval2; _Elem* _Ptr = _My_data._Bx._Buf; auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws if (_New_capacity < _New_size) { - _New_capacity = _Calculate_growth(_New_size, _BUF_SIZE - 1, max_size()); + _New_capacity = _Calculate_growth(_New_size, _SMALL_STRING_CAPACITY, max_size()); const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); // throws _Ptr = _Unfancy(_Fancyptr); _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); @@ -2863,7 +2866,7 @@ public: _Xlen_string(); } - const auto _New_capacity = _Calculate_growth(_New_size, _BUF_SIZE - 1, _Max); + const auto _New_capacity = _Calculate_growth(_New_size, _SMALL_STRING_CAPACITY, _Max); auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); // throws @@ -2921,7 +2924,7 @@ public: } else { _Traits::copy(_My_data._Bx._Buf, _Right, _Res); _My_data._Mysize = _Size; - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; } return _Is_large; @@ -4800,7 +4803,7 @@ private: _My_data._Activate_SSO_buffer(); _Traits::copy(_My_data._Bx._Buf, _Unfancy(_Ptr), _My_data._Mysize + 1); _Deallocate_from_al(_Al, _Ptr, _My_data._Myres); - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; } _CONSTEXPR20 void _Eos(const size_type _New_size) noexcept { // set new length and null terminator @@ -4812,7 +4815,7 @@ private: // initialize basic_string data members auto& _My_data = _Mypair._Myval2; _My_data._Mysize = 0; - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; _My_data._Activate_SSO_buffer(); // the _Traits::assign is last so the codegen doesn't think the char write can alias this @@ -4832,7 +4835,7 @@ private: } _My_data._Mysize = 0; - _My_data._Myres = _BUF_SIZE - 1; + _My_data._Myres = _SMALL_STRING_CAPACITY; // the _Traits::assign is last so the codegen doesn't think the char write can alias this _Traits::assign(_My_data._Bx._Buf[0], _Elem()); } From 9c3b701a8a3a51355c33e0a24b781177e95ede9a Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 15:35:54 +0800 Subject: [PATCH 06/28] introduce _Entails_large_string --- stl/inc/xstring | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index d90b0b05129..79bac14a709 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2216,11 +2216,11 @@ public: // length of internal buffer, [1, 16]: static constexpr size_type _BUF_SIZE = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type); // roundup mask for allocated buffers, [0, 15]: - static constexpr size_type _ALLOC_MASK = sizeof(value_type) <= 1 ? 15 - : sizeof(value_type) <= 2 ? 7 - : sizeof(value_type) <= 4 ? 3 - : sizeof(value_type) <= 8 ? 1 - : 0; + static constexpr size_type _ALLOC_MASK = sizeof(value_type) <= 1 ? 15 + : sizeof(value_type) <= 2 ? 7 + : sizeof(value_type) <= 4 ? 3 + : sizeof(value_type) <= 8 ? 1 + : 0; static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; _CONSTEXPR20 value_type* _Myptr() noexcept { @@ -2363,10 +2363,14 @@ public: using const_reverse_iterator = _STD reverse_iterator; private: - static constexpr auto _BUF_SIZE = _Scary_val::_BUF_SIZE; - static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; + static constexpr auto _BUF_SIZE = _Scary_val::_BUF_SIZE; + static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; + static constexpr bool _Entails_large_string(size_type _Size_or_capacity) noexcept { + return _Size_or_capacity > _SMALL_STRING_CAPACITY; + } + // When doing _String_val operations by memcpy, we are touching: // _String_val::_Bx::_Buf (type is array of _Elem) // _String_val::_Bx::_Ptr (type is pointer) @@ -2635,7 +2639,7 @@ private: auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Al); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); - if (_Count < _BUF_SIZE) { + if (!_Entails_large_string(_Count)) { _My_data._Mysize = _Count; _My_data._Myres = _SMALL_STRING_CAPACITY; @@ -2698,7 +2702,7 @@ private: _Xlen_string(); // result too long } - if (_Count >= _BUF_SIZE) { + if (_Entails_large_string(_Count)) { const size_type _New_capacity = _Calculate_growth(_Count); const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); @@ -3056,7 +3060,7 @@ private: const auto _Result_size = _Right_data._Clamp_suffix_size(_Roff, _Size_max); const auto _Right_ptr = _Right_data._Myptr(); auto& _Al = _Getal(); - if (_Allocators_equal(_Al, _Right._Getal()) && _Result_size >= _BUF_SIZE) { + if (_Allocators_equal(_Al, _Right._Getal()) && _Entails_large_string(_Result_size)) { if (_Roff != 0) { _Traits::move(_Right_ptr, _Right_ptr + _Roff, _Result_size); } @@ -3988,7 +3992,7 @@ public: return; } - if (_My_data._Mysize < _BUF_SIZE) { + if (!_Entails_large_string(_My_data._Mysize)) { _Become_small(); return; } @@ -4212,7 +4216,7 @@ public: return; } - if (_BUF_SIZE > _Newcap && _Mypair._Myval2._Large_string_engaged()) { + if (!_Entails_large_string(_Newcap) && _Mypair._Myval2._Large_string_engaged()) { // deallocate everything; switch back to "small" mode _Become_small(); return; @@ -4743,7 +4747,7 @@ private: _Mypair._Myval2._Mysize = _New_size; _Mypair._Myval2._Myres = _New_capacity; _Fn(_Unfancy(_New_ptr), _New_size, _Args...); - if (_BUF_SIZE <= _Old_capacity) { + if (_Old_capacity != _SMALL_STRING_CAPACITY) { // large string engaged _Deallocate_from_al(_Al, _Mypair._Myval2._Bx._Ptr, _Old_capacity); _Mypair._Myval2._Bx._Ptr = _New_ptr; } else { @@ -4775,7 +4779,7 @@ private: _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; _Elem* const _Raw_new = _Unfancy(_New_ptr); - if (_BUF_SIZE <= _Old_capacity) { + if (_Old_capacity != _SMALL_STRING_CAPACITY) { // large string engaged const pointer _Old_ptr = _My_data._Bx._Ptr; _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); _Deallocate_from_al(_Al, _Old_ptr, _Old_capacity); @@ -4793,7 +4797,7 @@ private: // release any held storage and return to small string mode auto& _My_data = _Mypair._Myval2; _STL_INTERNAL_CHECK(_My_data._Large_string_engaged()); - _STL_INTERNAL_CHECK(_My_data._Mysize < _BUF_SIZE); + _STL_INTERNAL_CHECK(!_Entails_large_string(_My_data._Mysize)); _My_data._Orphan_all(); _ASAN_STRING_REMOVE(*this); From f5089e60f913b0948b4cd6120b8993f171f79089 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 15:58:47 +0800 Subject: [PATCH 07/28] nit --- stl/inc/xstring | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 79bac14a709..1bf44fedfd1 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2216,11 +2216,12 @@ public: // length of internal buffer, [1, 16]: static constexpr size_type _BUF_SIZE = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type); // roundup mask for allocated buffers, [0, 15]: - static constexpr size_type _ALLOC_MASK = sizeof(value_type) <= 1 ? 15 - : sizeof(value_type) <= 2 ? 7 - : sizeof(value_type) <= 4 ? 3 - : sizeof(value_type) <= 8 ? 1 - : 0; + static constexpr size_type _ALLOC_MASK = sizeof(value_type) <= 1 ? 15 + : sizeof(value_type) <= 2 ? 7 + : sizeof(value_type) <= 4 ? 3 + : sizeof(value_type) <= 8 ? 1 + : 0; + // capacity of small strings static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; _CONSTEXPR20 value_type* _Myptr() noexcept { @@ -2292,8 +2293,8 @@ public: }; _Bxty _Bx; - size_type _Mysize = 0; // current length of string - size_type _Myres = 0; // current storage reserved for string + size_type _Mysize = 0; // current length of string (string::size) + size_type _Myres = 0; // current storage reserved for string (string::capacity) }; // get _Ty's size after being EBCO'd From 6539a437a82cdff01cc5b6384d74d043f10a4fe8 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 16:04:30 +0800 Subject: [PATCH 08/28] nit --- stl/inc/xstring | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 1bf44fedfd1..ecdbc61b522 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2221,7 +2221,7 @@ public: : sizeof(value_type) <= 4 ? 3 : sizeof(value_type) <= 8 ? 1 : 0; - // capacity of small strings + // capacity for small strings; smallest possible value of _Myres static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; _CONSTEXPR20 value_type* _Myptr() noexcept { @@ -2367,8 +2367,8 @@ private: static constexpr auto _BUF_SIZE = _Scary_val::_BUF_SIZE; static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; - static constexpr bool _Entails_large_string(size_type _Size_or_capacity) noexcept { + // checks wether planned size/capacity entails large string mode return _Size_or_capacity > _SMALL_STRING_CAPACITY; } From d2535337f0c5a898db7efc86421db8dbc28eebaf Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 16:22:16 +0800 Subject: [PATCH 09/28] nit --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index ecdbc61b522..d0a2a2edc3d 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2293,7 +2293,7 @@ public: }; _Bxty _Bx; - size_type _Mysize = 0; // current length of string (string::size) + size_type _Mysize = 0; // current length of string (string::size; <= _Myres) size_type _Myres = 0; // current storage reserved for string (string::capacity) }; From 427de41bd35a7d6f2acade0cde437947325e4cf1 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 17:13:35 +0800 Subject: [PATCH 10/28] nit --- stl/inc/xstring | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index d0a2a2edc3d..141cbcf2db4 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2367,8 +2367,9 @@ private: static constexpr auto _BUF_SIZE = _Scary_val::_BUF_SIZE; static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; + static constexpr bool _Entails_large_string(size_type _Size_or_capacity) noexcept { - // checks wether planned size/capacity entails large string mode + // decides wether planned size/capacity entails large string mode return _Size_or_capacity > _SMALL_STRING_CAPACITY; } @@ -2597,7 +2598,7 @@ public: } private: - static constexpr pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { + static _CONSTEXPR20 pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { _STL_INTERNAL_CHECK(_New_capacity > _SMALL_STRING_CAPACITY); const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); // throws // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, @@ -2613,7 +2614,7 @@ private: return _Fancy_ptr; } - static constexpr void _Deallocate_from_al( + static _CONSTEXPR20 void _Deallocate_from_al( _Alty& _Al, const pointer _Old_ptr, const size_type _Old_capacity) noexcept { _STL_INTERNAL_CHECK(_Old_capacity > _SMALL_STRING_CAPACITY); _Al.deallocate(_Old_ptr, _Old_capacity + 1); From 13977775eb61880fe82028e12bf2004907510538 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 17:38:14 +0800 Subject: [PATCH 11/28] nit --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 141cbcf2db4..7e5eb9fd6d4 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2600,7 +2600,7 @@ public: private: static _CONSTEXPR20 pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { _STL_INTERNAL_CHECK(_New_capacity > _SMALL_STRING_CAPACITY); - const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); // throws + const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, // but likely more impactful to throughput. #if _HAS_CXX20 From a9658d7ebff14ea7cb0ff29b4e98074b43b70e08 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 24 Jun 2023 19:02:58 +0800 Subject: [PATCH 12/28] nit --- stl/inc/xstring | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 7e5eb9fd6d4..8d931911e81 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2368,7 +2368,7 @@ private: static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; - static constexpr bool _Entails_large_string(size_type _Size_or_capacity) noexcept { + _NODISCARD static _CONSTEXPR20 bool _Entails_large_string(size_type _Size_or_capacity) noexcept { // decides wether planned size/capacity entails large string mode return _Size_or_capacity > _SMALL_STRING_CAPACITY; } @@ -2598,12 +2598,12 @@ public: } private: - static _CONSTEXPR20 pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { + _NODISCARD static _CONSTEXPR20 pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { _STL_INTERNAL_CHECK(_New_capacity > _SMALL_STRING_CAPACITY); const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); +#if _HAS_CXX20 // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, // but likely more impactful to throughput. -#if _HAS_CXX20 if (_STD is_constant_evaluated()) { _Elem* const _Ptr = _Unfancy(_Fancy_ptr); for (size_type _Idx = 0; _Idx < _New_capacity + 1; ++_Idx) { From dbcfa2c15990b590a4acb9140bf7afb94a5e4d18 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sun, 25 Jun 2023 11:12:55 +0800 Subject: [PATCH 13/28] fix typo wether -> whether make the behavior in `operator=(const basic_string&::if (_Al != _Right_al)` normal --- stl/inc/xstring | 43 ++++++++++++------------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 8d931911e81..c4bca9842ca 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2369,7 +2369,7 @@ private: static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; _NODISCARD static _CONSTEXPR20 bool _Entails_large_string(size_type _Size_or_capacity) noexcept { - // decides wether planned size/capacity entails large string mode + // decides whether planned size/capacity entails large string mode return _Size_or_capacity > _SMALL_STRING_CAPACITY; } @@ -3135,30 +3135,6 @@ public: static constexpr auto npos{static_cast(-1)}; -private: - _CONSTEXPR20 void _Copy_assign_val_from_small(const basic_string& _Right) { - // TRANSITION, VSO-761321; inline into only caller when that's fixed - _Tidy_deallocate(); -#if !defined(_INSERT_STRING_ANNOTATION) - if constexpr (_Can_memcpy_val) { -#if _HAS_CXX20 - if (!_STD is_constant_evaluated()) -#endif // _HAS_CXX20 - { - _Memcpy_val_from(_Right); - return; - } - } -#endif // !defined(_INSERT_STRING_ANNOTATION) - - auto& _My_data = _Mypair._Myval2; - auto& _Right_data = _Right._Mypair._Myval2; - - _Traits::copy(_My_data._Bx._Buf, _Right_data._Bx._Buf, _Right_data._Mysize + 1); - _My_data._Mysize = _Right_data._Mysize; - _My_data._Myres = _Right_data._Myres; - } - public: _CONSTEXPR20 basic_string& operator=(const basic_string& _Right) { if (this == _STD addressof(_Right)) { @@ -3173,19 +3149,24 @@ public: auto&& _Right_alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Right_al); _Container_proxy_ptr<_Alty> _New_proxy(_Right_alproxy, _Leave_proxy_unbound{}); // throws - if (_Right._Mypair._Myval2._Large_string_engaged()) { - const auto _New_size = _Right._Mypair._Myval2._Mysize; - const auto _New_capacity = _Calculate_growth(_New_size, 0, _Right.max_size()); + const auto _Right_size = _Right._Mypair._Myval2._Mysize; + const _Elem* const _Right_ptr = _Right._Mypair._Myval2._Myptr(); + if (_Entails_large_string(_Right_size)) { + const auto _New_capacity = + _Calculate_growth(_Right_size, _SMALL_STRING_CAPACITY, _Right.max_size()); auto _Right_al_non_const = _Right_al; const auto _New_ptr = _Allocate_from_al(_Right_al_non_const, _New_capacity); // throws - _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_Right._Mypair._Myval2._Bx._Ptr), _New_size + 1); + _Traits::copy(_Unfancy(_New_ptr), _Right_ptr, _Right_size + 1); _Tidy_deallocate(); _Mypair._Myval2._Bx._Ptr = _New_ptr; - _Mypair._Myval2._Mysize = _New_size; + _Mypair._Myval2._Mysize = _Right_size; _Mypair._Myval2._Myres = _New_capacity; } else { - _Copy_assign_val_from_small(_Right); + _Tidy_deallocate(); + _Traits::copy(_Mypair._Myval2._Bx._Buf, _Right_ptr, _Right_size + 1); + _Mypair._Myval2._Mysize = _Right_size; + _Mypair._Myval2._Myres = _SMALL_STRING_CAPACITY; } _Pocca(_Al, _Right_al); From a4734e4a8fa68ce68fd97c45ddcee91b2ddae72d Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sun, 25 Jun 2023 11:29:32 +0800 Subject: [PATCH 14/28] formatting --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index c4bca9842ca..6a99e2a32b4 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -3149,7 +3149,7 @@ public: auto&& _Right_alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Right_al); _Container_proxy_ptr<_Alty> _New_proxy(_Right_alproxy, _Leave_proxy_unbound{}); // throws - const auto _Right_size = _Right._Mypair._Myval2._Mysize; + const auto _Right_size = _Right._Mypair._Myval2._Mysize; const _Elem* const _Right_ptr = _Right._Mypair._Myval2._Myptr(); if (_Entails_large_string(_Right_size)) { const auto _New_capacity = From 323b448568444135f2c13c31d8b592c19ad5c40b Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 26 Jun 2023 10:51:45 +0800 Subject: [PATCH 15/28] various cleanups --- stl/inc/xstring | 65 ++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 6a99e2a32b4..619124a5fd2 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2221,7 +2221,7 @@ public: : sizeof(value_type) <= 4 ? 3 : sizeof(value_type) <= 8 ? 1 : 0; - // capacity for small strings; smallest possible value of _Myres + // capacity in small string mode; smallest possible value of _Myres static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; _CONSTEXPR20 value_type* _Myptr() noexcept { @@ -2242,9 +2242,14 @@ public: return _Result; } - _CONSTEXPR20 bool _Large_string_engaged() const noexcept { + static _CONSTEXPR20 _Large_string_engaged(size_type _Strcap) noexcept { + // decides whether string is in large mode; has no implication on largeness of _Mysize. _STL_INTERNAL_CHECK(_Myres >= _SMALL_STRING_CAPACITY); - return _Myres != _SMALL_STRING_CAPACITY; + return _Strcap != _SMALL_STRING_CAPACITY; + } + + _CONSTEXPR20 bool _Large_string_engaged() const noexcept { + return _Large_string_engaged(_Myres); } constexpr void _Activate_SSO_buffer() noexcept { @@ -2293,8 +2298,8 @@ public: }; _Bxty _Bx; - size_type _Mysize = 0; // current length of string (string::size; <= _Myres) - size_type _Myres = 0; // current storage reserved for string (string::capacity) + size_type _Mysize = 0; // current length of string (string::size(); <= _Myres) + size_type _Myres = 0; // current storage reserved for string (string::capacity()) }; // get _Ty's size after being EBCO'd @@ -2369,7 +2374,7 @@ private: static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; _NODISCARD static _CONSTEXPR20 bool _Entails_large_string(size_type _Size_or_capacity) noexcept { - // decides whether planned size/capacity entails large string mode + // decides whether planned size/capacity entails large mode return _Size_or_capacity > _SMALL_STRING_CAPACITY; } @@ -2431,7 +2436,7 @@ private: } #endif // _HAS_CXX20 // Don't annotate small strings; only annotate on the heap. - if (_Capacity == _SMALL_STRING_CAPACITY || !_Asan_string_should_annotate) { + if (!_Scary_val::_Large_string_engaged(_Capacity) || !_Asan_string_should_annotate) { return; } @@ -2598,8 +2603,8 @@ public: } private: - _NODISCARD static _CONSTEXPR20 pointer _Allocate_from_al(_Alty& _Al, const size_type _New_capacity) { - _STL_INTERNAL_CHECK(_New_capacity > _SMALL_STRING_CAPACITY); + _NODISCARD static _CONSTEXPR20 pointer _Allocate_for_capacity(_Alty& _Al, const size_type _New_capacity) { + _STL_INTERNAL_CHECK(_Entails_Large_string(_New_capacity)); const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); #if _HAS_CXX20 // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, @@ -2614,9 +2619,9 @@ private: return _Fancy_ptr; } - static _CONSTEXPR20 void _Deallocate_from_al( - _Alty& _Al, const pointer _Old_ptr, const size_type _Old_capacity) noexcept { - _STL_INTERNAL_CHECK(_Old_capacity > _SMALL_STRING_CAPACITY); + static _CONSTEXPR20 void _Deallocate_for_capacity( + _Alty& _Al, const pointer& _Old_ptr, const size_type _Old_capacity) noexcept { + _STL_INTERNAL_CHECK(_Entails_Large_string(_Old_capacity)); _Al.deallocate(_Old_ptr, _Old_capacity + 1); } @@ -2665,7 +2670,7 @@ private: _My_data._Myres = _SMALL_STRING_CAPACITY; const size_type _New_capacity = _Calculate_growth(_Count); - const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); _My_data._Mysize = _Count; @@ -2706,7 +2711,7 @@ private: if (_Entails_large_string(_Count)) { const size_type _New_capacity = _Calculate_growth(_Count); - const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); _My_data._Myres = _New_capacity; } @@ -2722,11 +2727,11 @@ private: const auto _Old_ptr = _My_data._Myptr(); const size_type _New_capacity = _Calculate_growth(_My_data._Mysize); - const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity)(); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity)(); // throws _Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize); if (_My_data._Large_string_engaged()) { // Need to deallocate old storage - _Deallocate_from_al(_Al, _My_data._Bx._Ptr, _My_data._Myres); + _Deallocate_for_capacity(_Al, _My_data._Bx._Ptr, _My_data._Myres); _My_data._Bx._Ptr = _New_ptr; } else { _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); @@ -2804,7 +2809,7 @@ public: if (_New_capacity < _New_size) { _New_capacity = _Calculate_growth(_New_size, _SMALL_STRING_CAPACITY, max_size()); - const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); // throws + const pointer _Fancyptr = _Allocate_for_capacity(_Getal(), _New_capacity); // throws _Ptr = _Unfancy(_Fancyptr); _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); } @@ -2875,7 +2880,7 @@ public: const auto _New_capacity = _Calculate_growth(_New_size, _SMALL_STRING_CAPACITY, _Max); auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data); // throws - const pointer _Fancyptr = _Allocate_from_al(_Getal(), _New_capacity); // throws + const pointer _Fancyptr = _Allocate_for_capacity(_Getal(), _New_capacity); // throws // nothrow hereafter _Construct_in_place(_My_data._Bx._Ptr, _Fancyptr); _My_data._Mysize = _New_size; @@ -2940,7 +2945,7 @@ public: struct _Released_buffer { pointer _Ptr; size_type _Size; - size_type _Res; + size_type _Res; // real allocation size, including space reserved for null terminator }; _NODISCARD _Released_buffer _Release_to_buffer(_Alloc& _Al) { @@ -3155,7 +3160,7 @@ public: const auto _New_capacity = _Calculate_growth(_Right_size, _SMALL_STRING_CAPACITY, _Right.max_size()); auto _Right_al_non_const = _Right_al; - const auto _New_ptr = _Allocate_from_al(_Right_al_non_const, _New_capacity); // throws + const auto _New_ptr = _Allocate_for_capacity(_Right_al_non_const, _New_capacity); // throws _Traits::copy(_Unfancy(_New_ptr), _Right_ptr, _Right_size + 1); _Tidy_deallocate(); @@ -3983,12 +3988,12 @@ public: const size_type _Target_capacity = (_STD min)(_My_data._Mysize | _ALLOC_MASK, max_size()); if (_Target_capacity < _My_data._Myres) { // worth shrinking, do it auto& _Al = _Getal(); - const pointer _New_ptr = _Allocate_from_al(_Al, _Target_capacity); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _Target_capacity); // throws _ASAN_STRING_REMOVE(*this); _My_data._Orphan_all(); _Traits::copy(_Unfancy(_New_ptr), _Unfancy(_My_data._Bx._Ptr), _My_data._Mysize + 1); - _Deallocate_from_al(_Al, _My_data._Bx._Ptr, _My_data._Myres); + _Deallocate_for_capacity(_Al, _My_data._Bx._Ptr, _My_data._Myres); _My_data._Bx._Ptr = _New_ptr; _My_data._Myres = _Target_capacity; _ASAN_STRING_CREATE(*this); @@ -4723,15 +4728,15 @@ private: const size_type _Old_capacity = _Mypair._Myval2._Myres; const size_type _New_capacity = _Calculate_growth(_New_size); auto& _Al = _Getal(); - const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws _Mypair._Myval2._Orphan_all(); _ASAN_STRING_REMOVE(*this); _Mypair._Myval2._Mysize = _New_size; _Mypair._Myval2._Myres = _New_capacity; _Fn(_Unfancy(_New_ptr), _New_size, _Args...); - if (_Old_capacity != _SMALL_STRING_CAPACITY) { // large string engaged - _Deallocate_from_al(_Al, _Mypair._Myval2._Bx._Ptr, _Old_capacity); + if (_Scary_val::_Large_string_engaged(_Old_capacity)) { + _Deallocate_for_capacity(_Al, _Mypair._Myval2._Bx._Ptr, _Old_capacity); _Mypair._Myval2._Bx._Ptr = _New_ptr; } else { _Construct_in_place(_Mypair._Myval2._Bx._Ptr, _New_ptr); @@ -4755,17 +4760,17 @@ private: const size_type _Old_capacity = _My_data._Myres; const size_type _New_capacity = _Calculate_growth(_New_size); auto& _Al = _Getal(); - const pointer _New_ptr = _Allocate_from_al(_Al, _New_capacity); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws _My_data._Orphan_all(); _ASAN_STRING_REMOVE(*this); _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; _Elem* const _Raw_new = _Unfancy(_New_ptr); - if (_Old_capacity != _SMALL_STRING_CAPACITY) { // large string engaged + if (_Scary_val::_Large_string_engaged(_Old_capacity)) { const pointer _Old_ptr = _My_data._Bx._Ptr; _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); - _Deallocate_from_al(_Al, _Old_ptr, _Old_capacity); + _Deallocate_for_capacity(_Al, _Old_ptr, _Old_capacity); _My_data._Bx._Ptr = _New_ptr; } else { _Fn(_Raw_new, _My_data._Bx._Buf, _Old_size, _Args...); @@ -4789,7 +4794,7 @@ private: _Destroy_in_place(_My_data._Bx._Ptr); _My_data._Activate_SSO_buffer(); _Traits::copy(_My_data._Bx._Buf, _Unfancy(_Ptr), _My_data._Mysize + 1); - _Deallocate_from_al(_Al, _Ptr, _My_data._Myres); + _Deallocate_for_capacity(_Al, _Ptr, _My_data._Myres); _My_data._Myres = _SMALL_STRING_CAPACITY; } @@ -4818,7 +4823,7 @@ private: auto& _Al = _Getal(); _Destroy_in_place(_My_data._Bx._Ptr); _My_data._Activate_SSO_buffer(); - _Deallocate_from_al(_Al, _Ptr, _My_data._Myres); + _Deallocate_for_capacity(_Al, _Ptr, _My_data._Myres); } _My_data._Mysize = 0; From 4b0f77593505f59eec1de73c88d2fb3ed02ce176 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:19:44 +0800 Subject: [PATCH 16/28] introduce _LEAST_ALLOCATION_SIZE for _Move_assign_from_buffer and _Release_to_buffer --- stl/inc/xstring | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 619124a5fd2..7caff45cce9 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2378,6 +2378,10 @@ private: return _Size_or_capacity > _SMALL_STRING_CAPACITY; } + // least real allocation size, including space reserved for terminating null + // used exclusively by _Move_assign_from_buffer and _Release_to_buffer + static constexpr size_type _LEAST_ALLOCATION_SIZE = _SMALL_STRING_CAPACITY + 1 + 1; + // When doing _String_val operations by memcpy, we are touching: // _String_val::_Bx::_Buf (type is array of _Elem) // _String_val::_Bx::_Ptr (type is pointer) @@ -2918,14 +2922,15 @@ public: _Tidy_init(); } - _NODISCARD bool _Move_assign_from_buffer(_Elem* const _Right, const size_type _Size, const size_type _Res) { + _NODISCARD bool _Move_assign_from_buffer( + _Elem* const _Right, const size_type _Size, const size_type _Res /* real allocation size */) { // Move assign from a buffer, used exclusively by basic_stringbuf; returns _Large_string_engaged() auto& _My_data = _Mypair._Myval2; _STL_INTERNAL_CHECK(!_My_data._Large_string_engaged() && _My_data._Mysize == 0); _STL_INTERNAL_CHECK(_Size < _Res); // So there is room for null terminator _Traits::assign(_Right[_Size], _Elem()); - const bool _Is_large = _Res > _BUF_SIZE; // Note: _BUF_SIZE because _Res now includes the null terminator + const bool _Is_large = _Res >= _LEAST_ALLOCATION_SIZE; if (_Is_large) { _ASAN_STRING_REMOVE(*this); _Construct_in_place(_My_data._Bx._Ptr, _Refancy(_Right)); @@ -2958,10 +2963,10 @@ public: _Result._Ptr = _My_data._Bx._Ptr; _Result._Res = _My_data._Myres + 1; } else { - // use _BUF_SIZE + 1 to avoid SSO, if the buffer is assigned back - _Result._Ptr = _Al.allocate(_BUF_SIZE + 1); + // use _LEAST_ALLOCATION_SIZE to avoid SSO, if the buffer is assigned back + _Result._Ptr = _Al.allocate(_LEAST_ALLOCATION_SIZE); _Traits::copy(_Unfancy(_Result._Ptr), _My_data._Bx._Buf, _BUF_SIZE); - _Result._Res = _BUF_SIZE + 1; + _Result._Res = _LEAST_ALLOCATION_SIZE; } _My_data._Orphan_all(); _Tidy_init(); From 6586c0eabdb47024271018509f524e96fd7856c0 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:21:26 +0800 Subject: [PATCH 17/28] oops --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 7caff45cce9..37c6b9f99ef 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2244,7 +2244,7 @@ public: static _CONSTEXPR20 _Large_string_engaged(size_type _Strcap) noexcept { // decides whether string is in large mode; has no implication on largeness of _Mysize. - _STL_INTERNAL_CHECK(_Myres >= _SMALL_STRING_CAPACITY); + _STL_INTERNAL_CHECK(_Strcap >= _SMALL_STRING_CAPACITY); return _Strcap != _SMALL_STRING_CAPACITY; } From 8adafe1542039dc8391ddd5ba32ec295a309502e Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:23:02 +0800 Subject: [PATCH 18/28] hm... --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 37c6b9f99ef..ccf6a652b28 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2242,7 +2242,7 @@ public: return _Result; } - static _CONSTEXPR20 _Large_string_engaged(size_type _Strcap) noexcept { + static _CONSTEXPR20 bool _Large_string_engaged(size_type _Strcap) noexcept { // decides whether string is in large mode; has no implication on largeness of _Mysize. _STL_INTERNAL_CHECK(_Strcap >= _SMALL_STRING_CAPACITY); return _Strcap != _SMALL_STRING_CAPACITY; From 915d12105457547b1601b0ead25586b321e0c776 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:56:46 +0800 Subject: [PATCH 19/28] nit --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index ccf6a652b28..64e758d2846 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2243,7 +2243,7 @@ public: } static _CONSTEXPR20 bool _Large_string_engaged(size_type _Strcap) noexcept { - // decides whether string is in large mode; has no implication on largeness of _Mysize. + // decides whether string is in large mode; has no implication on largeness of _Mysize _STL_INTERNAL_CHECK(_Strcap >= _SMALL_STRING_CAPACITY); return _Strcap != _SMALL_STRING_CAPACITY; } From 3f2b4d62aad20c429cb764d2aad998cab4cd416f Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:48:48 +0800 Subject: [PATCH 20/28] make it clear that `basic_string::_BUF_SIZE/...` is `size_type` --- stl/inc/xstring | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 64e758d2846..91c88f7fcc1 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2369,9 +2369,9 @@ public: using const_reverse_iterator = _STD reverse_iterator; private: - static constexpr auto _BUF_SIZE = _Scary_val::_BUF_SIZE; - static constexpr auto _ALLOC_MASK = _Scary_val::_ALLOC_MASK; - static constexpr auto _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; + static constexpr size_type _BUF_SIZE = _Scary_val::_BUF_SIZE; + static constexpr size_type _ALLOC_MASK = _Scary_val::_ALLOC_MASK; + static constexpr size_type _SMALL_STRING_CAPACITY = _Scary_val::_SMALL_STRING_CAPACITY; _NODISCARD static _CONSTEXPR20 bool _Entails_large_string(size_type _Size_or_capacity) noexcept { // decides whether planned size/capacity entails large mode From d8bd25b3d6ad9ec97a8b2529c17734e73fa8d36d Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Tue, 27 Jun 2023 09:00:15 +0800 Subject: [PATCH 21/28] fix silly typo --- stl/inc/xstring | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 91c88f7fcc1..d5c1b06b7fd 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2608,7 +2608,7 @@ public: private: _NODISCARD static _CONSTEXPR20 pointer _Allocate_for_capacity(_Alty& _Al, const size_type _New_capacity) { - _STL_INTERNAL_CHECK(_Entails_Large_string(_New_capacity)); + _STL_INTERNAL_CHECK(_Entails_large_string(_New_capacity)); const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); #if _HAS_CXX20 // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, @@ -2625,7 +2625,7 @@ private: static _CONSTEXPR20 void _Deallocate_for_capacity( _Alty& _Al, const pointer& _Old_ptr, const size_type _Old_capacity) noexcept { - _STL_INTERNAL_CHECK(_Entails_Large_string(_Old_capacity)); + _STL_INTERNAL_CHECK(_Entails_large_string(_Old_capacity)); _Al.deallocate(_Old_ptr, _Old_capacity + 1); } From f8e81b01429cf3bdb97b15b650f74843bcb9784a Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 28 Jun 2023 20:59:15 +0800 Subject: [PATCH 22/28] nits --- stl/inc/xstring | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index d5c1b06b7fd..7b7440e2381 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2224,7 +2224,7 @@ public: // capacity in small string mode; smallest possible value of _Myres static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; - _CONSTEXPR20 value_type* _Myptr() noexcept { + _NODISCARD _CONSTEXPR20 value_type* _Myptr() noexcept { value_type* _Result = _Bx._Buf; if (_Large_string_engaged()) { _Result = _Unfancy(_Bx._Ptr); @@ -2233,7 +2233,7 @@ public: return _Result; } - _CONSTEXPR20 const value_type* _Myptr() const noexcept { + _NODISCARD _CONSTEXPR20 const value_type* _Myptr() const noexcept { const value_type* _Result = _Bx._Buf; if (_Large_string_engaged()) { _Result = _Unfancy(_Bx._Ptr); @@ -2242,17 +2242,17 @@ public: return _Result; } - static _CONSTEXPR20 bool _Large_string_engaged(size_type _Strcap) noexcept { - // decides whether string is in large mode; has no implication on largeness of _Mysize + _NODISCARD static _CONSTEXPR20 bool _Large_string_engaged(size_type _Strcap) noexcept { + // decides whether string is in large mode; has no implication on largeness of string's size _STL_INTERNAL_CHECK(_Strcap >= _SMALL_STRING_CAPACITY); return _Strcap != _SMALL_STRING_CAPACITY; } - _CONSTEXPR20 bool _Large_string_engaged() const noexcept { + _NODISCARD _CONSTEXPR20 bool _Large_string_engaged() const noexcept { return _Large_string_engaged(_Myres); } - constexpr void _Activate_SSO_buffer() noexcept { + _CONSTEXPR20 void _Activate_SSO_buffer() noexcept { // start the lifetime of the array elements #if _HAS_CXX20 if (_STD is_constant_evaluated()) { @@ -2281,7 +2281,7 @@ public: _Xout_of_range("invalid string position"); } - _CONSTEXPR20 size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const noexcept { + _NODISCARD _CONSTEXPR20 size_type _Clamp_suffix_size(const size_type _Off, const size_type _Size) const noexcept { // trims _Size to the longest it can be assuming a string at/after _Off return (_STD min)(_Size, _Mysize - _Off); } From 10b086cfebee794e6ff736fc30bfdb675792f9dc Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 1 Jul 2023 15:51:52 +0800 Subject: [PATCH 23/28] remove redundant `()` --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 7b7440e2381..94d01bc7ac9 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2731,7 +2731,7 @@ private: const auto _Old_ptr = _My_data._Myptr(); const size_type _New_capacity = _Calculate_growth(_My_data._Mysize); - const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity)(); // throws + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws _Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize); if (_My_data._Large_string_engaged()) { // Need to deallocate old storage From b52c6bb9deb2f58474a1ca9d540ab4421135ea25 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:34:22 +0800 Subject: [PATCH 24/28] fix_starts_as_small_string --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 94d01bc7ac9..44478515627 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2299,7 +2299,7 @@ public: _Bxty _Bx; size_type _Mysize = 0; // current length of string (string::size(); <= _Myres) - size_type _Myres = 0; // current storage reserved for string (string::capacity()) + size_type _Myres = _SMALL_STRING_CAPACITY; // current storage reserved for string (string::capacity()) }; // get _Ty's size after being EBCO'd From 8bed5ecb09050b37c35bc5f06e1eaff2a580a273 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:12:48 +0800 Subject: [PATCH 25/28] remove internal check in _Large_string_engaged; various documentation fixes --- stl/inc/xstring | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 44478515627..a359fdc46f2 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2221,7 +2221,7 @@ public: : sizeof(value_type) <= 4 ? 3 : sizeof(value_type) <= 8 ? 1 : 0; - // capacity in small string mode; smallest possible value of _Myres + // capacity in SSO mode static constexpr size_type _SMALL_STRING_CAPACITY = _BUF_SIZE - 1; _NODISCARD _CONSTEXPR20 value_type* _Myptr() noexcept { @@ -2242,10 +2242,10 @@ public: return _Result; } - _NODISCARD static _CONSTEXPR20 bool _Large_string_engaged(size_type _Strcap) noexcept { - // decides whether string is in large mode; has no implication on largeness of string's size - _STL_INTERNAL_CHECK(_Strcap >= _SMALL_STRING_CAPACITY); - return _Strcap != _SMALL_STRING_CAPACITY; + _NODISCARD static _CONSTEXPR20 bool _Large_string_engaged(size_type _Capacity) noexcept { + // determines whether large mode is used for this capacity + // has no implication on largeness of string's size + return _Capacity > _SMALL_STRING_CAPACITY; } _NODISCARD _CONSTEXPR20 bool _Large_string_engaged() const noexcept { @@ -2298,8 +2298,9 @@ public: }; _Bxty _Bx; - size_type _Mysize = 0; // current length of string (string::size(); <= _Myres) - size_type _Myres = _SMALL_STRING_CAPACITY; // current storage reserved for string (string::capacity()) + // invariant: _Myres >= _Mysize, and _Myres >= _SMALL_STRING_CAPACITY + size_type _Mysize = 0; // current length of string (size) + size_type _Myres = _SMALL_STRING_CAPACITY; // current storage reserved for string (capacity) }; // get _Ty's size after being EBCO'd @@ -2607,15 +2608,15 @@ public: } private: - _NODISCARD static _CONSTEXPR20 pointer _Allocate_for_capacity(_Alty& _Al, const size_type _New_capacity) { - _STL_INTERNAL_CHECK(_Entails_large_string(_New_capacity)); - const pointer _Fancy_ptr = _Al.allocate(_New_capacity + 1); + _NODISCARD static _CONSTEXPR20 pointer _Allocate_for_capacity(_Alty& _Al, const size_type _Capacity) { + _STL_INTERNAL_CHECK(_Entails_large_string(_Capacity)); + const pointer _Fancy_ptr = _Al.allocate(_Capacity + 1);// +1 for null terminator #if _HAS_CXX20 // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, // but likely more impactful to throughput. if (_STD is_constant_evaluated()) { _Elem* const _Ptr = _Unfancy(_Fancy_ptr); - for (size_type _Idx = 0; _Idx < _New_capacity + 1; ++_Idx) { + for (size_type _Idx = 0; _Idx < _Capacity + 1; ++_Idx) { _STD construct_at(_Ptr + _Idx); } } @@ -2624,9 +2625,9 @@ private: } static _CONSTEXPR20 void _Deallocate_for_capacity( - _Alty& _Al, const pointer& _Old_ptr, const size_type _Old_capacity) noexcept { - _STL_INTERNAL_CHECK(_Entails_large_string(_Old_capacity)); - _Al.deallocate(_Old_ptr, _Old_capacity + 1); + _Alty& _Al, const pointer& _Old_ptr, const size_type _Capacity) noexcept { + _STL_INTERNAL_CHECK(_Entails_large_string(_Capacity)); + _Al.deallocate(_Old_ptr, _Capacity + 1); } enum class _Construct_strategy : uint8_t { _From_char, _From_ptr, _From_string }; @@ -2950,7 +2951,7 @@ public: struct _Released_buffer { pointer _Ptr; size_type _Size; - size_type _Res; // real allocation size, including space reserved for null terminator + size_type _Res; // real allocation size }; _NODISCARD _Released_buffer _Release_to_buffer(_Alloc& _Al) { From dfd82944c7abb57e059e2b3c0e6d51b7ec31a065 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:20:06 +0800 Subject: [PATCH 26/28] formatting --- stl/inc/xstring | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index a359fdc46f2..c6d4a429378 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2610,7 +2610,7 @@ public: private: _NODISCARD static _CONSTEXPR20 pointer _Allocate_for_capacity(_Alty& _Al, const size_type _Capacity) { _STL_INTERNAL_CHECK(_Entails_large_string(_Capacity)); - const pointer _Fancy_ptr = _Al.allocate(_Capacity + 1);// +1 for null terminator + const pointer _Fancy_ptr = _Al.allocate(_Capacity + 1); // +1 for null terminator #if _HAS_CXX20 // Start element lifetimes to avoid UB. This is a more general mechanism than _String_val::_Activate_SSO_buffer, // but likely more impactful to throughput. From 0d9eb9665b4c14bb05b527b18e986ea7b7f13136 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 10 Jul 2023 23:12:41 -0700 Subject: [PATCH 27/28] Use `_Entails_large_string` instead of overloading `_Large_string_engaged`. Also refine comment. --- stl/inc/xstring | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index c6d4a429378..3748dd5a68a 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2242,14 +2242,10 @@ public: return _Result; } - _NODISCARD static _CONSTEXPR20 bool _Large_string_engaged(size_type _Capacity) noexcept { - // determines whether large mode is used for this capacity - // has no implication on largeness of string's size - return _Capacity > _SMALL_STRING_CAPACITY; - } - _NODISCARD _CONSTEXPR20 bool _Large_string_engaged() const noexcept { - return _Large_string_engaged(_Myres); + // Determines whether large mode is used for the string's capacity. + // Doesn't imply anything about the largeness of the string's size. + return _Myres > _SMALL_STRING_CAPACITY; } _CONSTEXPR20 void _Activate_SSO_buffer() noexcept { @@ -2441,7 +2437,7 @@ private: } #endif // _HAS_CXX20 // Don't annotate small strings; only annotate on the heap. - if (!_Scary_val::_Large_string_engaged(_Capacity) || !_Asan_string_should_annotate) { + if (!_Entails_large_string(_Capacity) || !_Asan_string_should_annotate) { return; } @@ -4741,7 +4737,7 @@ private: _Mypair._Myval2._Mysize = _New_size; _Mypair._Myval2._Myres = _New_capacity; _Fn(_Unfancy(_New_ptr), _New_size, _Args...); - if (_Scary_val::_Large_string_engaged(_Old_capacity)) { + if (_Entails_large_string(_Old_capacity)) { _Deallocate_for_capacity(_Al, _Mypair._Myval2._Bx._Ptr, _Old_capacity); _Mypair._Myval2._Bx._Ptr = _New_ptr; } else { @@ -4773,7 +4769,7 @@ private: _My_data._Mysize = _New_size; _My_data._Myres = _New_capacity; _Elem* const _Raw_new = _Unfancy(_New_ptr); - if (_Scary_val::_Large_string_engaged(_Old_capacity)) { + if (_Entails_large_string(_Old_capacity)) { const pointer _Old_ptr = _My_data._Bx._Ptr; _Fn(_Raw_new, _Unfancy(_Old_ptr), _Old_size, _Args...); _Deallocate_for_capacity(_Al, _Old_ptr, _Old_capacity); From b32a4c816904ee8d113bf6e2c391dec6975f9457 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 10 Jul 2023 23:21:12 -0700 Subject: [PATCH 28/28] Reorder `basic_string(nullptr_t)` to match the Standard's order. --- stl/inc/xstring | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 3748dd5a68a..234a533ad76 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2551,10 +2551,6 @@ public: _Construct<_Construct_strategy::_From_ptr>(_Ptr, _Count); } -#if _HAS_CXX23 - basic_string(nullptr_t) = delete; -#endif // _HAS_CXX23 - _CONSTEXPR20 basic_string(_In_z_ const _Elem* const _Ptr) : _Mypair(_Zero_then_variadic_args_t{}) { _Construct<_Construct_strategy::_From_ptr>(_Ptr, _Convert_size(_Traits::length(_Ptr))); } @@ -2567,6 +2563,10 @@ public: _Construct<_Construct_strategy::_From_ptr>(_Ptr, _Convert_size(_Traits::length(_Ptr))); } +#if _HAS_CXX23 + basic_string(nullptr_t) = delete; +#endif // _HAS_CXX23 + _CONSTEXPR20 basic_string(_CRT_GUARDOVERFLOW const size_type _Count, const _Elem _Ch) : _Mypair(_Zero_then_variadic_args_t{}) { // construct from _Count * _Ch _Construct<_Construct_strategy::_From_char>(_Ch, _Count);