xref: /aosp_15_r20/external/abseil-cpp/absl/strings/str_replace_benchmark.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2018 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_replace.h"
16*9356374aSAndroid Build Coastguard Worker 
17*9356374aSAndroid Build Coastguard Worker #include <cstring>
18*9356374aSAndroid Build Coastguard Worker #include <string>
19*9356374aSAndroid Build Coastguard Worker 
20*9356374aSAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
21*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/raw_logging.h"
22*9356374aSAndroid Build Coastguard Worker 
23*9356374aSAndroid Build Coastguard Worker namespace {
24*9356374aSAndroid Build Coastguard Worker 
25*9356374aSAndroid Build Coastguard Worker std::string* big_string;
26*9356374aSAndroid Build Coastguard Worker std::string* after_replacing_the;
27*9356374aSAndroid Build Coastguard Worker std::string* after_replacing_many;
28*9356374aSAndroid Build Coastguard Worker 
29*9356374aSAndroid Build Coastguard Worker struct Replacement {
30*9356374aSAndroid Build Coastguard Worker   const char* needle;
31*9356374aSAndroid Build Coastguard Worker   const char* replacement;
32*9356374aSAndroid Build Coastguard Worker } replacements[] = {
33*9356374aSAndroid Build Coastguard Worker     {"the", "box"},          //
34*9356374aSAndroid Build Coastguard Worker     {"brown", "quick"},      //
35*9356374aSAndroid Build Coastguard Worker     {"jumped", "liquored"},  //
36*9356374aSAndroid Build Coastguard Worker     {"dozen", "brown"},      //
37*9356374aSAndroid Build Coastguard Worker     {"lazy", "pack"},        //
38*9356374aSAndroid Build Coastguard Worker     {"liquor", "shakes"},    //
39*9356374aSAndroid Build Coastguard Worker };
40*9356374aSAndroid Build Coastguard Worker 
41*9356374aSAndroid Build Coastguard Worker // Here, we set up a string for use in global-replace benchmarks.
42*9356374aSAndroid Build Coastguard Worker // We started with a million blanks, and then deterministically insert
43*9356374aSAndroid Build Coastguard Worker // 10,000 copies each of two pangrams.  The result is a string that is
44*9356374aSAndroid Build Coastguard Worker // 40% blank space and 60% these words.  'the' occurs 18,247 times and
45*9356374aSAndroid Build Coastguard Worker // all the substitutions together occur 49,004 times.
46*9356374aSAndroid Build Coastguard Worker //
47*9356374aSAndroid Build Coastguard Worker // We then create "after_replacing_the" to be a string that is a result of
48*9356374aSAndroid Build Coastguard Worker // replacing "the" with "box" in big_string.
49*9356374aSAndroid Build Coastguard Worker //
50*9356374aSAndroid Build Coastguard Worker // And then we create "after_replacing_many" to be a string that is result
51*9356374aSAndroid Build Coastguard Worker // of preferring several substitutions.
SetUpStrings()52*9356374aSAndroid Build Coastguard Worker void SetUpStrings() {
53*9356374aSAndroid Build Coastguard Worker   if (big_string == nullptr) {
54*9356374aSAndroid Build Coastguard Worker     size_t r = 0;
55*9356374aSAndroid Build Coastguard Worker     big_string = new std::string(1000 * 1000, ' ');
56*9356374aSAndroid Build Coastguard Worker     for (std::string phrase : {"the quick brown fox jumped over the lazy dogs",
57*9356374aSAndroid Build Coastguard Worker                                "pack my box with the five dozen liquor jugs"}) {
58*9356374aSAndroid Build Coastguard Worker       for (int i = 0; i < 10 * 1000; ++i) {
59*9356374aSAndroid Build Coastguard Worker         r = r * 237 + 41;  // not very random.
60*9356374aSAndroid Build Coastguard Worker         memcpy(&(*big_string)[r % (big_string->size() - phrase.size())],
61*9356374aSAndroid Build Coastguard Worker                phrase.data(), phrase.size());
62*9356374aSAndroid Build Coastguard Worker       }
63*9356374aSAndroid Build Coastguard Worker     }
64*9356374aSAndroid Build Coastguard Worker     // big_string->resize(50);
65*9356374aSAndroid Build Coastguard Worker     // OK, we've set up the string, now let's set up expectations - first by
66*9356374aSAndroid Build Coastguard Worker     // just replacing "the" with "box"
67*9356374aSAndroid Build Coastguard Worker     after_replacing_the = new std::string(*big_string);
68*9356374aSAndroid Build Coastguard Worker     for (size_t pos = 0;
69*9356374aSAndroid Build Coastguard Worker          (pos = after_replacing_the->find("the", pos)) != std::string::npos;) {
70*9356374aSAndroid Build Coastguard Worker       memcpy(&(*after_replacing_the)[pos], "box", 3);
71*9356374aSAndroid Build Coastguard Worker     }
72*9356374aSAndroid Build Coastguard Worker     // And then with all the replacements.
73*9356374aSAndroid Build Coastguard Worker     after_replacing_many = new std::string(*big_string);
74*9356374aSAndroid Build Coastguard Worker     for (size_t pos = 0;;) {
75*9356374aSAndroid Build Coastguard Worker       size_t next_pos = static_cast<size_t>(-1);
76*9356374aSAndroid Build Coastguard Worker       const char* needle_string = nullptr;
77*9356374aSAndroid Build Coastguard Worker       const char* replacement_string = nullptr;
78*9356374aSAndroid Build Coastguard Worker       for (const auto& r : replacements) {
79*9356374aSAndroid Build Coastguard Worker         auto needlepos = after_replacing_many->find(r.needle, pos);
80*9356374aSAndroid Build Coastguard Worker         if (needlepos != std::string::npos && needlepos < next_pos) {
81*9356374aSAndroid Build Coastguard Worker           next_pos = needlepos;
82*9356374aSAndroid Build Coastguard Worker           needle_string = r.needle;
83*9356374aSAndroid Build Coastguard Worker           replacement_string = r.replacement;
84*9356374aSAndroid Build Coastguard Worker         }
85*9356374aSAndroid Build Coastguard Worker       }
86*9356374aSAndroid Build Coastguard Worker       if (next_pos > after_replacing_many->size()) break;
87*9356374aSAndroid Build Coastguard Worker       after_replacing_many->replace(next_pos, strlen(needle_string),
88*9356374aSAndroid Build Coastguard Worker                                     replacement_string);
89*9356374aSAndroid Build Coastguard Worker       next_pos += strlen(replacement_string);
90*9356374aSAndroid Build Coastguard Worker       pos = next_pos;
91*9356374aSAndroid Build Coastguard Worker     }
92*9356374aSAndroid Build Coastguard Worker   }
93*9356374aSAndroid Build Coastguard Worker }
94*9356374aSAndroid Build Coastguard Worker 
BM_StrReplaceAllOneReplacement(benchmark::State & state)95*9356374aSAndroid Build Coastguard Worker void BM_StrReplaceAllOneReplacement(benchmark::State& state) {
96*9356374aSAndroid Build Coastguard Worker   SetUpStrings();
97*9356374aSAndroid Build Coastguard Worker   std::string src = *big_string;
98*9356374aSAndroid Build Coastguard Worker   for (auto _ : state) {
99*9356374aSAndroid Build Coastguard Worker     std::string dest = absl::StrReplaceAll(src, {{"the", "box"}});
100*9356374aSAndroid Build Coastguard Worker     ABSL_RAW_CHECK(dest == *after_replacing_the,
101*9356374aSAndroid Build Coastguard Worker                    "not benchmarking intended behavior");
102*9356374aSAndroid Build Coastguard Worker   }
103*9356374aSAndroid Build Coastguard Worker }
104*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrReplaceAllOneReplacement);
105*9356374aSAndroid Build Coastguard Worker 
BM_StrReplaceAll(benchmark::State & state)106*9356374aSAndroid Build Coastguard Worker void BM_StrReplaceAll(benchmark::State& state) {
107*9356374aSAndroid Build Coastguard Worker   SetUpStrings();
108*9356374aSAndroid Build Coastguard Worker   std::string src = *big_string;
109*9356374aSAndroid Build Coastguard Worker   for (auto _ : state) {
110*9356374aSAndroid Build Coastguard Worker     std::string dest = absl::StrReplaceAll(src, {{"the", "box"},
111*9356374aSAndroid Build Coastguard Worker                                                  {"brown", "quick"},
112*9356374aSAndroid Build Coastguard Worker                                                  {"jumped", "liquored"},
113*9356374aSAndroid Build Coastguard Worker                                                  {"dozen", "brown"},
114*9356374aSAndroid Build Coastguard Worker                                                  {"lazy", "pack"},
115*9356374aSAndroid Build Coastguard Worker                                                  {"liquor", "shakes"}});
116*9356374aSAndroid Build Coastguard Worker     ABSL_RAW_CHECK(dest == *after_replacing_many,
117*9356374aSAndroid Build Coastguard Worker                    "not benchmarking intended behavior");
118*9356374aSAndroid Build Coastguard Worker   }
119*9356374aSAndroid Build Coastguard Worker }
120*9356374aSAndroid Build Coastguard Worker BENCHMARK(BM_StrReplaceAll);
121*9356374aSAndroid Build Coastguard Worker 
122*9356374aSAndroid Build Coastguard Worker }  // namespace
123