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

via libcxx-commits libcxx-commits at lists.llvm.org
Sat May 18 07:41:57 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Valery Mironov (MBkkt)

<details>
<summary>Changes</summary>

* 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)


https://godbolt.org/z/fGP6e11ed

```
#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);
}
```

---
Full diff: https://github.com/llvm/llvm-project/pull/92652.diff


1 Files Affected:

- (modified) libcxx/include/string (+1-7) 


``````````diff
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<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;
 

``````````

</details>


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


More information about the libcxx-commits mailing list