Skip to content

Commit a769608

Browse files
authored
[libc++] Fold __search_substring into _Traits::find in case the second string has length 1 (#160076)
Apple M4: ``` Benchmark Baseline Candidate Difference % Difference ----------------------------------------------------------- ---------- ----------- ------------ -------------- BM_string_literal/1024 16.99 16.79 -0.21 -1.21 BM_string_literal/128 3.44 3.34 -0.10 -2.88 BM_string_literal/16 1.80 1.69 -0.11 -5.93 BM_string_literal/2048 38.44 38.38 -0.07 -0.17 BM_string_literal/256 5.77 5.65 -0.12 -2.02 BM_string_literal/32 2.03 1.92 -0.11 -5.44 BM_string_literal/4096 73.92 73.74 -0.18 -0.25 BM_string_literal/512 9.49 9.41 -0.08 -0.84 BM_string_literal/64 2.59 2.45 -0.14 -5.38 BM_string_literal/8 1.79 1.69 -0.11 -5.90 BM_string_literal/8192 132.09 131.81 -0.28 -0.21 ```
1 parent 8bcb614 commit a769608

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

libcxx/include/__string/char_traits.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,13 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __searc
369369
if (__len1 < __len2)
370370
return __last1;
371371

372+
if (__builtin_constant_p(__len2 == 1) && __len2 == 1) {
373+
auto __res = _Traits::find(__first1, __len1, *__first2);
374+
if (__res == nullptr)
375+
return __last1;
376+
return __res;
377+
}
378+
372379
// First element of __first2 is loop invariant.
373380
_CharT __f2 = *__first2;
374381
while (true) {

libcxx/test/benchmarks/containers/string.bench.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,45 @@ static void BM_StringFindMatch2(benchmark::State& state) {
6060
}
6161
BENCHMARK(BM_StringFindMatch2)->Range(1, MAX_STRING_LEN / 4);
6262

63+
static void BM_StringFindStringLiteral(benchmark::State& state) {
64+
std::string s;
65+
66+
for (int i = 0; i < state.range(0); i++)
67+
s += 'a';
68+
69+
s += 'b';
70+
71+
benchmark::DoNotOptimize(s.data());
72+
benchmark::ClobberMemory();
73+
size_t pos;
74+
75+
for (auto _ : state) {
76+
benchmark::DoNotOptimize(pos = s.find("b"));
77+
benchmark::ClobberMemory();
78+
}
79+
}
80+
81+
BENCHMARK(BM_StringFindStringLiteral)->RangeMultiplier(2)->Range(8, 8 << 10);
82+
83+
static void BM_StringFindCharLiteral(benchmark::State& state) {
84+
std::string s;
85+
86+
for (int i = 0; i < state.range(0); i++)
87+
s += 'a';
88+
89+
s += 'b';
90+
91+
benchmark::DoNotOptimize(s.data());
92+
benchmark::ClobberMemory();
93+
size_t pos;
94+
95+
for (auto _ : state) {
96+
benchmark::DoNotOptimize(pos = s.find('b'));
97+
benchmark::ClobberMemory();
98+
}
99+
}
100+
BENCHMARK(BM_StringFindCharLiteral)->RangeMultiplier(2)->Range(8, 8 << 10);
101+
63102
static void BM_StringCtorDefault(benchmark::State& state) {
64103
for (auto _ : state) {
65104
std::string Default;

libcxx/test/std/strings/basic.string/string.ops/string_find/string_size.pass.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,17 @@ TEST_CONSTEXPR_CXX20 void test0() {
4343
test(S(""), S("abcdeabcde"), 1, S::npos);
4444
test(S(""), S("abcdeabcdeabcdeabcde"), 1, S::npos);
4545
test(S("abcde"), S(""), 0, 0);
46+
test(S("abcde"), S("a"), 0, 0);
4647
test(S("abcde"), S("abcde"), 0, 0);
4748
test(S("abcde"), S("abcdeabcde"), 0, S::npos);
4849
test(S("abcde"), S("abcdeabcdeabcdeabcde"), 0, S::npos);
4950
test(S("abcde"), S(""), 1, 1);
51+
test(S("abcde"), S("a"), 1, S::npos);
5052
test(S("abcde"), S("abcde"), 1, S::npos);
5153
test(S("abcde"), S("abcdeabcde"), 1, S::npos);
5254
test(S("abcde"), S("abcdeabcdeabcdeabcde"), 1, S::npos);
5355
test(S("abcde"), S(""), 2, 2);
56+
test(S("abcde"), S("a"), 2, S::npos);
5457
test(S("abcde"), S("abcde"), 2, S::npos);
5558
test(S("abcde"), S("abcdeabcde"), 2, S::npos);
5659
test(S("abcde"), S("abcdeabcdeabcdeabcde"), 2, S::npos);
@@ -59,58 +62,72 @@ TEST_CONSTEXPR_CXX20 void test0() {
5962
test(S("abcde"), S("abcdeabcde"), 4, S::npos);
6063
test(S("abcde"), S("abcdeabcdeabcdeabcde"), 4, S::npos);
6164
test(S("abcde"), S(""), 5, 5);
65+
test(S("abcde"), S("a"), 5, S::npos);
6266
test(S("abcde"), S("abcde"), 5, S::npos);
6367
test(S("abcde"), S("abcdeabcde"), 5, S::npos);
6468
test(S("abcde"), S("abcdeabcdeabcdeabcde"), 5, S::npos);
6569
test(S("abcde"), S(""), 6, S::npos);
70+
test(S("abcde"), S("a"), 6, S::npos);
6671
test(S("abcde"), S("abcde"), 6, S::npos);
6772
test(S("abcde"), S("abcdeabcde"), 6, S::npos);
6873
test(S("abcde"), S("abcdeabcdeabcdeabcde"), 6, S::npos);
6974
test(S("abcdeabcde"), S(""), 0, 0);
75+
test(S("abcdeabcde"), S("a"), 0, 0);
7076
test(S("abcdeabcde"), S("abcde"), 0, 0);
7177
test(S("abcdeabcde"), S("abcdeabcde"), 0, 0);
7278
test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 0, S::npos);
7379
test(S("abcdeabcde"), S(""), 1, 1);
80+
test(S("abcdeabcde"), S("a"), 1, 5);
7481
test(S("abcdeabcde"), S("abcde"), 1, 5);
7582
test(S("abcdeabcde"), S("abcdeabcde"), 1, S::npos);
7683
test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 1, S::npos);
7784
test(S("abcdeabcde"), S(""), 5, 5);
85+
test(S("abcdeabcde"), S("a"), 5, 5);
7886
test(S("abcdeabcde"), S("abcde"), 5, 5);
7987
test(S("abcdeabcde"), S("abcdeabcde"), 5, S::npos);
8088
test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 5, S::npos);
8189
test(S("abcdeabcde"), S(""), 9, 9);
90+
test(S("abcdeabcde"), S("a"), 9, S::npos);
8291
test(S("abcdeabcde"), S("abcde"), 9, S::npos);
8392
test(S("abcdeabcde"), S("abcdeabcde"), 9, S::npos);
8493
test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 9, S::npos);
8594
test(S("abcdeabcde"), S(""), 10, 10);
95+
test(S("abcdeabcde"), S("a"), 10, S::npos);
8696
test(S("abcdeabcde"), S("abcde"), 10, S::npos);
8797
test(S("abcdeabcde"), S("abcdeabcde"), 10, S::npos);
8898
test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 10, S::npos);
8999
test(S("abcdeabcde"), S(""), 11, S::npos);
100+
test(S("abcdeabcde"), S("a"), 11, S::npos);
90101
test(S("abcdeabcde"), S("abcde"), 11, S::npos);
91102
test(S("abcdeabcde"), S("abcdeabcde"), 11, S::npos);
92103
test(S("abcdeabcde"), S("abcdeabcdeabcdeabcde"), 11, S::npos);
93104
test(S("abcdeabcdeabcdeabcde"), S(""), 0, 0);
105+
test(S("abcdeabcdeabcdeabcde"), S("a"), 0, 0);
94106
test(S("abcdeabcdeabcdeabcde"), S("abcde"), 0, 0);
95107
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 0, 0);
96108
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 0, 0);
97109
test(S("abcdeabcdeabcdeabcde"), S(""), 1, 1);
110+
test(S("abcdeabcdeabcdeabcde"), S("a"), 1, 5);
98111
test(S("abcdeabcdeabcdeabcde"), S("abcde"), 1, 5);
99112
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 1, 5);
100113
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 1, S::npos);
101114
test(S("abcdeabcdeabcdeabcde"), S(""), 10, 10);
115+
test(S("abcdeabcdeabcdeabcde"), S("a"), 10, 10);
102116
test(S("abcdeabcdeabcdeabcde"), S("abcde"), 10, 10);
103117
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 10, 10);
104118
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 10, S::npos);
105119
test(S("abcdeabcdeabcdeabcde"), S(""), 19, 19);
120+
test(S("abcdeabcdeabcdeabcde"), S("a"), 19, S::npos);
106121
test(S("abcdeabcdeabcdeabcde"), S("abcde"), 19, S::npos);
107122
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 19, S::npos);
108123
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 19, S::npos);
109124
test(S("abcdeabcdeabcdeabcde"), S(""), 20, 20);
125+
test(S("abcdeabcdeabcdeabcde"), S("a"), 20, S::npos);
110126
test(S("abcdeabcdeabcdeabcde"), S("abcde"), 20, S::npos);
111127
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 20, S::npos);
112128
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 20, S::npos);
113129
test(S("abcdeabcdeabcdeabcde"), S(""), 21, S::npos);
130+
test(S("abcdeabcdeabcdeabcde"), S("a"), 21, S::npos);
114131
test(S("abcdeabcdeabcdeabcde"), S("abcde"), 21, S::npos);
115132
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcde"), 21, S::npos);
116133
test(S("abcdeabcdeabcdeabcde"), S("abcdeabcdeabcdeabcde"), 21, S::npos);

0 commit comments

Comments
 (0)