From e4fc044fa5a066c6889c8bed8fbc0889ab38d970 Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Sat, 18 May 2024 16:40:49 +0200 Subject: [PATCH 1/6] Improve string allocation * Remove unnecessary std::max in shrink_to_fit * Remove unnecessary condition in __recommend * Fix allocation for string with small_size required less bytes (24 instead of 26, 12 instead of 11, etc) ``` #include #include using size_type = size_t; template struct __long { long_type x; long_type y; long_type z; }; template static constexpr size_type min_cap = (sizeof(__long) - 1) / sizeof(value_type) > 2 ? (sizeof(__long) - 1) / sizeof(value_type) : 2; template static constexpr size_type alignment = sizeof(long_type); template static constexpr size_type __align_it(size_type __s) noexcept { return (__s + (__a - 1)) & ~(__a - 1); } template static constexpr size_type __recommend(size_type __s) noexcept { constexpr auto __min_cap = min_cap; constexpr auto __alignment = alignment; if (__s < __min_cap) { return static_cast(__min_cap) - 1; } const size_type __boundary = sizeof(value_type) < __alignment ? __alignment / sizeof(value_type) : __endian_factor; size_type __guess = __align_it<__boundary>(__s + 1) - 1; //if (__guess == __min_cap) __guess += __endian_factor; return __guess; } template static constexpr auto to_alloc(size_type s) { return __recommend(s) + 1; } int main() { static constexpr auto char8_64 = min_cap; static_assert(char8_64 == 23); static constexpr auto char16_64 = min_cap; static_assert(char16_64 == 11); static constexpr auto char32_64 = min_cap; static_assert(char32_64 == 5); static constexpr auto char64_64 = min_cap; static_assert(char64_64 == 2); static constexpr auto char8_32 = min_cap; static_assert(char8_32 == 11); static constexpr auto char16_32 = min_cap; static_assert(char16_32 == 5); static constexpr auto char32_32 = min_cap; static_assert(char32_32 == 2); static constexpr auto char64_32 = min_cap; static_assert(char64_32 == 2); // 64 bit system, __endian_factor = 1 static_assert(to_alloc(0) == char8_64); static_assert(to_alloc(0) == char16_64); static_assert(to_alloc(0) == char32_64); static_assert(to_alloc(0) == char64_64); static_assert(to_alloc(char8_64) == char8_64 + 1); static_assert(to_alloc(char16_64) == char16_64 + 1); static_assert(to_alloc(char32_64) == char32_64 + 1); static_assert(to_alloc(char64_64) == char64_64 + 1); static_assert(to_alloc(char8_64 + 1) == 32); static_assert(to_alloc(char16_64 + 1) == 16); static_assert(to_alloc(char32_64 + 1) == 8); static_assert(to_alloc(char64_64 + 1) == 4); // 64 bit system, __endian_factor = 2 static_assert(to_alloc(0) == char8_64); static_assert(to_alloc(0) == char16_64); static_assert(to_alloc(0) == char32_64); static_assert(to_alloc(0) == char64_64); static_assert(to_alloc(char8_64) == char8_64 + 1); static_assert(to_alloc(char16_64) == char16_64 + 1); static_assert(to_alloc(char32_64) == char32_64 + 1); static_assert(to_alloc(char64_64) == char64_64 + 2); static_assert(to_alloc(char8_64 + 1) == 32); static_assert(to_alloc(char16_64 + 1) == 16); static_assert(to_alloc(char32_64 + 1) == 8); static_assert(to_alloc(char64_64 + 1) == 4); // 32 bit system, __endian_factor = 1 static_assert(to_alloc(0) == char8_32); static_assert(to_alloc(0) == char16_32); static_assert(to_alloc(0) == char32_32); static_assert(to_alloc(0) == char64_32); static_assert(to_alloc(char8_32) == char8_32 + 1); static_assert(to_alloc(char16_32) == char16_32 + 1); static_assert(to_alloc(char32_32) == char32_32 + 1); static_assert(to_alloc(char64_32) == char64_32 + 1); static_assert(to_alloc(char8_32 + 1) == 16); static_assert(to_alloc(char16_32 + 1) == 8); static_assert(to_alloc(char32_32 + 1) == 4); static_assert(to_alloc(char64_32 + 1) == 4); // 32 bit system, __endian_factor = 2 static_assert(to_alloc(0) == char8_32); static_assert(to_alloc(0) == char16_32); static_assert(to_alloc(0) == char32_32); static_assert(to_alloc(0) == char64_32); static_assert(to_alloc(char8_32) == char8_32 + 1); static_assert(to_alloc(char16_32) == char16_32 + 1); static_assert(to_alloc(char32_32) == 4); static_assert(to_alloc(char64_32) == 4); static_assert(to_alloc(char8_32 + 1) == 16); static_assert(to_alloc(char16_32 + 1) == 8); static_assert(to_alloc(char32_32 + 1) == 4); static_assert(to_alloc(char64_32 + 1) == 4); } ``` --- libcxx/include/string | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libcxx/include/string b/libcxx/include/string index 1db803e822d72..4d66e1a6be31e 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1984,13 +1984,8 @@ private: } enum { __alignment = 8 }; static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __s) _NOEXCEPT { - if (__s < __min_cap) { - return static_cast(__min_cap) - 1; - } const size_type __boundary = sizeof(value_type) < __alignment ? __alignment / sizeof(value_type) : __endian_factor; size_type __guess = __align_it<__boundary>(__s + 1) - 1; - if (__guess == __min_cap) - __guess += __endian_factor; return __guess; } @@ -3249,8 +3244,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re if (__requested_capacity <= capacity()) return; - size_type __target_capacity = std::max(__requested_capacity, size()); - __target_capacity = __recommend(__target_capacity); + __target_capacity = __recommend(__target_capacity); if (__target_capacity == capacity()) return; From d05b553ee30f98fb813ca88947622b6ec4764233 Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Sat, 18 May 2024 17:17:00 +0200 Subject: [PATCH 2/6] Fix compilation --- libcxx/include/string | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/string b/libcxx/include/string index 4d66e1a6be31e..868bc820d6512 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3244,7 +3244,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re if (__requested_capacity <= capacity()) return; - __target_capacity = __recommend(__target_capacity); + size_type __target_capacity = __recommend(__target_capacity); if (__target_capacity == capacity()) return; From 4651e1cfd6f1b811b791c469f26797429224d45f Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Sat, 18 May 2024 17:18:19 +0200 Subject: [PATCH 3/6] Fix compilation --- libcxx/include/string | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/string b/libcxx/include/string index 868bc820d6512..7b1c46fc0d89e 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3244,7 +3244,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re if (__requested_capacity <= capacity()) return; - size_type __target_capacity = __recommend(__target_capacity); + size_type __target_capacity = __recommend(__requested_capacity); if (__target_capacity == capacity()) return; From 757d827e972f056b5787c6108c6ab2fc08bf7541 Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Sat, 18 May 2024 21:47:13 +0200 Subject: [PATCH 4/6] Fix shrink_to_fit --- libcxx/include/string | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/include/string b/libcxx/include/string index 7b1c46fc0d89e..e72270579dd9d 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3253,7 +3253,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re template inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::shrink_to_fit() _NOEXCEPT { - size_type __target_capacity = __recommend(size()); + size_type __target_capacity = size(); + __target_capacity = __target_capacity < __min_cap ? static_cast(__min_cap) - 1 : __recommend(__target_capacity); if (__target_capacity == capacity()) return; From 80f6b053a22f255c8391fd43bf7bd67888830f2c Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Thu, 22 May 2025 21:38:17 +0300 Subject: [PATCH 5/6] Update string --- libcxx/include/string | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/string b/libcxx/include/string index d58e95a0ea659..25ee09c6bd408 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -2279,6 +2279,7 @@ private: } enum { __alignment = 8 }; static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __s) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__s >= __min_cap, "recommend is called for small string capacity"); const size_type __boundary = sizeof(value_type) < __alignment ? __alignment / sizeof(value_type) : __endian_factor; size_type __guess = __align_it<__boundary>(__s + 1) - 1; _LIBCPP_ASSERT_INTERNAL(__guess >= __s, "recommendation is below the requested size"); From 64ad928d06c80fb0ee8e151e34a4726044991bb5 Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Sat, 24 May 2025 10:29:15 +0300 Subject: [PATCH 6/6] Fix code format --- libcxx/include/string | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/include/string b/libcxx/include/string index 25ee09c6bd408..e861096dbc098 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3418,7 +3418,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re template inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::shrink_to_fit() _NOEXCEPT { size_type __target_capacity = size(); - __target_capacity = __target_capacity < __min_cap ? static_cast(__min_cap) - 1 : __recommend(__target_capacity); + __target_capacity = + __target_capacity < __min_cap ? static_cast(__min_cap) - 1 : __recommend(__target_capacity); if (__target_capacity == capacity()) return;