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

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Sep 23 03:22:18 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>



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


3 Files Affected:

- (modified) libcxx/include/__string/char_traits.h (+7) 
- (modified) libcxx/test/benchmarks/containers/string.bench.cpp (+39) 
- (modified) libcxx/test/std/strings/basic.string/string.ops/string_find/string_size.pass.cpp (+17) 


``````````diff
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..68f596b1be62a 100644
--- a/libcxx/test/benchmarks/containers/string.bench.cpp
+++ b/libcxx/test/benchmarks/containers/string.bench.cpp
@@ -60,6 +60,45 @@ 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;
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_find/string_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_find/string_size.pass.cpp
index 60ed469ce991b..4aa4a3f339142 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string_find/string_size.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_find/string_size.pass.cpp
@@ -43,14 +43,17 @@ TEST_CONSTEXPR_CXX20 void test0() {
   test(S(""), S("abcdeabcde"), 1, S::npos);
   test(S(""), S("abcdeabcdeabcdeabcde"), 1, S::npos);
   test(S("abcde"), S(""), 0, 0);
+  test(S("abcde"), S("a"), 0, 0);
   test(S("abcde"), S("abcde"), 0, 0);
   test(S("abcde"), S("abcdeabcde"), 0, S::npos);
   test(S("abcde"), S("abcdeabcdeabcdeabcde"), 0, S::npos);
   test(S("abcde"), S(""), 1, 1);
+  test(S("abcde"), S("a"), 1, S::npos);
   test(S("abcde"), S("abcde"), 1, S::npos);
   test(S("abcde"), S("abcdeabcde"), 1, S::npos);
   test(S("abcde"), S("abcdeabcdeabcdeabcde"), 1, S::npos);
   test(S("abcde"), S(""), 2, 2);
+  test(S("abcde"), S("a"), 2, S::npos);
   test(S("abcde"), S("abcde"), 2, S::npos);
   test(S("abcde"), S("abcdeabcde"), 2, S::npos);
   test(S("abcde"), S("abcdeabcdeabcdeabcde"), 2, S::npos);
@@ -59,58 +62,72 @@ TEST_CONSTEXPR_CXX20 void test0() {
   test(S("abcde"), S("abcdeabcde"), 4, S::npos);
   test(S("abcde"), S("abcdeabcdeabcdeabcde"), 4, S::npos);
   test(S("abcde"), S(""), 5, 5);
+  test(S("abcde"), S("a"), 5, S::npos);
   test(S("abcde"), S("abcde"), 5, S::npos);
   test(S("abcde"), S("abcdeabcde"), 5, S::npos);
   test(S("abcde"), S("abcdeabcdeabcdeabcde"), 5, S::npos);
   test(S("abcde"), S(""), 6, S::npos);
+  test(S("abcde"), S("a"), 6, S::npos);
   test(S("abcde"), S("abcde"), 6, S::npos);
   test(S("abcde"), S("abcdeabcde"), 6, S::npos);
   test(S("abcde"), S("abcdeabcdeabcdeabcde"), 6, S::npos);
   test(S("abcdeabcde"), S(""), 0, 0);
+  test(S("abcdeabcde"), S("a"), 0, 0);
   test(S("abcdeabcde"), S("abcde"), 0, 0);
   test(S("abcdeabcde"), S("abcdeabcde"), 0, 0);
   test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 0, S::npos);
   test(S("abcdeabcde"), S(""), 1, 1);
+  test(S("abcdeabcde"), S("a"), 1, 5);
   test(S("abcdeabcde"), S("abcde"), 1, 5);
   test(S("abcdeabcde"), S("abcdeabcde"), 1, S::npos);
   test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 1, S::npos);
   test(S("abcdeabcde"), S(""), 5, 5);
+  test(S("abcdeabcde"), S("a"), 5, 5);
   test(S("abcdeabcde"), S("abcde"), 5, 5);
   test(S("abcdeabcde"), S("abcdeabcde"), 5, S::npos);
   test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 5, S::npos);
   test(S("abcdeabcde"), S(""), 9, 9);
+  test(S("abcdeabcde"), S("a"), 9, S::npos);
   test(S("abcdeabcde"), S("abcde"), 9, S::npos);
   test(S("abcdeabcde"), S("abcdeabcde"), 9, S::npos);
   test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 9, S::npos);
   test(S("abcdeabcde"), S(""), 10, 10);
+  test(S("abcdeabcde"), S("a"), 10, S::npos);
   test(S("abcdeabcde"), S("abcde"), 10, S::npos);
   test(S("abcdeabcde"), S("abcdeabcde"), 10, S::npos);
   test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 10, S::npos);
   test(S("abcdeabcde"), S(""), 11, S::npos);
+  test(S("abcdeabcde"), S("a"), 11, S::npos);
   test(S("abcdeabcde"), S("abcde"), 11, S::npos);
   test(S("abcdeabcde"), S("abcdeabcde"), 11, S::npos);
   test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 11, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S(""), 0, 0);
+  test(S("abcdeabcdeabcdeabcde"), S("a"), 0, 0);
   test(S("abcdeabcdeabcdeabcde"), S("abcde"), 0, 0);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 0, 0);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 0, 0);
   test(S("abcdeabcdeabcdeabcde"), S(""), 1, 1);
+  test(S("abcdeabcdeabcdeabcde"), S("a"), 1, 5);
   test(S("abcdeabcdeabcdeabcde"), S("abcde"), 1, 5);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 1, 5);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 1, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S(""), 10, 10);
+  test(S("abcdeabcdeabcdeabcde"), S("a"), 10, 10);
   test(S("abcdeabcdeabcdeabcde"), S("abcde"), 10, 10);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 10, 10);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 10, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S(""), 19, 19);
+  test(S("abcdeabcdeabcdeabcde"), S("a"), 19, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcde"), 19, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 19, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 19, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S(""), 20, 20);
+  test(S("abcdeabcdeabcdeabcde"), S("a"), 20, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcde"), 20, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 20, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 20, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S(""), 21, S::npos);
+  test(S("abcdeabcdeabcdeabcde"), S("a"), 21, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcde"), 21, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 21, S::npos);
   test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 21, S::npos);

``````````

</details>


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


More information about the libcxx-commits mailing list