[libcxx-commits] [libcxx] [libc++] Fold __search_substring into _Traits::find in case the second string has length 1 (PR #160076)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Sep 22 04:27:33 PDT 2025


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

None

>From dd1885ac1d47bf910307b670c3ef89c29b234bda Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 22 Sep 2025 13:27:10 +0200
Subject: [PATCH] [libc++] Fold __search_substring into _Traits::find in case
 the second string has length 1

---
 libcxx/include/__string/char_traits.h         |  7 +++
 .../benchmarks/containers/string.bench.cpp    | 43 +++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h
index 86c92477cbfeb..8292750919427 100644
--- a/libcxx/include/__string/char_traits.h
+++ b/libcxx/include/__string/char_traits.h
@@ -369,6 +369,13 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __searc
   if (__len1 < __len2)
     return __last1;
 
+  if (__builtin_constant_p(__len2 == 1) && __len2 == 1) {
+    auto __res = _Traits::find(__first1, __len1, *__first2);
+    if (__res == nullptr)
+      return __last1;
+    return __res;
+  }
+
   // First element of __first2 is loop invariant.
   _CharT __f2 = *__first2;
   while (true) {
diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp
index 966775d31a8cf..6528ae6a04f52 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -60,6 +60,49 @@ static void BM_StringFindMatch2(benchmark::State& state) {
 }
 BENCHMARK(BM_StringFindMatch2)->Range(1, MAX_STRING_LEN / 4);
 
+static void BM_string_literal(benchmark::State& state)
+{
+    std::string s;
+
+    for (int i = 0; i < state.range(0); i++)
+        s += 'a';
+
+    s += 'b';
+
+    benchmark::DoNotOptimize(s.data());
+    benchmark::ClobberMemory();
+    size_t pos;
+
+    for (auto _ : state)
+    {
+        benchmark::DoNotOptimize(pos = s.find("b")); // "b" is a string literal, it should be longer
+        benchmark::ClobberMemory();
+    }
+}
+
+BENCHMARK(BM_string_literal)->RangeMultiplier(2)->Range(8, 8<<10);
+
+static void BM_char_literal(benchmark::State& state)
+{
+    std::string s;
+
+    for (int i = 0; i < state.range(0); i++)
+        s += 'a';
+
+    s += 'b';
+
+    benchmark::DoNotOptimize(s.data());
+    benchmark::ClobberMemory();
+    size_t pos;
+
+    for (auto _ : state)
+    {
+        benchmark::DoNotOptimize(pos = s.find('b')); // 'b' is a char literal, it should be faster
+        benchmark::ClobberMemory();
+    }
+}
+BENCHMARK(BM_char_literal)->RangeMultiplier(2)->Range(8, 8<<10);
+
 static void BM_StringCtorDefault(benchmark::State& state) {
   for (auto _ : state) {
     std::string Default;



More information about the libcxx-commits mailing list