[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