[libcxx-commits] [libcxx] [libc++] Make __allocate_long_buffer a constructor of __long (PR #166451)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Tue Nov 4 13:49:53 PST 2025


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/166451

We currently have `__allocate_long_buffer` as a static function inside `basic_string`. This functions basically just creates a `__long` string representation, so this patch makes it a constructor of that internal struct instead. This reduces the library-internal interface a bit, making it less likely to be misused.


>From 44621945f201e0b081f9a451f212490eb2b19534 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 4 Nov 2025 22:47:43 +0100
Subject: [PATCH] [libc++] Make __allocate_long_buffer a constructor of __long

---
 libcxx/include/string | 54 +++++++++++++++++++++----------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/libcxx/include/string b/libcxx/include/string
index ede42467b99fe..4249f43d1ac39 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -884,9 +884,18 @@ private:
   struct __long {
     __long() = default;
 
-    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(__alloc_result __alloc, size_type __size)
-        : __is_long_(true), __cap_(__alloc.count / __endian_factor), __size_(__size), __data_(__alloc.ptr) {
-      _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__alloc.count), "Long capacity should always be larger than the SSO");
+    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(_Allocator& __allocator, size_type __size)
+        : __is_long_(true), __size_(__size) {
+      _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__size), "Long capacity should always be larger than the SSO");
+      auto __allocation = std::__allocate_at_least(__allocator, __recommend(__size) + 1);
+
+      __cap_  = __allocation.count / __endian_factor;
+      __data_ = __allocation.ptr;
+
+      if (__libcpp_is_constant_evaluated()) {
+        for (size_type __i = 0; __i != __allocation.count; ++__i)
+          std::__construct_at(std::addressof(__allocation.ptr[__i]));
+      }
     }
 
     struct _LIBCPP_PACKED {
@@ -906,6 +915,13 @@ private:
     };
     _LIBCPP_NO_UNIQUE_ADDRESS __padding<sizeof(value_type) - 1> __padding_;
     value_type __data_[__min_cap];
+
+    __short() = default;
+    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __short(size_type __size)
+        : __is_long_(false), __size_(static_cast<unsigned char>(__size)), __padding_(), __data_() {
+      _LIBCPP_ASSERT_INTERNAL(
+          __fits_in_sso(__size), "Trying to construct short string with a size greater than the small buffer size");
+    }
   };
 
 #  endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
@@ -2255,19 +2271,6 @@ private:
   // These functions are only responsible for managing the buffer itself, not the value inside the buffer. As such,
   // none of these facilities ensure that there is a null terminator at `data()[size()]`.
 
-  // Allocate a buffer of __capacity size with __alloc and return it
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __long
-  __allocate_long_buffer(_Allocator& __alloc, size_type __capacity) {
-    auto __buffer = std::__allocate_at_least(__alloc, __recommend(__capacity) + 1);
-
-    if (__libcpp_is_constant_evaluated()) {
-      for (size_type __i = 0; __i != __buffer.count; ++__i)
-        std::__construct_at(std::addressof(__buffer.ptr[__i]));
-    }
-
-    return __long(__buffer, __capacity);
-  }
-
   // Replace the current buffer with __new_rep. Deallocate the old long buffer if it exists.
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __reset_internal_buffer(__rep __new_rep = __short()) {
     __annotate_delete();
@@ -2279,18 +2282,15 @@ private:
   // Initialize the internal buffer to hold __size elements
   // The elements and null terminator have to be set by the caller
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __init_internal_buffer(size_type __size) {
-    if (__libcpp_is_constant_evaluated())
-      __rep_ = __rep();
-
     if (__size > max_size())
       __throw_length_error();
 
     if (__fits_in_sso(__size)) {
-      __set_short_size(__size);
+      __rep_ = __short(__size);
       __annotate_new(__size);
       return __get_short_pointer();
     } else {
-      __rep_.__l = __allocate_long_buffer(__alloc_, __size);
+      __rep_ = __long(__alloc_, __size);
       __annotate_new(__size);
       return __get_long_pointer();
     }
@@ -2447,7 +2447,7 @@ private:
         __annotate_delete();
         auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
         auto __alloc = __str.__alloc_;
-        __reset_internal_buffer(__allocate_long_buffer(__alloc, __str.size()));
+        __reset_internal_buffer(__long(__alloc, __str.size()));
         __alloc_ = std::move(__alloc);
       }
     }
@@ -2700,8 +2700,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
   size_type __cap =
       __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms;
   __annotate_delete();
-  auto __guard    = std::__make_scope_guard(__annotate_new_size(*this));
-  __long __buffer = __allocate_long_buffer(__alloc_, __cap);
+  auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
+  __long __buffer(__alloc_, __cap);
   if (__n_copy != 0)
     traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__old_p), __n_copy);
   if (__n_add != 0)
@@ -2737,7 +2737,7 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait
   pointer __old_p = __get_pointer();
   size_type __cap =
       __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms;
-  __long __buffer = __allocate_long_buffer(__alloc_, __cap);
+  __long __buffer(__alloc_, __cap);
   if (__n_copy != 0)
     traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__old_p), __n_copy);
   size_type __sec_cp_sz = __old_sz - __n_del - __n_copy;
@@ -3394,7 +3394,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
     return;
 
   __annotation_guard __g(*this);
-  __long __buffer  = __allocate_long_buffer(__alloc_, __requested_capacity);
+  __long __buffer(__alloc_, __requested_capacity);
   __buffer.__size_ = size();
   traits_type::copy(std::__to_address(__buffer.__data_), data(), __buffer.__size_ + 1);
   __reset_internal_buffer(__buffer);
@@ -3425,7 +3425,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
   try {
 #  endif // _LIBCPP_HAS_EXCEPTIONS
     __annotation_guard __g(*this);
-    __long __buffer = __allocate_long_buffer(__alloc_, __size);
+    __long __buffer(__alloc_, __size);
 
     // The Standard mandates shrink_to_fit() does not increase the capacity.
     // With equal capacity keep the existing buffer. This avoids extra work



More information about the libcxx-commits mailing list