[libcxx-commits] [libcxx] Improve string allocation (PR #92652)

Valery Mironov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 28 10:19:03 PDT 2024


https://github.com/MBkkt updated https://github.com/llvm/llvm-project/pull/92652

>From e4fc044fa5a066c6889c8bed8fbc0889ab38d970 Mon Sep 17 00:00:00 2001
From: Valery Mironov <valera.mironow at gmail.com>
Date: Sat, 18 May 2024 16:40:49 +0200
Subject: [PATCH 1/4] 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 <cstddef>
#include <cstdint>

using size_type = size_t;

template <typename long_type>
struct __long {
    long_type x;
    long_type y;
    long_type z;
};

template <typename value_type, typename long_type>
static constexpr size_type min_cap =
    (sizeof(__long<long_type>) - 1) / sizeof(value_type) > 2
        ? (sizeof(__long<long_type>) - 1) / sizeof(value_type)
        : 2;

template <typename long_type>
static constexpr size_type alignment = sizeof(long_type);

template <size_type __a>
static constexpr size_type __align_it(size_type __s) noexcept {
    return (__s + (__a - 1)) & ~(__a - 1);
}

template <typename value_type, typename long_type, size_type __endian_factor>
static constexpr size_type __recommend(size_type __s) noexcept {
    constexpr auto __min_cap = min_cap<value_type, long_type>;
    constexpr auto __alignment = alignment<long_type>;
    if (__s < __min_cap) {
        return static_cast<size_type>(__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 <typename value_type, typename long_type, size_type __endian_factor>
static constexpr auto to_alloc(size_type s) {
    return __recommend<value_type, long_type, __endian_factor>(s) + 1;
}

int main() {
    static constexpr auto char8_64 = min_cap<char, long>;
    static_assert(char8_64 == 23);
    static constexpr auto char16_64 = min_cap<char16_t, long>;
    static_assert(char16_64 == 11);
    static constexpr auto char32_64 = min_cap<char32_t, long>;
    static_assert(char32_64 == 5);
    static constexpr auto char64_64 = min_cap<long, long>;
    static_assert(char64_64 == 2);

    static constexpr auto char8_32 = min_cap<char, int>;
    static_assert(char8_32 == 11);
    static constexpr auto char16_32 = min_cap<char16_t, int>;
    static_assert(char16_32 == 5);
    static constexpr auto char32_32 = min_cap<char32_t, int>;
    static_assert(char32_32 == 2);
    static constexpr auto char64_32 = min_cap<long, int>;
    static_assert(char64_32 == 2);


    // 64 bit system, __endian_factor = 1
    static_assert(to_alloc<char, long, 1>(0) == char8_64);
    static_assert(to_alloc<char16_t, long, 1>(0) == char16_64);
    static_assert(to_alloc<char32_t, long, 1>(0) == char32_64);
    static_assert(to_alloc<long, long, 1>(0) == char64_64);

    static_assert(to_alloc<char, long, 1>(char8_64) == char8_64 + 1);
    static_assert(to_alloc<char16_t, long, 1>(char16_64) == char16_64 + 1);
    static_assert(to_alloc<char32_t, long, 1>(char32_64) == char32_64 + 1);
    static_assert(to_alloc<long, long, 1>(char64_64) == char64_64 + 1);

    static_assert(to_alloc<char, long, 1>(char8_64 + 1) == 32);
    static_assert(to_alloc<char16_t, long, 1>(char16_64 + 1) == 16);
    static_assert(to_alloc<char32_t, long, 1>(char32_64 + 1) == 8);
    static_assert(to_alloc<long, long, 1>(char64_64 + 1) == 4);


    // 64 bit system, __endian_factor = 2
    static_assert(to_alloc<char, long, 2>(0) == char8_64);
    static_assert(to_alloc<char16_t, long, 2>(0) == char16_64);
    static_assert(to_alloc<char32_t, long, 2>(0) == char32_64);
    static_assert(to_alloc<long, long, 2>(0) == char64_64);

    static_assert(to_alloc<char, long, 2>(char8_64) == char8_64 + 1);
    static_assert(to_alloc<char16_t, long, 2>(char16_64) == char16_64 + 1);
    static_assert(to_alloc<char32_t, long, 2>(char32_64) == char32_64 + 1);
    static_assert(to_alloc<long, long, 2>(char64_64) == char64_64 + 2);

    static_assert(to_alloc<char, long, 2>(char8_64 + 1) == 32);
    static_assert(to_alloc<char16_t, long, 2>(char16_64 + 1) == 16);
    static_assert(to_alloc<char32_t, long, 2>(char32_64 + 1) == 8);
    static_assert(to_alloc<long, long, 2>(char64_64 + 1) == 4);


    // 32 bit system, __endian_factor = 1
    static_assert(to_alloc<char, int, 1>(0) == char8_32);
    static_assert(to_alloc<char16_t, int, 1>(0) == char16_32);
    static_assert(to_alloc<char32_t, int, 1>(0) == char32_32);
    static_assert(to_alloc<long, int, 1>(0) == char64_32);

    static_assert(to_alloc<char, int, 1>(char8_32) == char8_32 + 1);
    static_assert(to_alloc<char16_t, int, 1>(char16_32) == char16_32 + 1);
    static_assert(to_alloc<char32_t, int, 1>(char32_32) == char32_32 + 1);
    static_assert(to_alloc<long, int, 1>(char64_32) == char64_32 + 1);

    static_assert(to_alloc<char, int, 1>(char8_32 + 1) == 16);
    static_assert(to_alloc<char16_t, int, 1>(char16_32 + 1) == 8);
    static_assert(to_alloc<char32_t, int, 1>(char32_32 + 1) == 4);
    static_assert(to_alloc<long, int, 1>(char64_32 + 1) == 4);


    // 32 bit system, __endian_factor = 2
    static_assert(to_alloc<char, int, 2>(0) == char8_32);
    static_assert(to_alloc<char16_t, int, 2>(0) == char16_32);
    static_assert(to_alloc<char32_t, int, 2>(0) == char32_32);
    static_assert(to_alloc<long, int, 2>(0) == char64_32);

    static_assert(to_alloc<char, int, 2>(char8_32) == char8_32 + 1);
    static_assert(to_alloc<char16_t, int, 2>(char16_32) == char16_32 + 1);
    static_assert(to_alloc<char32_t, int, 2>(char32_32) == 4);
    static_assert(to_alloc<long, int, 2>(char64_32) == 4);

    static_assert(to_alloc<char, int, 2>(char8_32 + 1) == 16);
    static_assert(to_alloc<char16_t, int, 2>(char16_32 + 1) == 8);
    static_assert(to_alloc<char32_t, int, 2>(char32_32 + 1) == 4);
    static_assert(to_alloc<long, int, 2>(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 1db803e822d727..4d66e1a6be31ea 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<size_type>(__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 <valera.mironow at gmail.com>
Date: Sat, 18 May 2024 17:17:00 +0200
Subject: [PATCH 2/4] Fix compilation

---
 libcxx/include/string | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 4d66e1a6be31ea..868bc820d65128 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 <valera.mironow at gmail.com>
Date: Sat, 18 May 2024 17:18:19 +0200
Subject: [PATCH 3/4] Fix compilation

---
 libcxx/include/string | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index 868bc820d65128..7b1c46fc0d89eb 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 <valera.mironow at gmail.com>
Date: Sat, 18 May 2024 21:47:13 +0200
Subject: [PATCH 4/4] 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 7b1c46fc0d89eb..e72270579dd9d2 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 <class _CharT, class _Traits, class _Allocator>
 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<size_type>(__min_cap) - 1 : __recommend(__target_capacity);
   if (__target_capacity == capacity())
     return;
 



More information about the libcxx-commits mailing list