[libcxx-commits] [libcxx] [libc++] fix minor performance issue in `basic_string<C>::append()` (PR #210078)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 21 05:06:19 PDT 2026
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/210078
>From 34419f2461f3cc4ac0c285cfbb76e64f016db652 Mon Sep 17 00:00:00 2001
From: Pavel Novikov <dev-ape at yandex.ru>
Date: Thu, 16 Jul 2026 17:43:25 +0300
Subject: [PATCH 1/2] [libc++] fix minor performance issue
---
libcxx/include/string | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index a297a05813cee..957eb15e4fe1f 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1359,13 +1359,13 @@ 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));
- if (__n == 0)
+ if (__first == __last)
return *this;
if (__string_is_trivial_iterator_v<_ForwardIterator> && !__addr_in_range(*__first)) {
+ size_type __sz = size();
+ size_type __cap = capacity();
+ size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
__annotate_increase(__n);
>From bd806f470a02647245b01bfa9209fc4937699bc0 Mon Sep 17 00:00:00 2001
From: Pavel Novikov <dev-ape at yandex.ru>
Date: Tue, 21 Jul 2026 14:42:18 +0300
Subject: [PATCH 2/2] [libc++] added benchmarks for `string::append()`
---
.../benchmarks/containers/string.bench.cpp | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 776ee5f58b7e2..5ad80d1d3ec5a 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -17,6 +17,7 @@
#include "benchmark/benchmark.h"
#include "make_string.h"
#include "test_macros.h"
+#include "test_iterators.h"
constexpr size_t small_size = 5;
constexpr size_t large_size = 30;
@@ -502,6 +503,45 @@ int main(int argc, char** argv) {
[](auto bm) { bm->Arg(large_size); }); // for naming
}
+ {
+ static auto bench_impl =
+ []<size_t size, bool opaque, class CharT>(
+ std::integral_constant<size_t, size>,
+ std::bool_constant<opaque>,
+ std::type_identity<CharT>,
+ benchmark::State& state) {
+ std::basic_string<CharT> src(size, 'a');
+ auto getIterator = [&src](size_t i) {
+ // INT_MAX because we want overhead of ThrowingIterator without actually throwing
+ return ThrowingIterator<CharT>(src.data() + i, src.data() + src.size(), INT_MAX);
+ };
+ std::basic_string<CharT> string = src;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(string);
+ string.clear();
+ if constexpr (opaque)
+ benchmark::DoNotOptimize(src);
+ benchmark::DoNotOptimize(string.append(getIterator(0), getIterator(size)));
+ }
+ };
+
+ bench("std::basic_string::append(ForwardIt, ForwardIt) (opaque)",
+ std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}, std::true_type{}),
+ [](auto bm) { bm->Arg(small_size); }); // for naming
+
+ bench("std::basic_string::append(ForwardIt, ForwardIt) (opaque)",
+ std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}, std::true_type{}),
+ [](auto bm) { bm->Arg(large_size); }); // for naming
+
+ bench("std::basic_string::append(ForwardIt, ForwardIt) (transparent)",
+ std::bind_front(bench_impl, std::integral_constant<size_t, small_size>{}, std::false_type{}),
+ [](auto bm) { bm->Arg(small_size); }); // for naming
+
+ bench("std::basic_string::append(ForwardIt, ForwardIt) (transparent)",
+ std::bind_front(bench_impl, std::integral_constant<size_t, large_size>{}, std::false_type{}),
+ [](auto bm) { bm->Arg(large_size); }); // for naming
+ }
+
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
More information about the libcxx-commits
mailing list