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