Skip to content

Conversation

@philnik777
Copy link
Contributor

No description provided.

@github-actions
Copy link

github-actions bot commented Nov 27, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions ,cpp -- libcxx/include/string libcxx/test/benchmarks/containers/string.bench.cpp --diff_from_common_commit

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 68249ad89..8fb1d1a21 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -128,7 +128,7 @@ BENCHMARK(BM_StringResizeAndOverwrite);
 template <class Container>
 static void BM_StringAppend(benchmark::State& state) {
   std::string orig_str = "This is some data so the string isn't empty";
-  std::string str = orig_str;
+  std::string str      = orig_str;
 
   const char to_append_str[] = "This is a long string to make sure append does some work";
   Container to_append;

@philnik777 philnik777 force-pushed the optimize_string_append_range branch 2 times, most recently from e850aa4 to f4596cb Compare November 28, 2025 13:15
@philnik777 philnik777 force-pushed the optimize_string_append_range branch from f4596cb to 1ac38dc Compare December 2, 2025 14:55
@ldionne ldionne marked this pull request as ready for review December 2, 2025 16:11
@ldionne ldionne requested a review from a team as a code owner December 2, 2025 16:11
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Dec 2, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 2, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

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

2 Files Affected:

  • (modified) libcxx/include/string (+40-13)
  • (modified) libcxx/test/benchmarks/containers/string.bench.cpp (+23)
diff --git a/libcxx/include/string b/libcxx/include/string
index 2b3ba6d2d9b62..c0454ba2cb9f8 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1440,24 +1440,51 @@ public:
   template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
   append(_ForwardIterator __first, _ForwardIterator __last) {
-    size_type __sz  = size();
-    size_type __cap = capacity();
-    size_type __n   = static_cast<size_type>(std::distance(__first, __last));
+    const size_type __size = size();
+    const size_type __cap  = capacity();
+    const size_type __n    = static_cast<size_type>(std::distance(__first, __last));
     if (__n == 0)
       return *this;
 
-    if (__string_is_trivial_iterator_v<_ForwardIterator> && !__addr_in_range(*__first)) {
-      if (__cap - __sz < __n)
-        __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
-      __annotate_increase(__n);
-      auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__get_pointer() + __sz));
-      traits_type::assign(*__end, value_type());
-      __set_size(__sz + __n);
-      return *this;
+    __annotate_delete();
+    auto __asan_guard = std::__make_scope_guard(__annotate_new_size(*this));
+
+    if (__n > __cap - __size) {
+      __long __buffer  = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__size + __n));
+      __buffer.__size_ = __size + __n;
+      auto __guard     = std::__make_exception_guard([&] {
+        __alloc_traits::deallocate(__alloc_, __buffer.__data_, __buffer.__cap_ * __endian_factor);
+      });
+      auto __end       = __copy_non_overlapping_range(__first, __last, std::__to_address(__buffer.__data_) + __size);
+      traits_type::assign(*__end, _CharT());
+      traits_type::copy(std::__to_address(__buffer.__data_), data(), __size);
+      __guard.__complete();
+      __reset_internal_buffer(__buffer);
     } else {
-      const basic_string __temp(__first, __last, __alloc_);
-      return append(__temp.data(), __temp.size());
+      _CharT* const __ptr = std::__to_address(__get_pointer());
+#  ifndef _LIBCPP_CXX03_LANG
+      if constexpr (__libcpp_is_contiguous_iterator<_ForwardIterator>::value &&
+                    is_same<value_type, __remove_cvref_t<decltype(*__first)>>::value) {
+        traits_type::move(__ptr + __size, std::__to_address(__first), __last - __first);
+      } else if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
+        auto __dest = __ptr + __size + __n;
+        while (__first != __last) {
+          --__last;
+          --__dest;
+          traits_type::assign(*__dest, *__last);
+        }
+      } else
+#  endif
+      {
+        _CharT __first_val = *__first;
+        ++__first;
+        __copy_non_overlapping_range(__first, __last, __ptr + __size + 1);
+        traits_type::assign(__ptr[__size], __first_val);
+      }
+      traits_type::assign(__ptr[__size + __n], _CharT());
+      __set_size(__size + __n);
     }
+    return *this;
   }
 
 #  if _LIBCPP_STD_VER >= 23
diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 98216d22d0144..68249ad8963ed 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -11,7 +11,10 @@
 #include <algorithm>
 #include <cstdint>
 #include <cstdlib>
+#include <deque>
+#include <iterator>
 #include <new>
+#include <list>
 #include <vector>
 
 #include "../CartesianBenchmarks.h"
@@ -122,6 +125,26 @@ static void BM_StringResizeAndOverwrite(benchmark::State& state) {
 }
 BENCHMARK(BM_StringResizeAndOverwrite);
 
+template <class Container>
+static void BM_StringAppend(benchmark::State& state) {
+  std::string orig_str = "This is some data so the string isn't empty";
+  std::string str = orig_str;
+
+  const char to_append_str[] = "This is a long string to make sure append does some work";
+  Container to_append;
+  std::copy(std::begin(to_append_str), std::end(to_append_str), std::back_inserter(to_append));
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(str);
+    str.append(to_append.begin(), to_append.end());
+    benchmark::DoNotOptimize(str);
+    str.resize(orig_str.size());
+  }
+}
+BENCHMARK(BM_StringAppend<std::vector<char>>);
+BENCHMARK(BM_StringAppend<std::deque<char>>);
+BENCHMARK(BM_StringAppend<std::list<char>>);
+
 enum class Length { Empty, Small, Large, Huge };
 struct AllLengths : EnumValuesAsTuple<AllLengths, Length, 4> {
   static constexpr const char* Names[] = {"Empty", "Small", "Large", "Huge"};

@ldionne
Copy link
Member

ldionne commented Dec 2, 2025

/libcxx-bot benchmark libcxx/test/benchmarks/containers/string.bench.cpp

Benchmark results:
Benchmark                                                      Baseline    Candidate    Difference    % Difference
-----------------------------------------------------------  ----------  -----------  ------------  --------------
BM_StringAppend<std::deque<char>>                                 53.45        31.84        -21.61         -40.43%
BM_StringAppend<std::list<char>>                                 122.52       101.53        -20.99         -17.13%
BM_StringAppend<std::vector<char>>                                 6.56         6.23         -0.33          -4.96%
BM_StringAssignAsciizMix_Opaque                                   11.58        11.46         -0.12          -1.04%
BM_StringAssignAsciizMix_Transparent                               4.79         4.91          0.11           2.36%
BM_StringAssignAsciiz_Empty_Opaque                                 9.57         9.56         -0.01          -0.11%
BM_StringAssignAsciiz_Empty_Transparent                            0.67         0.67         -0.00          -0.38%
BM_StringAssignAsciiz_Huge_Opaque                               2322.19      2334.53         12.34           0.53%
BM_StringAssignAsciiz_Huge_Transparent                          2322.31      2303.58        -18.73          -0.81%
BM_StringAssignAsciiz_Large_Opaque                                17.97        18.08          0.11           0.60%
BM_StringAssignAsciiz_Large_Transparent                           18.15        18.02         -0.13          -0.71%
BM_StringAssignAsciiz_Small_Opaque                                 9.58         9.58         -0.00          -0.03%
BM_StringAssignAsciiz_Small_Transparent                            0.93         0.93          0.00           0.03%
BM_StringAssignStr_Empty_Opaque                                    1.43         1.43          0.01           0.47%
BM_StringAssignStr_Empty_Transparent                               1.15         1.11         -0.04          -3.66%
BM_StringAssignStr_Huge_Opaque                                  2286.90      2248.44        -38.46          -1.68%
BM_StringAssignStr_Huge_Transparent                             2274.21      2239.00        -35.21          -1.55%
BM_StringAssignStr_Large_Opaque                                   15.05        15.04         -0.01          -0.07%
BM_StringAssignStr_Large_Transparent                              14.87        14.96          0.09           0.59%
BM_StringAssignStr_Small_Opaque                                    1.23         1.23         -0.00          -0.22%
BM_StringAssignStr_Small_Transparent                               1.15         1.12         -0.04          -3.21%
BM_StringConstructDestroyCStr_Empty_Opaque                         7.78         7.48         -0.31          -3.93%
BM_StringConstructDestroyCStr_Empty_Transparent                    0.62         0.63          0.00           0.33%
BM_StringConstructDestroyCStr_Huge_Opaque                        151.35       151.22         -0.13          -0.09%
BM_StringConstructDestroyCStr_Huge_Transparent                   118.78       117.74         -1.04          -0.88%
BM_StringConstructDestroyCStr_Large_Opaque                        20.95        21.11          0.16           0.78%
BM_StringConstructDestroyCStr_Large_Transparent                   14.79        14.71         -0.08          -0.54%
BM_StringConstructDestroyCStr_Small_Opaque                         6.86         6.85         -0.01          -0.19%
BM_StringConstructDestroyCStr_Small_Transparent                    1.56         0.94         -0.62         -39.76%
BM_StringCopy_Empty                                                0.97         0.97          0.00           0.15%
BM_StringCopy_Huge                                              1911.56      1982.42         70.86           3.71%
BM_StringCopy_Large                                               13.49        13.21         -0.28          -2.09%
BM_StringCopy_Small                                                1.15         1.16          0.01           0.92%
BM_StringCtorDefault                                               0.94         0.94         -0.00          -0.02%
BM_StringDestroy_Empty                                             1.15         1.16          0.02           1.43%
BM_StringDestroy_Huge                                            270.97       283.41         12.43           4.59%
BM_StringDestroy_Large                                             9.83         9.81         -0.02          -0.25%
BM_StringDestroy_Small                                             1.14         1.13         -0.01          -0.81%
BM_StringEraseToEnd_Empty_Opaque                                   1.48         1.48          0.00           0.02%
BM_StringEraseToEnd_Empty_Transparent                              0.67         0.65         -0.02          -2.93%
BM_StringEraseToEnd_Huge_Opaque                                    6.42         6.34         -0.08          -1.21%
BM_StringEraseToEnd_Huge_Transparent                               4.97         4.91         -0.06          -1.13%
BM_StringEraseToEnd_Large_Opaque                                   2.23         2.34          0.11           5.04%
BM_StringEraseToEnd_Large_Transparent                              1.74         1.80          0.06           3.71%
BM_StringEraseToEnd_Small_Opaque                                   1.48         1.47         -0.01          -0.36%
BM_StringEraseToEnd_Small_Transparent                              1.12         1.11         -0.01          -0.81%
BM_StringEraseWithMove_Empty_Opaque                                2.67         2.68          0.01           0.40%
BM_StringEraseWithMove_Empty_Transparent                           2.36         2.36         -0.00          -0.01%
BM_StringEraseWithMove_Huge_Opaque                                78.72        81.40          2.69           3.41%
BM_StringEraseWithMove_Huge_Transparent                           75.29        71.75         -3.54          -4.70%
BM_StringEraseWithMove_Large_Opaque                                6.87         6.97          0.09           1.38%
BM_StringEraseWithMove_Large_Transparent                           6.57         6.71          0.13           2.02%
BM_StringEraseWithMove_Small_Opaque                                6.43         6.51          0.09           1.33%
BM_StringEraseWithMove_Small_Transparent                           6.43         6.56          0.13           2.06%
BM_StringFindAllMatch/1                                            7.48         7.48          0.00           0.07%
BM_StringFindAllMatch/131072                                    2606.34      2592.03        -14.31          -0.55%
BM_StringFindAllMatch/32768                                      653.68       652.72         -0.95          -0.15%
BM_StringFindAllMatch/4096                                        49.56        49.39         -0.17          -0.35%
BM_StringFindAllMatch/512                                         12.07        12.02         -0.06          -0.47%
BM_StringFindAllMatch/64                                           7.18         7.17         -0.01          -0.15%
BM_StringFindAllMatch/8                                            7.47         7.48          0.00           0.03%
BM_StringFindCharLiteral/1024                                     10.55        10.65          0.10           0.92%
BM_StringFindCharLiteral/128                                       4.99         5.01          0.02           0.44%
BM_StringFindCharLiteral/16                                        3.74         3.75          0.01           0.21%
BM_StringFindCharLiteral/2048                                     15.72        15.86          0.13           0.84%
BM_StringFindCharLiteral/256                                       5.64         5.65          0.01           0.13%
BM_StringFindCharLiteral/32                                        4.68         4.69          0.01           0.27%
BM_StringFindCharLiteral/4096                                     26.22        26.37          0.14           0.55%
BM_StringFindCharLiteral/512                                       7.66         7.69          0.04           0.51%
BM_StringFindCharLiteral/64                                        4.68         4.69          0.01           0.14%
BM_StringFindCharLiteral/8                                         3.76         3.76         -0.00          -0.11%
BM_StringFindCharLiteral/8192                                     46.40        46.49          0.09           0.20%
BM_StringFindMatch1/1                                            651.11       650.44         -0.67          -0.10%
BM_StringFindMatch1/32768                                       1290.17      1292.66          2.49           0.19%
BM_StringFindMatch1/4096                                         725.48       729.60          4.13           0.57%
BM_StringFindMatch1/512                                          659.27       659.64          0.37           0.06%
BM_StringFindMatch1/64                                           648.50       650.36          1.85           0.29%
BM_StringFindMatch1/8                                            649.77       651.80          2.03           0.31%
BM_StringFindMatch2/1                                            650.38       651.50          1.12           0.17%
BM_StringFindMatch2/32768                                       1293.52      1293.59          0.07           0.01%
BM_StringFindMatch2/4096                                         732.20       737.73          5.53           0.76%
BM_StringFindMatch2/512                                          668.36       669.55          1.19           0.18%
BM_StringFindMatch2/64                                           650.16       650.95          0.79           0.12%
BM_StringFindMatch2/8                                            650.56       651.49          0.93           0.14%
BM_StringFindNoMatch/10                                            9.78        10.00          0.22           2.27%
BM_StringFindNoMatch/131072                                     1283.27      1284.28          1.01           0.08%
BM_StringFindNoMatch/32768                                       184.60       183.58         -1.02          -0.55%
BM_StringFindNoMatch/4096                                         26.62        26.49         -0.13          -0.50%
BM_StringFindNoMatch/512                                           7.67         7.50         -0.17          -2.21%
BM_StringFindNoMatch/64                                            5.02         5.19          0.17           3.34%
BM_StringFindStringLiteral/1024                                   11.06        11.06          0.00           0.00%
BM_StringFindStringLiteral/128                                     4.99         4.99          0.00           0.05%
BM_StringFindStringLiteral/16                                      3.75         3.74         -0.01          -0.23%
BM_StringFindStringLiteral/2048                                   15.42        15.59          0.17           1.08%
BM_StringFindStringLiteral/256                                     5.75         5.76          0.01           0.12%
BM_StringFindStringLiteral/32                                      4.69         4.68         -0.01          -0.21%
BM_StringFindStringLiteral/4096                                   25.48        26.06          0.58           2.27%
BM_StringFindStringLiteral/512                                     7.81         7.80         -0.01          -0.10%
BM_StringFindStringLiteral/64                                      4.70         4.68         -0.01          -0.24%
BM_StringFindStringLiteral/8                                       3.76         3.75         -0.00          -0.06%
BM_StringFindStringLiteral/8192                                   46.30        46.67          0.37           0.80%
BM_StringMove_Empty                                                2.81         2.96          0.15           5.51%
BM_StringMove_Huge                                                 2.81         3.19          0.38          13.45%
BM_StringMove_Large                                                2.81         3.19          0.38          13.51%
BM_StringMove_Small                                                2.81         3.19          0.39          13.73%
BM_StringRead_Cold_Deep_Empty                                      4.70         5.30          0.60          12.80%
BM_StringRead_Cold_Deep_Large                                      5.48         5.81          0.33           6.01%
BM_StringRead_Cold_Deep_Small                                      5.02         5.87          0.84          16.81%
BM_StringRead_Cold_Shallow_Empty                                   4.84         5.18          0.34           6.94%
BM_StringRead_Cold_Shallow_Large                                   4.82         5.22          0.40           8.34%
BM_StringRead_Cold_Shallow_Small                                   5.00         5.51          0.52          10.32%
BM_StringRead_Hot_Deep_Empty                                       0.95         0.95         -0.00          -0.15%
BM_StringRead_Hot_Deep_Large                                       1.06         1.07          0.01           0.68%
BM_StringRead_Hot_Deep_Small                                       1.26         1.25         -0.01          -0.57%
BM_StringRead_Hot_Shallow_Empty                                    0.94         0.94          0.00           0.48%
BM_StringRead_Hot_Shallow_Large                                    0.94         0.94         -0.00          -0.47%
BM_StringRead_Hot_Shallow_Small                                    0.94         0.95          0.00           0.50%
BM_StringRelationalLiteral_Compare_Empty_Empty_ChangeFirst         0.62         0.62          0.00           0.36%
BM_StringRelationalLiteral_Compare_Empty_Empty_ChangeLast          0.62         0.62          0.00           0.32%
BM_StringRelationalLiteral_Compare_Empty_Empty_ChangeMiddle        0.62         0.62          0.00           0.15%
BM_StringRelationalLiteral_Compare_Empty_Empty_Control             0.62         0.62          0.00           0.33%
BM_StringRelationalLiteral_Compare_Empty_Large_Control             4.37         4.38          0.01           0.29%
BM_StringRelationalLiteral_Compare_Empty_Small_Control             4.38         4.39          0.01           0.30%
BM_StringRelationalLiteral_Compare_Large_Empty_Control             0.63         0.63          0.00           0.20%
BM_StringRelationalLiteral_Compare_Large_Large_ChangeFirst         4.06         4.07          0.01           0.17%
BM_StringRelationalLiteral_Compare_Large_Large_ChangeLast          4.36         4.37          0.01           0.17%
BM_StringRelationalLiteral_Compare_Large_Large_ChangeMiddle        4.05         4.06          0.01           0.19%
BM_StringRelationalLiteral_Compare_Large_Large_Control             3.76         3.78          0.02           0.50%
BM_StringRelationalLiteral_Compare_Large_Small_Control             4.07         4.13          0.06           1.48%
BM_StringRelationalLiteral_Compare_Small_Empty_Control             0.93         0.94          0.00           0.50%
BM_StringRelationalLiteral_Compare_Small_Large_Control             3.74         3.75          0.00           0.12%
BM_StringRelationalLiteral_Compare_Small_Small_ChangeFirst         4.36         4.37          0.01           0.24%
BM_StringRelationalLiteral_Compare_Small_Small_ChangeLast          4.36         4.38          0.01           0.34%
BM_StringRelationalLiteral_Compare_Small_Small_ChangeMiddle        4.36         4.39          0.03           0.61%
BM_StringRelationalLiteral_Compare_Small_Small_Control             3.74         3.74          0.00           0.13%
BM_StringRelationalLiteral_Eq_Empty_Empty_ChangeFirst              0.94         0.94          0.00           0.21%
BM_StringRelationalLiteral_Eq_Empty_Empty_ChangeLast               0.94         0.93         -0.00          -0.28%
BM_StringRelationalLiteral_Eq_Empty_Empty_ChangeMiddle             0.93         0.94          0.00           0.10%
BM_StringRelationalLiteral_Eq_Empty_Empty_Control                  0.93         0.94          0.00           0.02%
BM_StringRelationalLiteral_Eq_Empty_Large_Control                  0.62         0.62         -0.00          -0.20%
BM_StringRelationalLiteral_Eq_Empty_Small_Control                  1.25         1.25         -0.00          -0.07%
BM_StringRelationalLiteral_Eq_Large_Empty_Control                  0.95         0.94         -0.01          -0.98%
BM_StringRelationalLiteral_Eq_Large_Large_ChangeFirst              3.12         3.13          0.01           0.33%
BM_StringRelationalLiteral_Eq_Large_Large_ChangeLast               3.44         3.43         -0.01          -0.24%
BM_StringRelationalLiteral_Eq_Large_Large_ChangeMiddle             3.12         3.11         -0.01          -0.27%
BM_StringRelationalLiteral_Eq_Large_Large_Control                  3.12         3.12         -0.01          -0.24%
BM_StringRelationalLiteral_Eq_Large_Small_Control                  0.63         0.63         -0.00          -0.09%
BM_StringRelationalLiteral_Eq_Small_Empty_Control                  0.94         0.94         -0.00          -0.05%
BM_StringRelationalLiteral_Eq_Small_Large_Control                  0.63         0.63          0.00           0.05%
BM_StringRelationalLiteral_Eq_Small_Small_ChangeFirst              1.25         1.26          0.01           0.68%
BM_StringRelationalLiteral_Eq_Small_Small_ChangeLast               1.26         1.33          0.07           5.54%
BM_StringRelationalLiteral_Eq_Small_Small_ChangeMiddle             1.33         1.27         -0.06          -4.44%
BM_StringRelationalLiteral_Eq_Small_Small_Control                  1.25         1.25          0.00           0.06%
BM_StringRelationalLiteral_Less_Empty_Empty_ChangeFirst            0.63         0.62         -0.01          -0.80%
BM_StringRelationalLiteral_Less_Empty_Empty_ChangeLast             0.64         0.63         -0.01          -1.89%
BM_StringRelationalLiteral_Less_Empty_Empty_ChangeMiddle           0.64         0.63         -0.01          -1.97%
BM_StringRelationalLiteral_Less_Empty_Empty_Control                0.63         0.62         -0.01          -1.09%
BM_StringRelationalLiteral_Less_Empty_Large_Control                4.37         4.36         -0.01          -0.16%
BM_StringRelationalLiteral_Less_Empty_Small_Control                4.07         4.05         -0.01          -0.34%
BM_StringRelationalLiteral_Less_Large_Empty_Control                0.63         0.66          0.03           5.41%
BM_StringRelationalLiteral_Less_Large_Large_ChangeFirst            3.74         3.74          0.00           0.10%
BM_StringRelationalLiteral_Less_Large_Large_ChangeLast             4.05         4.06          0.01           0.13%
BM_StringRelationalLiteral_Less_Large_Large_ChangeMiddle           3.74         3.75          0.00           0.11%
BM_StringRelationalLiteral_Less_Large_Large_Control                3.74         3.74         -0.00          -0.03%
BM_StringRelationalLiteral_Less_Large_Small_Control                3.74         3.75          0.00           0.08%
BM_StringRelationalLiteral_Less_Small_Empty_Control                0.31         0.31         -0.00          -1.00%
BM_StringRelationalLiteral_Less_Small_Large_Control                3.75         3.84          0.09           2.41%
BM_StringRelationalLiteral_Less_Small_Small_ChangeFirst            4.05         4.05         -0.00          -0.06%
BM_StringRelationalLiteral_Less_Small_Small_ChangeLast             4.05         4.07          0.02           0.49%
BM_StringRelationalLiteral_Less_Small_Small_ChangeMiddle           4.06         4.05         -0.01          -0.27%
BM_StringRelationalLiteral_Less_Small_Small_Control                3.74         3.74         -0.00          -0.12%
BM_StringRelational_Compare_Empty_Empty_Control                    4.38         4.36         -0.01          -0.28%
BM_StringRelational_Compare_Empty_Huge_Control                     4.67         4.67          0.00           0.07%
BM_StringRelational_Compare_Empty_Large_Control                    4.67         4.68          0.00           0.05%
BM_StringRelational_Compare_Empty_Small_Control                    4.68         4.67         -0.01          -0.21%
BM_StringRelational_Compare_Huge_Empty_Control                     4.67         4.68          0.01           0.19%
BM_StringRelational_Compare_Huge_Huge_ChangeFirst                  4.09         4.12          0.03           0.79%
BM_StringRelational_Compare_Huge_Huge_ChangeLast                  68.72        68.62         -0.10          -0.15%
BM_StringRelational_Compare_Huge_Huge_ChangeMiddle                36.55        36.56          0.02           0.05%
BM_StringRelational_Compare_Huge_Huge_Control                     68.34        68.26         -0.09          -0.13%
BM_StringRelational_Compare_Huge_Large_Control                     3.43         3.43         -0.00          -0.06%
BM_StringRelational_Compare_Huge_Small_Control                     3.75         3.74         -0.00          -0.08%
BM_StringRelational_Compare_Large_Empty_Control                    4.39         4.37         -0.02          -0.55%
BM_StringRelational_Compare_Large_Huge_Control                     4.07         4.06         -0.01          -0.31%
BM_StringRelational_Compare_Large_Large_ChangeFirst                4.39         4.51          0.12           2.77%
BM_StringRelational_Compare_Large_Large_ChangeLast                 4.68         4.68         -0.00          -0.08%
BM_StringRelational_Compare_Large_Large_ChangeMiddle               4.09         4.06         -0.03          -0.63%
BM_StringRelational_Compare_Large_Large_Control                    3.47         3.48          0.01           0.28%
BM_StringRelational_Compare_Large_Small_Control                    5.01         4.39         -0.62         -12.35%
BM_StringRelational_Compare_Small_Empty_Control                    4.07         4.05         -0.02          -0.48%
BM_StringRelational_Compare_Small_Huge_Control                     4.37         4.37          0.00           0.10%
BM_StringRelational_Compare_Small_Large_Control                    5.03         4.37         -0.66         -13.14%
BM_StringRelational_Compare_Small_Small_ChangeFirst                4.69         4.69         -0.01          -0.11%
BM_StringRelational_Compare_Small_Small_ChangeLast                 4.69         4.69          0.00           0.02%
BM_StringRelational_Compare_Small_Small_ChangeMiddle               4.38         4.38         -0.00          -0.05%
BM_StringRelational_Compare_Small_Small_Control                    4.38         4.39          0.00           0.09%
BM_StringRelational_Eq_Empty_Empty_Control                         5.32         5.30         -0.02          -0.41%
BM_StringRelational_Eq_Empty_Huge_Control                          0.94         0.94          0.00           0.33%
BM_StringRelational_Eq_Empty_Large_Control                         0.94         0.94          0.00           0.51%
BM_StringRelational_Eq_Empty_Small_Control                         1.56         1.57          0.00           0.18%
BM_StringRelational_Eq_Huge_Huge_ChangeFirst                       4.05         4.06          0.01           0.13%
BM_StringRelational_Eq_Huge_Huge_ChangeLast                       69.51        69.43         -0.09          -0.13%
BM_StringRelational_Eq_Huge_Huge_ChangeMiddle                     37.33        37.08         -0.25          -0.67%
BM_StringRelational_Eq_Huge_Huge_Control                          69.36        69.57          0.21           0.30%
BM_StringRelational_Eq_Large_Huge_Control                          0.93         0.94          0.01           0.70%
BM_StringRelational_Eq_Large_Large_ChangeFirst                     3.43         3.43         -0.00          -0.13%
BM_StringRelational_Eq_Large_Large_ChangeLast                      3.75         3.76          0.01           0.28%
BM_StringRelational_Eq_Large_Large_ChangeMiddle                    3.91         3.78         -0.14          -3.51%
BM_StringRelational_Eq_Large_Large_Control                         3.75         3.74         -0.01          -0.37%
BM_StringRelational_Eq_Small_Huge_Control                          0.94         0.93         -0.00          -0.33%
BM_StringRelational_Eq_Small_Large_Control                         0.94         0.94         -0.00          -0.14%
BM_StringRelational_Eq_Small_Small_ChangeFirst                     5.62         5.61         -0.01          -0.17%
BM_StringRelational_Eq_Small_Small_ChangeLast                      5.31         5.30         -0.01          -0.18%
BM_StringRelational_Eq_Small_Small_ChangeMiddle                    5.33         5.29         -0.03          -0.59%
BM_StringRelational_Eq_Small_Small_Control                         5.32         5.30         -0.02          -0.40%
BM_StringRelational_Less_Empty_Empty_Control                       4.67         4.36         -0.31          -6.59%
BM_StringRelational_Less_Empty_Huge_Control                        4.40         4.43          0.04           0.83%
BM_StringRelational_Less_Empty_Large_Control                       4.36         4.36         -0.01          -0.23%
BM_StringRelational_Less_Empty_Small_Control                       4.05         4.05          0.00           0.11%
BM_StringRelational_Less_Huge_Empty_Control                        4.38         4.37         -0.01          -0.12%
BM_StringRelational_Less_Huge_Huge_ChangeFirst                     4.07         4.06         -0.01          -0.24%
BM_StringRelational_Less_Huge_Huge_ChangeLast                     69.96        69.78         -0.18          -0.25%
BM_StringRelational_Less_Huge_Huge_ChangeMiddle                   37.77        37.55         -0.23          -0.60%
BM_StringRelational_Less_Huge_Huge_Control                        72.16        70.09         -2.07          -2.86%
BM_StringRelational_Less_Huge_Large_Control                        3.79         3.75         -0.05          -1.25%
BM_StringRelational_Less_Huge_Small_Control                        4.07         4.05         -0.02          -0.44%
BM_StringRelational_Less_Large_Empty_Control                       4.36         4.39          0.02           0.52%
BM_StringRelational_Less_Large_Huge_Control                        3.45         3.44         -0.01          -0.24%
BM_StringRelational_Less_Large_Large_ChangeFirst                   3.75         3.75         -0.01          -0.15%
BM_StringRelational_Less_Large_Large_ChangeLast                    4.07         4.07         -0.00          -0.04%
BM_StringRelational_Less_Large_Large_ChangeMiddle                  3.75         3.75         -0.00          -0.11%
BM_StringRelational_Less_Large_Large_Control                       4.07         4.07          0.01           0.16%
BM_StringRelational_Less_Large_Small_Control                       4.71         4.12         -0.59         -12.60%
BM_StringRelational_Less_Small_Empty_Control                       4.38         4.56          0.18           4.05%
BM_StringRelational_Less_Small_Huge_Control                        3.76         3.75         -0.02          -0.47%
BM_StringRelational_Less_Small_Large_Control                       4.69         4.06         -0.63         -13.37%
BM_StringRelational_Less_Small_Small_ChangeFirst                   4.36         4.37          0.01           0.12%
BM_StringRelational_Less_Small_Small_ChangeLast                    4.36         4.37          0.01           0.22%
BM_StringRelational_Less_Small_Small_ChangeMiddle                  4.68         4.70          0.02           0.45%
BM_StringRelational_Less_Small_Small_Control                       4.05         4.06          0.01           0.32%
BM_StringResizeAndOverwrite                                        8.10         8.10          0.01           0.10%
Geomean                                                            6.75         6.73         -0.02          -0.29%

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add an explanation of what the optimization is in the commit message? And also please include benchmark results.

Comment on lines +1453 to +1454
__long __buffer = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__size + __n));
__buffer.__size_ = __size + __n;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semantically, that's what we have:

Suggested change
__long __buffer = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__size + __n));
__buffer.__size_ = __size + __n;
const size_type __new_size = __size + __n;
const size_type __new_capacity = __get_amortized_growth_capacity(__new_size);
__long __buffer = __allocate_long_buffer(__alloc_, __new_size, __new_capacity);

It might not be necessary to actually name __new_size, but I think it would make sense for the API to allow us to write this.

The other way I can see to achieve the same result without losing the fact that we're doing amortized growth at the call site would be:

struct __amortized_growth_strategy_t {};
__long __buffer  = __allocate_long_buffer(__alloc_, __size + __n, __amortized_growth_strategy_t{});

and then

_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __long
  __allocate_long_buffer(_Allocator& __alloc, size_type __size, __amortized_growth_strategy_t) {
    _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__size),
                            "Trying to allocate long buffer for a size what would fit into the small buffer");
    size_type const __capacity = has-amortized-growth-strategy ? __get_amortized_growth_capacity(__size) : __size;
    auto __buffer = std::__allocate_at_least(__alloc, __align_allocation_size(__capacity));

    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, __size);
  }

__long __buffer = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__size + __n));
__buffer.__size_ = __size + __n;
auto __guard = std::__make_exception_guard([&] {
__alloc_traits::deallocate(__alloc_, __buffer.__data_, __buffer.__cap_ * __endian_factor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a member function to the long buffer representation that gives you the correct capacity. I'd like to do that refactoring before we land this patch.

} else {
const basic_string __temp(__first, __last, __alloc_);
return append(__temp.data(), __temp.size());
_CharT* const __ptr = std::__to_address(__get_pointer());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

     _CharT* const __ptr = std::__to_address(__get_pointer());
#  ifndef _LIBCPP_CXX03_LANG
      if constexpr (__libcpp_is_contiguous_iterator<_ForwardIterator>::value &&
                    is_same<value_type, __remove_cvref_t<decltype(*__first)>>::value) {
        traits_type::move(__ptr + __size, std::__to_address(__first), __last - __first);
      } else if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
        auto __dest = __ptr + __size + __n;
        while (__first != __last) {
          --__last;
          --__dest;
          traits_type::assign(*__dest, *__last);
        }
      } else {
        _CharT __first_val = *__first;
        ++__first;
        __copy_non_overlapping_range(__first, __last, __ptr + __size + 1);
        traits_type::assign(__ptr[__size], __first_val);
      }
#  else
      _CharT __first_val = *__first;
      ++__first;
      __copy_non_overlapping_range(__first, __last, __ptr + __size + 1);
      traits_type::assign(__ptr[__size], __first_val);
#  endif
      traits_type::assign(__ptr[__size + __n], _CharT());
      __set_size(__size + __n);

IMO this is a lot easier to read because the interaction between the preprocessor and if constexpr is a lot more straightforward. There's a tiny bit more duplication, but IMO it increases readability over status quo.

traits_type::move(__ptr + __size, std::__to_address(__first), __last - __first);
} else if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
auto __dest = __ptr + __size + __n;
while (__first != __last) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is non-trivial. Can you please add a comment explaining why you go from the back?


template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
append(_ForwardIterator __first, _ForwardIterator __last) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment, we are not optimizing append(char8_t*, char8_t*) into a memmove, but we could. We should figure out how to do that, perhaps in __copy_non_overlapping_range.

std::string str = orig_str;

const char to_append_str[] = "This is a long string to make sure append does some work";
Container to_append;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Container to_append;
Container to_append(std::begin(to_append_str), std::end(to_append_str));


template <class Container>
static void BM_StringAppend(benchmark::State& state) {
std::string orig_str = "This is some data so the string isn't empty";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string orig_str = "This is some data so the string isn't empty";
std::string const orig_str = "This is some data so the string isn't empty";

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants