/* * ver. 1.7.2 * (c) Проект "SimStr", Александр Орефков orefkov@gmail.com * Бенчмарки * (c) Project "SimStr", Aleksandr Orefkov orefkov@gmail.com * Benchmarks */ #include #include #include "bench.h" #include #include #include #include #include #include using namespace simstr; using namespace std::literals; #ifdef EMSCRIPTEN #include bool do_sync = false; static void DoTeardown(const benchmark::State& state) { // Это нужно чтобы интерфейс браузера обновился // This is necessary for the browser interface to refresh. if (!do_sync) { emscripten_sleep(1); } } #undef BENCHMARK #define BENCHMARK(...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>(#__VA_ARGS__, \ __VA_ARGS__)))->Teardown(DoTeardown) #undef BENCHMARK_CAPTURE #define BENCHMARK_CAPTURE(func, test_case_name, ...) \ BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \ (::benchmark::internal::RegisterBenchmarkInternal( \ ::benchmark::internal::make_unique< \ ::benchmark::internal::FunctionBenchmark>( \ #func "/" #test_case_name, \ [](::benchmark::State& st) { func(st, __VA_ARGS__); })))->Teardown(DoTeardown) #endif #define TEST_TEXT "Test text" #define LONG_TEXT "123456789012345678901234567890" #define TEXT_16 "abbaabbaabbaabba" //#define CHECK_RESULT void __(benchmark::State& state) { for (auto _: state) {} } namespace sz = ashvardanian::stringzilla; sz::string email_concat_stringzilla_app(sz::string name, sz::string_view domain, sz::string_view tld) { return name.append("@").append(domain).append(".").append(tld); } //> sz::string email_concat_stringzilla_app(sz::string name, sz::string_view domain, sz::string_view tld) { void ConcatEmailSzApp(benchmark::State& state) { sz::string name = "username"; sz::string_view domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_stringzilla_app(name, domain, tld); benchmark::DoNotOptimize(email); } } sz::string email_concat_stringzilla_exp(sz::string name, sz::string_view domain, sz::string_view tld) { return sz::string{name | sz::string_view{"@"} | domain | sz::string_view{"."} | tld}; } //> sz::string email_concat_stringzilla_exp(sz::string name, sz::string_view domain, sz::string_view tld) { void ConcatEmailSzExp(benchmark::State& state) { sz::string name = "username"; sz::string_view domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_stringzilla_exp(name, domain, tld); benchmark::DoNotOptimize(email); } } std::string email_concat_format(std::string_view name, std::string_view domain, std::string_view tld) { return std::format("{}@{}.{}", name, domain, tld); } //> std::string email_concat_format(std::string_view name, std::string_view domain, std::string_view tld) { void ConcatEmailFormat(benchmark::State& state) { std::string_view name = "username", domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_format(name, domain, tld); benchmark::DoNotOptimize(email); } } std::string email_concat_stream(std::string_view name, std::string_view domain, std::string_view tld) { std::stringstream s; s << name << "@" << domain << "." << tld; return s.str(); } //> std::string email_concat_stream(std::string_view name, std::string_view domain, std::string_view tld) { void ConcatEmailStream(benchmark::State& state) { std::string_view name = "username", domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_stream(name, domain, tld); benchmark::DoNotOptimize(email); } } std::string email_concat_std(std::string name, std::string_view domain, std::string_view tld) { return name.append("@").append(domain).append(".").append(tld); } //> std::string email_concat_std(std::string name, std::string_view domain, std::string_view tld) { void ConcatEmailStd(benchmark::State& state) { std::string name = "username"; std::string_view domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_std(name, domain, tld); benchmark::DoNotOptimize(email); } } std::string email_concat_std_expr(std::string_view name, std::string_view domain, std::string_view tld) { return +name + "@" + domain + "." + tld; } //> std::string email_concat_std_expr(std::string_view name, std::string_view domain, std::string_view tld) { void ConcatEmailStdExp(benchmark::State& state) { std::string_view name = "username", domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_std_expr(name, domain, tld); benchmark::DoNotOptimize(email); } } stringa email_concat_sim_expr(ssa name, ssa domain, ssa tld) { return name + "@" + domain + "." + tld; } //> stringa email_concat_sim_expr(ssa name, ssa domain, ssa tld) { void ConcatEmailSimExp(benchmark::State& state) { ssa name = "username", domain = "verybigdomain", tld = "tld"; for (auto _: state) { benchmark::DoNotOptimize(name); benchmark::DoNotOptimize(domain); benchmark::DoNotOptimize(tld); auto email = email_concat_sim_expr(name, domain, tld); benchmark::DoNotOptimize(email); } } BENCHMARK(__)->Name("----- Concatenate email ---------")->Repetitions(1); BENCHMARK(ConcatEmailFormat)->Name("Concat email std::format"); BENCHMARK(ConcatEmailStream)->Name("Concat email std::stringstream"); BENCHMARK(ConcatEmailSzApp) ->Name("Concat email stringzilla append"); BENCHMARK(ConcatEmailSzExp) ->Name("Concat email stringzilla concat"); BENCHMARK(ConcatEmailStd) ->Name("Concat email std::string append"); BENCHMARK(ConcatEmailStdExp)->Name("Concat email std::string by strexpr"); BENCHMARK(ConcatEmailSimExp)->Name("Concat email stringa"); void ConcatStdToStd(benchmark::State& state) { std::string s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); std::string str = s1 + std::to_string(i) + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToStd(benchmark::State& state) { std::string s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); std::string str = +s1 + i + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToSim(benchmark::State& state) { stra s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = s1 + i + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToSimConcat(benchmark::State& state) { stra s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = e_concat("", s1, i, " end"); benchmark::DoNotOptimize(str); } } } BENCHMARK(__)->Name("----- Concatenate string + Number + \"Literal\" ---------")->Repetitions(1); BENCHMARK(ConcatStdToStd) ->Name("Concat std::string and number by std to std::string"); BENCHMARK(ConcatSimToStd) ->Name("Concat std::string and number by StrExpr to std::string"); BENCHMARK(ConcatSimToSim) ->Name("Concat stringa and number by StrExpr to simstr::stringa"); BENCHMARK(ConcatSimToSimConcat) ->Name("Concat stringa and number by e_concat to simstr::stringa"); void ConcatStdToFmtHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // It is not worked for char8_t, char16_t, char32_t :( std::string str = s1 + std::format("{:#x}", i) + " end"; benchmark::DoNotOptimize(str); } } } void ConcatAllFmtToHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // It is not worked for char8_t, char16_t, char32_t :( std::string str = std::format("{}{:#x} end", s1, i); benchmark::DoNotOptimize(str); } } } void ConcatStdToCharsHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // it worked only for char :( char buf[40]; size_t len = std::to_chars(buf, buf + std::size(buf), i, 16).ptr - buf; std::string str = s1 + "0x" + std::string(buf, len) + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToStdHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // Can work for all types of symbols std::string str = +s1 + i / 1_f16 + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToSimHex(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // Can work for all types of symbols stringa str = s1 + i / 1_f16 + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToSimHexC(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // Can work for all types of symbols stringa str = e_concat("", s1, i / 1_f16, " end"); benchmark::DoNotOptimize(str); } } } void ConcatSimToSimHexS(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = e_subst("{}{} end", s1, i / 1_f16); benchmark::DoNotOptimize(str); } } } void ConcatSimToSimHexVS(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = e_vsubst("{}{} end"_ss, s1, i / 1_f16); benchmark::DoNotOptimize(str); } } } BENCHMARK(__)->Name("----- Concatenate string + Hex Number + \"Literal\" ---------")->Repetitions(1); BENCHMARK(ConcatStdToFmtHex) ->Name("Concat std::string and format hex number and literal to std::string"); BENCHMARK(ConcatAllFmtToHex) ->Name("std::format std::string and hex number by literal to std::string"); BENCHMARK(ConcatStdToCharsHex) ->Name("Concat std::string and std::to_chars and string to std::string"); BENCHMARK(ConcatSimToStdHex) ->Name("Concat std::string and hex number and literal by StrExpr to std::string"); BENCHMARK(ConcatSimToSimHex) ->Name("Concat stringa and hex number and literal by StrExpr to simstr::stringa"); BENCHMARK(ConcatSimToSimHexC) ->Name("Concat stringa and hex number and literal by e_concat to simstr::stringa"); BENCHMARK(ConcatSimToSimHexS) ->Name("Subst stringa and hex number by e_subst literal to simstr::stringa"); BENCHMARK(ConcatSimToSimHexVS) ->Name("Subst stringa and hex number by e_vsubst stra to simstr::stringa"); void ConcatSimToSimOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { stringa str = "abcdefghihklmopqr "_ss + i / 0x8a010_fmt + " end"; benchmark::DoNotOptimize(str); } } } void SubstSimToSimOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { stringa str = e_subst("abcdefghihklmopqr {} end", i / 0x8a010_fmt); benchmark::DoNotOptimize(str); } } } void VSubstSimToSimOct(benchmark::State& state) { ssa pattern = "abcdefghihklmopqr {} end"; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { stringa str = e_vsubst(pattern, i / 0x8a010_fmt); benchmark::DoNotOptimize(str); } } } void FormatStdToStdOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = std::format("abcdefghihklmopqr {:#010o} end", i); benchmark::DoNotOptimize(str); } } } void VFormatStdToStdOct(benchmark::State& state) { std::string_view pattern = "abcdefghihklmopqr {:#010o} end"; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = std::vformat(pattern, std::make_format_args(i)); benchmark::DoNotOptimize(str); } } } void StreamStdToStdOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::stringstream strm; strm << "abcdefghihklmopqr 0" << std::oct << std::setw(9) << std::setfill('0') << i << " end"; std::string str = strm.str(); benchmark::DoNotOptimize(str); } } } void FmtFormatComp(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = fmt::format(FMT_COMPILE("abcdefghihklmopqr {:#010o} end"), i); benchmark::DoNotOptimize(str); } } } void FmtFormat(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = fmt::format("abcdefghihklmopqr {:#010o} end", i); benchmark::DoNotOptimize(str); } } } void StdFormatSize(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { size_t len = std::formatted_size("abcdefghihklmopqr {:#010o} end", i); std::string str(len, 0); std::format_to_n(str.data(), len, "abcdefghihklmopqr {:#010o} end", i); benchmark::DoNotOptimize(str); } } } BENCHMARK(__)->Name("---- format/vformat and subst/vsubst octal number to 32 symbols result ----")->Repetitions(1); BENCHMARK(ConcatSimToSimOct) ->Name("\"abcdefghihklmopqr \"_ss + i / 0x8a010_fmt + \" end\""); BENCHMARK(SubstSimToSimOct) ->Name("e_subst(\"abcdefghihklmopqr {} end\", i / 0x8a010_fmt)"); BENCHMARK(VSubstSimToSimOct) ->Name("e_vsubst(pattern, i / 0x8a010_fmt)"); BENCHMARK(FmtFormatComp) ->Name("fmt::format(FMT_COMPILE(\"abcdefghihklmopqr {:#010o} end\"), i)"); BENCHMARK(FmtFormat) ->Name("fmt::format(\"abcdefghihklmopqr {:#010o} end\", i)"); BENCHMARK(FormatStdToStdOct) ->Name("std::format(\"abcdefghihklmopqr {:#010o} end\", i)"); BENCHMARK(VFormatStdToStdOct) ->Name("std::vformat(pattern, std::make_format_args(i))"); BENCHMARK(StdFormatSize) ->Name("std::format with std::formatted_size"); BENCHMARK(StreamStdToStdOct) ->Name("strm << \"abcdefghihklmopqr 0\" << std::oct << std::setw(9) << std::setfill('0') << i << \" end\""); void ConcatStdToStdS(benchmark::State& state) { std::string s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); std::string str = s1 + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToStdS(benchmark::State& state) { std::string s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); std::string str = +s1 + " end"; benchmark::DoNotOptimize(str); } } } void ConcatSimToSimS(benchmark::State& state) { stra s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = s1 + " end"; benchmark::DoNotOptimize(str); } } } BENCHMARK(__)->Name("----- Concatenate string + \"Literal\" ---------")->Repetitions(1); BENCHMARK(ConcatStdToStdS) ->Name("Concat std::string by std to std::string"); BENCHMARK(ConcatSimToStdS) ->Name("Concat std::string by StrExpr to std::string"); BENCHMARK(ConcatSimToSimS) ->Name("Concat stringa by StrExpr to stringa"); size_t find_pos_str(std::string_view src, std::string_view name) { // before C++26 we can not concatenate string and string_view... return src.find("\n- "s + std::string{name} + " -\n"); } size_t find_pos_exp(ssa src, ssa name) { return src.find(std::string{"\n- " + name + " -\n"}); } size_t find_pos_sim(ssa src, ssa name) { return src.find(lstringa<200>{"\n- " + name + " -\n"}); } size_t find_pos_sz(sz::string_view src, sz::string_view name) { return src.find(sz::string{"\n- "}.append(name).append(" -\n")); } //> size_t find_pos_str(std::string_view src, std::string_view name) { void FindConcatThreeStr(benchmark::State& state) { std::string_view src = "sdfsdf\n- testtesttesttesttesttesttestte -\nsfrgdgfsg"; std::string_view fnd = "testtesttesttesttesttesttestte"; for (auto _: state) { benchmark::DoNotOptimize(src); benchmark::DoNotOptimize(fnd); size_t pos = find_pos_str(src, fnd); benchmark::DoNotOptimize(pos); #ifdef CHECK_RESULT if (pos != 6) { state.SkipWithError("fail"); } #endif } } //> size_t find_pos_exp(ssa src, ssa name) { void FindConcatThreeExp(benchmark::State& state) { std::string_view src = "sdfsdf\n- testtesttesttesttesttesttestte -\nsfrgdgfsg"; std::string_view fnd = "testtesttesttesttesttesttestte"; for (auto _: state) { benchmark::DoNotOptimize(src); benchmark::DoNotOptimize(fnd); size_t pos = find_pos_exp(src, fnd); benchmark::DoNotOptimize(pos); #ifdef CHECK_RESULT if (pos != 6) { state.SkipWithError("fail"); } #endif } } //> size_t find_pos_sim(ssa src, ssa name) { void FindConcatThreeSim(benchmark::State& state) { ssa src = "sdfsdf\n- testtesttesttesttesttesttestte -\nsfrgdgfsg"; ssa fnd = "testtesttesttesttesttesttestte"; for (auto _: state) { benchmark::DoNotOptimize(src); benchmark::DoNotOptimize(fnd); size_t pos = find_pos_sim(src, fnd); benchmark::DoNotOptimize(pos); #ifdef CHECK_RESULT if (pos != 6) { state.SkipWithError("fail"); } #endif } } //> size_t find_pos_sz(sz::string_view src, sz::string_view name) { void FindConcatThreeSz(benchmark::State& state) { sz::string_view src = "sdfsdf\n- testtesttesttesttesttesttestte -\nsfrgdgfsg"; sz::string_view fnd = "testtesttesttesttesttesttestte"; for (auto _: state) { benchmark::DoNotOptimize(src); benchmark::DoNotOptimize(fnd); size_t pos = find_pos_sz(src, fnd); benchmark::DoNotOptimize(pos); #ifdef CHECK_RESULT if (pos != 6) { state.SkipWithError("fail"); } #endif } } BENCHMARK(__)->Name("----- Find three concatenated string in string_view -----")->Repetitions(1); BENCHMARK(FindConcatThreeStr)->Name("Find concat three std::string"); BENCHMARK(FindConcatThreeExp)->Name("Find concat three strexpr"); BENCHMARK(FindConcatThreeSim)->Name("Find concat three simstr"); BENCHMARK(FindConcatThreeSz) ->Name("Find concat three stringzilla string"); std::string buildTypeNameStr(std::string_view type_name, size_t prec, size_t scale) { std::string res{type_name}; if (prec) { res += "(" + std::to_string(prec); if (scale) { res += "," + std::to_string(scale); } res += ")"; } return res; } std::string buildTypeNameExp(ssa type_name, size_t prec, size_t scale) { if (prec) { return type_name + "(" + prec + e_if(scale, ","_ss + scale) + ")"; } return type_name; } stringa buildTypeNameSim(ssa type_name, size_t prec, size_t scale) { if (prec) { return type_name + "(" + prec + e_if(scale, ","_ss + scale) + ")"; } return type_name; } //> std::string buildTypeNameStr(std::string_view type_name, size_t prec, size_t scale) { void BuildTypeNameStr(benchmark::State& state) { std::string_view type_name = "numeric"; size_t prec = state.range(0), scale = prec / 2; for (auto _: state) { benchmark::DoNotOptimize(type_name); benchmark::DoNotOptimize(prec); benchmark::DoNotOptimize(scale); std::string res = buildTypeNameStr(type_name, prec, scale); benchmark::DoNotOptimize(res); } } //> std::string buildTypeNameExp(ssa type_name, size_t prec, size_t scale) { void BuildTypeNameExp(benchmark::State& state) { std::string_view type_name = "numeric"; size_t prec = state.range(0), scale = prec / 2; for (auto _: state) { benchmark::DoNotOptimize(type_name); benchmark::DoNotOptimize(prec); benchmark::DoNotOptimize(scale); std::string res = buildTypeNameExp(type_name, prec, scale); benchmark::DoNotOptimize(res); } } //> stringa buildTypeNameSim(ssa type_name, size_t prec, size_t scale) { void BuildTypeNameSim(benchmark::State& state) { ssa type_name = "numeric"; size_t prec = state.range(0), scale = prec / 2; for (auto _: state) { benchmark::DoNotOptimize(type_name); benchmark::DoNotOptimize(prec); benchmark::DoNotOptimize(scale); stringa res = buildTypeNameSim(type_name, prec, scale); benchmark::DoNotOptimize(res); } } BENCHMARK(__)->Name("----- Build Type Name ---------")->Repetitions(1); BENCHMARK(BuildTypeNameStr) ->Name("BuildTypeNameStr 0")->Arg(0); BENCHMARK(BuildTypeNameExp) ->Name("BuildTypeNameExp 0")->Arg(0); BENCHMARK(BuildTypeNameSim) ->Name("BuildTypeNameSim 0")->Arg(0); BENCHMARK(BuildTypeNameStr) ->Name("BuildTypeNameStr 10")->Arg(10); BENCHMARK(BuildTypeNameExp) ->Name("BuildTypeNameExp 10")->Arg(10); BENCHMARK(BuildTypeNameSim) ->Name("BuildTypeNameSim 10")->Arg(10); std::string make_str_str(std::string_view from, std::string_view pattern, std::string_view repl) { auto str_replace = [](std::string_view from, std::string_view pattern, std::string_view repl) { std::string result; for (size_t offset = 0; ;) { size_t pos = from.find(pattern, offset); if (pos == std::string::npos) { result += from.substr(offset); break; } result += from.substr(offset, pos - offset); result += repl; offset = pos + pattern.length(); } return result; }; return "<" + str_replace(from, pattern, repl) + ">"; } std::string make_str_exp(std::string_view from, std::string_view pattern, std::string_view repl) { return "<" + e_repl(from, pattern, repl) + ">"; } //> std::string make_str_str(std::string_view from, std::string_view pattern, std::string_view repl) { void ReplaceStr(benchmark::State& state) { std::string_view from = "testitestitestitesti", what = "te", repl = "--+--"; for (auto _: state) { benchmark::DoNotOptimize(from); benchmark::DoNotOptimize(what); benchmark::DoNotOptimize(repl); std::string res = make_str_str(from, what, repl); benchmark::DoNotOptimize(res); } } //> std::string make_str_exp(std::string_view from, std::string_view pattern, std::string_view repl) { void ReplaceExp(benchmark::State& state) { std::string_view from = "testitestitestitesti", what = "te", repl = "--+--"; for (auto _: state) { benchmark::DoNotOptimize(from); benchmark::DoNotOptimize(what); benchmark::DoNotOptimize(repl); std::string res = make_str_exp(from, what, repl); benchmark::DoNotOptimize(res); } } BENCHMARK(__)->Name("----- Replace string by copy -----")->Repetitions(1); BENCHMARK(ReplaceStr)->Name("Concat with replace str"); BENCHMARK(ReplaceExp)->Name("Concat with replace exp"); template void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } } BENCHMARK(__)->Name("----- Create Empty Str ---------")->Repetitions(1); BENCHMARK(CreateEmpty) ->Name("std::string e;"); BENCHMARK(CreateEmpty) ->Name("std::string_view e;"); BENCHMARK(CreateEmpty) ->Name("ssa e;"); BENCHMARK(CreateEmpty) ->Name("stringa e;"); BENCHMARK(CreateEmpty>) ->Name("lstringa<20> e;"); BENCHMARK(CreateEmpty>) ->Name("lstringa<40> e;"); template void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } } BENCHMARK(__)->Name("----- Create Str from short literal (9 symbols) --------")->Repetitions(1); BENCHMARK(CreateShortLiteral) ->Name("std::string e = \"Test text\";"); BENCHMARK(CreateShortLiteral) ->Name("std::string_view e = \"Test text\";"); BENCHMARK(CreateShortLiteral) ->Name("ssa e = \"Test text\";"); BENCHMARK(CreateShortLiteral) ->Name("stringa e = \"Test text\";"); BENCHMARK(CreateShortLiteral>) ->Name("lstringa<20> e = \"Test text\";"); BENCHMARK(CreateShortLiteral>) ->Name("lstringa<40> e = \"Test text\";"); template void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } BENCHMARK(__)->Name("----- Create Str from long literal (30 symbols) ---------")->Repetitions(1); BENCHMARK(CreateLongLiteral) ->Name("std::string e = \"123456789012345678901234567890\";"); BENCHMARK(CreateLongLiteral) ->Name("std::string_view e = \"123456789012345678901234567890\";"); BENCHMARK(CreateLongLiteral) ->Name("ssa e = \"123456789012345678901234567890\";"); BENCHMARK(CreateLongLiteral) ->Name("stringa e = \"123456789012345678901234567890\";"); BENCHMARK(CreateLongLiteral>) ->Name("lstringa<20> e = \"123456789012345678901234567890\";"); BENCHMARK(CreateLongLiteral>) ->Name("lstringa<40> e = \"123456789012345678901234567890\";"); template void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } BENCHMARK(__)->Name("----- Create copy of Str with 9 symbols ---------")->Repetitions(1); BENCHMARK(CopyShortString) ->Name("std::string e = \"Test text\"; auto c{e};"); BENCHMARK(CopyShortString) ->Name("std::string_view e = \"Test text\"; auto c{e};"); BENCHMARK(CopyShortString) ->Name("ssa e = \"Test text\"; auto c{e};"); BENCHMARK(CopyShortString) ->Name("stringa e = \"Test text\"; auto c{e};"); BENCHMARK(CopyShortString>) ->Name("lstringa<20> e = \"Test text\"; auto c{e};"); BENCHMARK(CopyShortString>) ->Name("lstringa<40> e = \"Test text\"; auto c{e};"); template void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } } BENCHMARK(__)->Name("----- Create copy of Str with 30 symbols ---------")->Repetitions(1); BENCHMARK(CopyLongString) ->Name("std::string e = \"123456789012345678901234567890\"; auto c{e};"); BENCHMARK(CopyLongString) ->Name("std::string_view e = \"123456789012345678901234567890\"; auto c{e};"); BENCHMARK(CopyLongString) ->Name("ssa e = \"123456789012345678901234567890\"; auto c{e};"); BENCHMARK(CopyLongString) ->Name("stringa e = \"123456789012345678901234567890\"; auto c{e};"); BENCHMARK(CopyLongString>) ->Name("lstringa<20> e = \"123456789012345678901234567890\"; auto c{e};"); BENCHMARK(CopyLongString>) ->Name("lstringa<40> e = \"123456789012345678901234567890\"; auto c{e};"); template void Find(benchmark::State& state) { T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT}; for (auto _: state) { int i = (int)x.find(TEST_TEXT); #ifdef CHECK_RESULT if (i != 90) { state.SkipWithError("not find?"); break; } #endif benchmark::DoNotOptimize(i); benchmark::DoNotOptimize(x); } } BENCHMARK(__)->Name("----- Find 9 symbols text in end of 99 symbols text ---------")->Repetitions(1); BENCHMARK(Find)->Name("sz::string::find;"); BENCHMARK(Find) ->Name("std::string::find;"); BENCHMARK(Find) ->Name("std::string_view::find;"); BENCHMARK(Find) ->Name("ssa::find;"); BENCHMARK(Find) ->Name("stringa::find;"); BENCHMARK(Find>) ->Name("lstringa<20>::find;"); BENCHMARK(Find>) ->Name("lstringa<40>::find;"); template void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } BENCHMARK(__)->Name("------- Copy not literal Str with N symbols ---------")->Repetitions(1); BENCHMARK(CopyDynString) ->Name("std::string copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096); BENCHMARK(CopyDynString) ->Name("stringa copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096); BENCHMARK(CopyDynString>) ->Name("lstringa<16> copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096); BENCHMARK(CopyDynString>) ->Name("lstringa<512> copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096); void ToIntStr10(benchmark::State& state, const std::string& s, int c) { for (auto _: state) { int res = std::strtol(s.c_str(), nullptr, 10); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } void ToIntStr16(benchmark::State& state, const std::string& s, int c) { for (auto _: state) { int res = std::strtol(s.c_str(), nullptr, 16); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } void ToIntStr0(benchmark::State& state, const std::string& s, int c) { for (auto _: state) { int res = std::strtol(s.c_str(), nullptr, 0); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c) { for (auto _: state) { int res = 0; std::from_chars(s.data(), s.data() + s.size(), res, 10); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c) { for (auto _: state) { int res = 0; std::from_chars(s.data(), s.data() + s.size(), res, 16); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } template void ToIntSimStr10(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } } template void ToIntSimStr16(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } } template void ToIntSimStr0(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } } void ToIntNoOverflow(benchmark::State& state, ssa t, int c) { for (auto _: state) { int res = t.to_int().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } } BENCHMARK(__)->Name("----- Convert to int '1234567' ---------")->Repetitions(1); BENCHMARK_CAPTURE(ToIntStr10, , std::string{"123456789"}, 123456789) ->Name("std::string s = \"123456789\"; int res = std::strtol(s.c_str(), 0, 10);"); BENCHMARK_CAPTURE(ToIntFromChars10, , std::string_view{"123456789"}, 123456789) ->Name("std::string_view s = \"123456789\"; std::from_chars(s.data(), s.data() + s.size(), res, 10);"); BENCHMARK_CAPTURE(ToIntSimStr10, , stringa{"123456789"}, 123456789) ->Name("stringa s = \"123456789\"; int res = s.to_int"); BENCHMARK_CAPTURE(ToIntSimStr10, , ssa{"123456789"}, 123456789) ->Name("ssa s = \"123456789\"; int res = s.to_int"); BENCHMARK_CAPTURE(ToIntSimStr10, , lstringa<20>{"123456789"}, 123456789) ->Name("lstringa<20> s = \"123456789\"; int res = s.to_int"); BENCHMARK(__)->Name("----- Convert to unsigned 'abcDef' ---------")->Repetitions(1); BENCHMARK_CAPTURE(ToIntStr16, , std::string{"abcDef"}, 0xabcDef) ->Name("std::string s = \"abcDef\"; int res = std::strtol(s.c_str(), 0, 16);"); BENCHMARK_CAPTURE(ToIntFromChars16, , std::string_view{"abcDef"}, 0xabcDef) ->Name("std::string_view s = \"abcDef\"; std::from_chars(s.data(), s.data() + s.size(), res, 16);"); BENCHMARK_CAPTURE(ToIntSimStr16, , stringa{"abcDef"}, 0xabcDef) ->Name("stringa s = \"abcDef\"; int res = s.to_int"); BENCHMARK_CAPTURE(ToIntSimStr16, , ssa{"abcDef"}, 0xabcDef) ->Name("ssa s = \"abcDef\"; int res = s.to_int"); BENCHMARK_CAPTURE(ToIntSimStr16, >, lstringa<20>{"abcDef"}, 0xabcDef) ->Name("lstringa<20> s = \"abcDef\"; int res = s.to_int"); BENCHMARK(__)->Name("----- Convert to int ' 1234567' ---------")->Repetitions(1); BENCHMARK_CAPTURE(ToIntStr0, , std::string{" 123456789"}, 123456789) ->Name("std::string s = \" 123456789\"; int res = std::strtol(s.c_str(), 0, 0);"); BENCHMARK_CAPTURE(ToIntSimStr0, , stringa{" 123456789"}, 123456789) ->Name("stringa s = \" 123456789\"; int res = s.to_int; // Check overflow"); BENCHMARK_CAPTURE(ToIntNoOverflow, , ssa{" 123456789"}, 123456789) ->Name("ssa s = \" 123456789\"; int res = s.to_int; // No check overflow"); void ToDoubleStr(benchmark::State& state, const std::string& s, double c) { for (auto _: state) { char* ptr = nullptr; double res = std::strtod(s.c_str(), &ptr); if (ptr == s.c_str()) { state.SkipWithError("not equal"); } #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } template void ToDoubleFromChars(benchmark::State& state, const std::string_view& s, double c) { for (auto _: state) { double res = 0; if constexpr (requires { std::from_chars(std::declval(), std::declval(), std::declval()); }) { if (std::from_chars((const K*)s.data(), (const K*)s.data() + s.size(), res).ec != std::errc{}) { state.SkipWithError("not equal"); } } else { state.SkipWithError("not implemented"); } #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } template void ToDoubleSimStr(benchmark::State& state, T t, double c) { for (auto _: state) { auto r = t.template to_double(); if (!r) { state.SkipWithError("not equal"); } double res = *r; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } } BENCHMARK(__)->Name("----- Convert to double '1234.567e10' ---------")->Repetitions(1); BENCHMARK_CAPTURE(ToDoubleStr, , std::string{"1234.567e10"}, 1234.567e10) ->Name("std::string s = \"1234.567e10\"; double res = std::strtod(s.c_str(), nullptr);"); BENCHMARK_CAPTURE(ToDoubleFromChars, , std::string_view{"1234.567e10"}, 1234.567e10) ->Name("std::string_view s = \"1234.567e10\"; std::from_chars(s.data(), s.data() + s.size(), res);"); BENCHMARK_CAPTURE(ToDoubleSimStr, , ssa{"1234.567e10"}, 1234.567e10) ->Name("ssa s = \"1234.567e10\"; double res = *s.to_double()"); void AppendStreamConstLiteral(benchmark::State& state) { for (auto _: state) { std::string result; std::stringstream str; for (size_t c = 0; c < 64; c++) { str << TEXT_16; } result = str.str(); #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(str); } } void AppendStdStringConstLiteral(benchmark::State& state) { for (auto _: state) { std::string result; for (size_t c = 0; c < 64; c++) { result += TEXT_16; } #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); } } template void AppendLstringConstLiteral(benchmark::State& state) { for (auto _: state) { lstringa result; for (size_t c = 0; c < 64; c++) { result += TEXT_16; } #ifdef CHECK_RESULT if (result.length() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); } } BENCHMARK(__)->Name("-- Append const literal of 16 bytes 64 times, 1024 total length --")->Repetitions(1); BENCHMARK(AppendStreamConstLiteral) ->Name("std::stringstream str; ... str << \"abbaabbaabbaabba\";"); BENCHMARK(AppendStdStringConstLiteral) ->Name("std::string str; ... str += \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringConstLiteral<8>) ->Name("lstringa<8> str; ... str += \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringConstLiteral<128>) ->Name("lstringa<128> str; ... str += \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringConstLiteral<512>) ->Name("lstringa<512> str; ... str += \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringConstLiteral<1024>)->Name("lstringa<1024> str; ... str += \"abbaabbaabbaabba\";"); void AppendStreamStrConstLiteral(benchmark::State& state) { std::string s1 = TEXT_16; for (auto _: state) { std::string result; std::stringstream s; for (size_t c = 0; c < 32; c++) { s << s1 << TEXT_16; } result = s.str(); #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); } } void AppendStdStrStrConstLiteral(benchmark::State& state) { std::string p1 = TEXT_16; for (auto _: state) { std::string result; for (size_t c = 0; c < 32; c++) { result += p1 + TEXT_16; } #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(p1); } } template void AppendLstringStrConstLiteral(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa result; for (size_t c = 0; c < 32; c++) { result += p1 + TEXT_16; } #ifdef CHECK_RESULT if (result.length() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(p1); } } BENCHMARK(__)->Name("-- Append string of 16 bytes and const literal of 16 bytes 32 times, 1024 total length --")->Repetitions(1); BENCHMARK(AppendStreamStrConstLiteral) ->Name("std::stringstream str; ... str << str_var << \"abbaabbaabbaabba\";"); BENCHMARK(AppendStdStrStrConstLiteral) ->Name("std::string str; ... str += str_var + \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringStrConstLiteral<8>) ->Name("lstringa<8> str; ... str += str_var + \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringStrConstLiteral<128>) ->Name("lstringa<128> str; ... str += str_var + \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringStrConstLiteral<512>) ->Name("lstringa<512> str; ... str += str_var + \"abbaabbaabbaabba\";"); BENCHMARK(AppendLstringStrConstLiteral<1024>) ->Name("lstringa<1024> str; ... str += str_var + \"abbaabbaabbaabba\";"); void AppendStreamStrConstLiteralBig(benchmark::State& state) { std::string s1 = TEXT_16; for (auto _: state) { std::string result; std::stringstream s; for (size_t c = 0; c < 2048; c++) { s << s1 << TEXT_16; } result = s.str(); #ifdef CHECK_RESULT if (result.size() != 1024 * 64) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); } } void AppendStdStrStrConstLiteralBig(benchmark::State& state) { std::string p1 = TEXT_16; for (auto _: state) { std::string result; for (size_t c = 0; c < 2048; c++) { result += p1 + TEXT_16; } #ifdef CHECK_RESULT if (result.size() != 1024 * 64) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(p1); } } template void AppendLstringStrConstLiteralBig(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa result; for (size_t c = 0; c < 2048; c++) { result += p1 + TEXT_16; } #ifdef CHECK_RESULT if (result.length() != 1024 * 64) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(p1); } } BENCHMARK(__)->Name("-- Append string of 16 bytes and const literal of 16 bytes 2048 times, 65536 total length --")->Repetitions(1); BENCHMARK(AppendStreamStrConstLiteralBig) ->Name("std::stringstream str; ... str << str_var << \"abbaabbaabbaabba\"; 2048 times"); BENCHMARK(AppendStdStrStrConstLiteralBig) ->Name("std::string str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times"); BENCHMARK(AppendLstringStrConstLiteralBig<8>) ->Name("lstringa<8> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times"); BENCHMARK(AppendLstringStrConstLiteralBig<128>) ->Name("lstringa<128> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times"); BENCHMARK(AppendLstringStrConstLiteralBig<512>) ->Name("lstringa<512> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times"); BENCHMARK(AppendLstringStrConstLiteralBig<1024>) ->Name("lstringa<1024> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times"); void AppendStream2String(benchmark::State& state) { std::string s1 = TEXT_16; std::string s2 = TEXT_16; for (auto _: state) { std::string result; std::stringstream s; for (size_t c = 0; c < 32; c++) { s << s1 << s2; } result = s.str(); #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); benchmark::DoNotOptimize(s2); } } void AppendStdStr2String(benchmark::State& state) { std::string s1 = TEXT_16; std::string s2 = TEXT_16; for (auto _: state) { std::string result; for (size_t c = 0; c < 32; c++) { result += s1 + s2; } #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); benchmark::DoNotOptimize(s2); } } template void AppendLstring2String(benchmark::State& state) { stra s1 = TEXT_16; stra s2 = TEXT_16; for (auto _: state) { lstringa result; for (size_t c = 0; c < 32; c++) { result += s1 + s2; } #ifdef CHECK_RESULT if (result.length() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); benchmark::DoNotOptimize(s2); } } BENCHMARK(__)->Name("-- Append 2 string of 16 bytes 32 times, 1024 total length --")->Repetitions(1); BENCHMARK(AppendStream2String) ->Name("std::stringstream str; ... str << str_var1 << str_var2;"); BENCHMARK(AppendStdStr2String) ->Name("std::string str; ... str += str_var1 + str_var2;"); BENCHMARK(AppendLstring2String<8>) ->Name("lstringa<16> str; ... str += str_var1 + str_var2;"); BENCHMARK(AppendLstring2String<128>) ->Name("lstringa<128> str; ... str += str_var1 + str_var2;"); BENCHMARK(AppendLstring2String<512>) ->Name("lstringa<512> str; ... str += str_var1 + str_var2;"); BENCHMARK(AppendLstring2String<1024>) ->Name("lstringa<1024> str; ... str += str_var1 + str_var2;"); void AppendStreamStrNumStr(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { std::stringstream t; t << "test = " << k << " times"; std::string result = t.str(); #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } } void AppendStdStringStrNumStr(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { std::string result = "test = " + std::to_string(k) + " times"; #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } } void AppendSprintfStrNumStr(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { char buf[100]; std::sprintf(buf, "test = %u times", k); std::string result = buf; #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } } void AppendFormatStrNumStr(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { std::string result = std::format("test = {} times", k); #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } } template void AppendSimStrStrNumStrF(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { T result; result.format("test = {} times", k); #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } } template void AppendSimStrStrNumStr(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { T result = "test = "_ss + k + " times"; #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } } BENCHMARK(__)->Name("-- Append text, number, text --")->Repetitions(1); BENCHMARK(AppendStreamStrNumStr) ->Name("std::stringstream str; str << \"test = \" << k << \" times\";"); BENCHMARK(AppendStdStringStrNumStr) ->Name("std::string str = \"test = \" + std::to_string(k) + \" times\";"); BENCHMARK(AppendSprintfStrNumStr) ->Name("char buf[100]; sprintf(buf, \"test = %u times\", k); std::string str = buf;"); BENCHMARK(AppendFormatStrNumStr) ->Name("std::string str = std::format(\"test = {} times\", k);"); BENCHMARK(AppendSimStrStrNumStrF>) ->Name("lstringa<8> str; str.format(\"test = {} times\", k);"); BENCHMARK(AppendSimStrStrNumStrF>)->Name("lstringa<32> str; str.format(\"test = {} times\", k);"); BENCHMARK(AppendSimStrStrNumStr>) ->Name("lstringa<8> str = \"test = \" + k + \" times\";"); BENCHMARK(AppendSimStrStrNumStr>) ->Name("lstringa<32> str = \"test = \" + k + \" times\";"); BENCHMARK(AppendSimStrStrNumStr) ->Name("stringa str = \"test = \" + k + \" times\";"); const char NUMBER_LIST[] = "1-!- 2-!- 3-!- 4 -!- 5-!- 6 -!- 7-!- -8-!- 0xaF-!- 15-!- 010"; // 218 void SplitConvertIntStdString(benchmark::State& state) { std::string numbers = NUMBER_LIST; for (auto _: state) { int total = 0; for (size_t start = 0; start < numbers.length(); ) { int delim = numbers.find("-!-", start); if (delim == std::string::npos) { delim = numbers.size(); } std::string part = numbers.substr(start, delim - start); total += std::strtol(part.c_str(), nullptr, 0); start = delim + 3; } #ifdef CHECK_RESULT if (total != 218) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(total); benchmark::DoNotOptimize(numbers); } } void SplitConvertIntSimStr(benchmark::State& state) { stra numbers = NUMBER_LIST; for (auto _: state) { int total = 0; for (auto splitter = numbers.splitter("-!-"); !splitter.is_done();) { total += splitter.next().as_int(); } #ifdef CHECK_RESULT if (total != 218) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(total); benchmark::DoNotOptimize(numbers); } } void SplitConvertIntSplitf(benchmark::State& state) { stra numbers = NUMBER_LIST; for (auto _: state) { int total = 0; numbers.splitf("-!-", [&](ssa& part){total += part.as_int();}); #ifdef CHECK_RESULT if (total != 218) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(total); benchmark::DoNotOptimize(numbers); } } BENCHMARK(__)->Name("-- Split text and convert to int --")->Repetitions(1); BENCHMARK(SplitConvertIntStdString) ->Name("std::string::find + substr + std::strtol"); BENCHMARK(SplitConvertIntSimStr) ->Name("ssa::splitter + ssa::as_int"); BENCHMARK(SplitConvertIntSplitf) ->Name("ssa::splitf + functor"); void ReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" ; std::vector> repl = { {'&', "&"}, {'-', ""}, {'<', "<"}, {'>', ">"}, {'\'', "'"}, {'\"', """} }; auto repl_all = [](std::string& str, char s, std::string_view repl) { size_t start_pos = 0; while((start_pos = str.find(s, start_pos)) != std::string::npos) { str.replace(start_pos, 1, repl); start_pos += repl.length(); } }; for (auto _: state) { std::string result{source}; for (const auto& r : repl) { repl_all(result, r.first, r.second); } #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } void ReplaceSymbolsStdStringNaiveRight(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" ; std::vector> repl = { {'-', ""}, {'<', "<"}, {'>', ">"}, {'\'', "'"}, {'\"', """}, {'&', "&"}, }; for (auto _: state) { std::string result{source}; std::string pattern; for (const auto& r : repl) { pattern += r.first; } size_t start_pos = 0; while((start_pos = result.find_first_of(pattern, start_pos)) != std::string::npos) { size_t idx = pattern.find(result[start_pos]); result.replace(start_pos, 1, repl[idx].second); start_pos += repl[idx].second.length(); } #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } void ReplaceSymbolsStdString(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" ; const std::string_view repl_from = "-<>'\"&"; const std::string_view repl_to[] = {"", "<", ">", "'", """, "&"}; for (auto _: state) { std::string result; for (size_t start = 0; start < source.size();) { size_t idx = source.find_first_of(repl_from, start); if (idx == std::string::npos) { result += source.substr(start); break; } if (idx > start) { result += source.substr(start, idx - start); } size_t what = repl_from.find(source[idx]); result += repl_to[what]; start = idx + 1; } #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } template void ReplaceSymbolsDynPatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" ; std::vector> repl = { {'-', ""}, {'<', "<"}, {'>', ">"}, {'\'', "'"}, {'\"', """}, {'&', "&"}, }; for (auto _: state) { stringa result = expr_replace_symbols{source, repl}; #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } template void ReplaceSymbolsCons2PatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" ; for (auto _: state) { stringa result = e_repl_const_symbols(source, '-', "", '<', "<", '>', ">", '\'', "'", '\"', """, '&', "&" ); #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } BENCHMARK(__)->Name("-- Replace symbols in text ~400 symbols --")->Repetitions(1); BENCHMARK(ReplaceSymbolsStdStringNaiveWrong) ->Name("Naive (and wrong) replace symbols with std::string find + replace"); BENCHMARK(ReplaceSymbolsStdStringNaiveRight) ->Name("replace symbols with std::string find_first_of + replace"); BENCHMARK(ReplaceSymbolsStdString) ->Name("replace symbols with std::string_view find_first_of + copy"); BENCHMARK(ReplaceSymbolsDynPatternSimStr) ->Name("replace runtime symbols with string expressions and without remembering all search results"); BENCHMARK(ReplaceSymbolsDynPatternSimStr) ->Name("replace runtime symbols with simstr and memorization of all search results"); BENCHMARK(ReplaceSymbolsCons2PatternSimStr) ->Name("replace const symbols with string expressions and without remembering all search results"); BENCHMARK(ReplaceSymbolsCons2PatternSimStr) ->Name("replace const symbols with string expressions and memorization of all search results"); void ShortReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector> repl = { {'&', "&"}, {'-', ""}, {'<', "<"}, {'>', ">"}, {'\'', "'"}, {'\"', """} }; auto repl_all = [](std::string& str, char s, std::string_view repl) { size_t start_pos = 0; while((start_pos = str.find(s, start_pos)) != std::string::npos) { str.replace(start_pos, 1, repl); start_pos += repl.length(); } }; for (auto _: state) { std::string result{source}; for (const auto& r : repl) { repl_all(result, r.first, r.second); } #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } void ShortReplaceSymbolsStdStringNaiveRight(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector> repl = { {'-', ""}, {'<', "<"}, {'>', ">"}, {'\'', "'"}, {'\"', """}, {'&', "&"}, }; for (auto _: state) { std::string result{source}; std::string pattern; for (const auto& r : repl) { pattern += r.first; } size_t start_pos = 0; while((start_pos = result.find_first_of(pattern, start_pos)) != std::string::npos) { size_t idx = pattern.find(result[start_pos]); result.replace(start_pos, 1, repl[idx].second); start_pos += repl[idx].second.length(); } #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } void ShortReplaceSymbolsStdString(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; const std::string_view repl_from = "-<>'\"&"; const std::string_view repl_to[] = {"", "<", ">", "'", """, "&"}; for (auto _: state) { std::string result; for (size_t start = 0; start < source.size();) { size_t idx = source.find_first_of(repl_from, start); if (idx == std::string::npos) { result += source.substr(start); break; } if (idx > start) { result += source.substr(start, idx - start); } size_t what = repl_from.find_first_of(source[idx]); result += repl_to[what]; start = idx + 1; } #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } template void ShortReplaceSymbolsDynPatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector> repl = { {'-', ""}, {'<', "<"}, {'>', ">"}, {'\'', "'"}, {'\"', """}, {'&', "&"}, }; for (auto _: state) { stringa result = expr_replace_symbols{source, repl}; #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } template void ShortReplaceSymbolsCons2PatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; for (auto _: state) { stringa result = e_repl_const_symbols(source, '-', "", '<', "<", '>', ">", '\'', "'", '\"', """, '&', "&" ); #ifdef CHECK_RESULT if (result != "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } BENCHMARK(__)->Name("-- Replace symbols in text ~40 symbols --")->Repetitions(1); BENCHMARK(ShortReplaceSymbolsStdStringNaiveWrong) ->Name("Short Naive (and wrong) replace symbols with std::string find + replace"); BENCHMARK(ShortReplaceSymbolsStdStringNaiveRight) ->Name("Short replace symbols with std::string find_first_of + replace"); BENCHMARK(ShortReplaceSymbolsStdString) ->Name("Short replace symbols with std::string_view find_first_of + copy"); BENCHMARK(ShortReplaceSymbolsDynPatternSimStr) ->Name("Short replace runtime symbols with string expressions and without remembering all search results"); BENCHMARK(ShortReplaceSymbolsDynPatternSimStr) ->Name("Short replace runtime symbols with simstr and memorization of all search results"); BENCHMARK(ShortReplaceSymbolsCons2PatternSimStr) ->Name("Short replace const symbols with string expressions and without remembering all search results"); BENCHMARK(ShortReplaceSymbolsCons2PatternSimStr) ->Name("Short replace const symbols with string expressions and memorization of all search results"); template void ReplaceAllLongerStdString(benchmark::State& state) { std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a"; std::string_view pattern = "bb"; std::string_view repl = "----"; std::string big_source, big_sample; for (int i = 0; i < Long; i++) { big_source += source; big_sample += sample; } for (auto _: state) { std::string result{big_source}; size_t start_pos = 0; while((start_pos = result.find(pattern, start_pos)) != std::string::npos) { result.replace(start_pos, pattern.length(), repl); start_pos += repl.length(); } #ifdef CHECK_RESULT if (result != big_sample) { state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(pattern); benchmark::DoNotOptimize(repl); } } template void ReplaceAllLongerSimString(benchmark::State& state) { ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a"; lstringa<2048> big_source{Count, source}, big_sample{Count, sample}; for (auto _: state) { lstringa result = big_source; result.replace("bb", "----"); #ifdef CHECK_RESULT if (result.to_str() != big_sample) { std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n"; state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } template void ReplaceAllLongerSimStringExpr(benchmark::State& state) { ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a"; lstringa<2048> big_source{Count, source}, big_sample{Count, sample}; for (auto _: state) { stringa result = e_repl(big_source, "bb", "----"); #ifdef CHECK_RESULT if (result.to_str() != big_sample) { std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n"; state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } template void ReplaceAllEqualStdString(benchmark::State& state) { std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a"; std::string_view pattern = "bb"; std::string_view repl = "--"; std::string big_source, big_sample; for (int i = 0; i < Long; i++) { big_source += source; big_sample += sample; } for (auto _: state) { std::string result{big_source}; size_t start_pos = 0; while((start_pos = result.find(pattern, start_pos)) != std::string::npos) { result.replace(start_pos, pattern.length(), repl); start_pos += repl.length(); } #ifdef CHECK_RESULT if (result != big_sample) { state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(pattern); benchmark::DoNotOptimize(repl); } } template void ReplaceAllEqualSimString(benchmark::State& state) { ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a"; lstringa<2048> big_source{Long, source}, big_sample{Long, sample}; for (auto _: state) { lstringa result = big_source; result.replace("bb", "--"); #ifdef CHECK_RESULT if (result.to_str() != big_sample) { std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n"; state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } } template void ReplaceAllEqualSimStringExpr(benchmark::State& state) { ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a"; ssa pattern = "bb"; ssa repl = "--"; lstringa<2048> big_source{Count, source}, big_sample{Count, sample}; for (auto _: state) { stringa result = e_repl(big_source.to_str(), "bb", "--"); #ifdef CHECK_RESULT if (result.to_str() != big_sample) { std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n"; state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(pattern); benchmark::DoNotOptimize(repl); } } BENCHMARK(__)->Name("----- Replace All Str To Longer Size ---------")->Repetitions(1); BENCHMARK(ReplaceAllLongerStdString<1>) ->Name("replace bb to ---- in std::string|64"); BENCHMARK(ReplaceAllLongerStdString<4>) ->Name("replace bb to ---- in std::string|256"); BENCHMARK(ReplaceAllLongerStdString<8>) ->Name("replace bb to ---- in std::string|512"); BENCHMARK(ReplaceAllLongerStdString<16>) ->Name("replace bb to ---- in std::string|1024"); BENCHMARK(ReplaceAllLongerStdString<32>) ->Name("replace bb to ---- in std::string|2048"); BENCHMARK(ReplaceAllLongerSimString<8, 1>) ->Name("replace bb to ---- in lstringa<8>|64"); BENCHMARK(ReplaceAllLongerSimString<8, 4>) ->Name("replace bb to ---- in lstringa<8>|256"); BENCHMARK(ReplaceAllLongerSimString<8, 8>) ->Name("replace bb to ---- in lstringa<8>|512"); BENCHMARK(ReplaceAllLongerSimString<8, 16>) ->Name("replace bb to ---- in lstringa<8>|1024"); BENCHMARK(ReplaceAllLongerSimString<8, 32>) ->Name("replace bb to ---- in lstringa<8>|2048"); BENCHMARK(ReplaceAllLongerSimStringExpr<1>) ->Name("replace bb to ---- by init stringa|64"); BENCHMARK(ReplaceAllLongerSimStringExpr<4>) ->Name("replace bb to ---- by init stringa|256"); BENCHMARK(ReplaceAllLongerSimStringExpr<8>) ->Name("replace bb to ---- by init stringa|512"); BENCHMARK(ReplaceAllLongerSimStringExpr<16>) ->Name("replace bb to ---- by init stringa|1024"); BENCHMARK(ReplaceAllLongerSimStringExpr<32>) ->Name("replace bb to ---- by init stringa|2048"); BENCHMARK(__)->Name("----- Replace All Str To Same Size ---------")->Repetitions(1); BENCHMARK(ReplaceAllEqualStdString<1>) ->Name("replace bb to -- in std::string|64"); BENCHMARK(ReplaceAllEqualStdString<4>) ->Name("replace bb to -- in std::string|256"); BENCHMARK(ReplaceAllEqualStdString<8>) ->Name("replace bb to -- in std::string|512"); BENCHMARK(ReplaceAllEqualStdString<16>) ->Name("replace bb to -- in std::string|1024"); BENCHMARK(ReplaceAllEqualStdString<32>) ->Name("replace bb to -- in std::string|2048"); BENCHMARK(ReplaceAllEqualSimString<8, 1>) ->Name("replace bb to -- in lstringa<8>|64"); BENCHMARK(ReplaceAllEqualSimString<8, 4>) ->Name("replace bb to -- in lstringa<8>|256"); BENCHMARK(ReplaceAllEqualSimString<8, 8>) ->Name("replace bb to -- in lstringa<8>|512"); BENCHMARK(ReplaceAllEqualSimString<8, 16>) ->Name("replace bb to -- in lstringa<8>|1024"); BENCHMARK(ReplaceAllEqualSimString<8, 32>) ->Name("replace bb to -- in lstringa<8>|2048"); BENCHMARK(ReplaceAllEqualSimStringExpr<1>) ->Name("replace bb to -- by init stringa|64"); BENCHMARK(ReplaceAllEqualSimStringExpr<4>) ->Name("replace bb to -- by init stringa|256"); BENCHMARK(ReplaceAllEqualSimStringExpr<8>) ->Name("replace bb to -- by init stringa|512"); BENCHMARK(ReplaceAllEqualSimStringExpr<16>) ->Name("replace bb to -- by init stringa|1024"); BENCHMARK(ReplaceAllEqualSimStringExpr<32>) ->Name("replace bb to -- by init stringa|2048"); std::vector prepareTestStrings(size_t length, size_t delta, size_t count) { std::vector result; result.reserve(count); struct expr_rand { using symb_type = u8s; size_t len; size_t length() const noexcept { return len; } char* place(char* ptr) const { for (size_t idx = len; idx > 0; idx--) { *ptr++ = char(' ' + std::rand() % 200); } return ptr; } }; for (size_t idx = 0; idx < count; idx++) { result.emplace_back(expr_rand{length + std::rand() % delta}); } return result; } std::vector bs_sim = prepareTestStrings(30, 20, 10'000); std::vector prepareTestStdStrings() { std::vector result; result.reserve(bs_sim.size()); for (const auto& s: bs_sim) { result.emplace_back(s.to_string()); } return result; } std::vector bs_std = prepareTestStdStrings(); void HashMapSimStr(benchmark::State& state) { for (auto _: state) { hashStrMapA store; for (size_t idx = 0; idx < bs_sim.size(); idx++) { store.try_emplace(bs_sim[idx], idx); } #ifdef CHECK_RESULT if (store.size() != bs_sim.size()) { state.SkipWithError("bad inserts"); } #endif for (size_t idx = 0; idx < bs_sim.size(); idx++) { auto find = store.find(bs_sim[idx]); size_t res = find->second; #ifdef CHECK_RESULT if (res != idx) { state.SkipWithError("bad find"); } #endif benchmark::DoNotOptimize(res); } } } void HashMapStdStr(benchmark::State& state) { for (auto _: state) { std::unordered_map store; for (size_t idx = 0; idx < bs_std.size(); idx++) { store.try_emplace(bs_std[idx], idx); } #ifdef CHECK_RESULT if (store.size() != bs_std.size()) { state.SkipWithError("bad inserts"); } #endif for (size_t idx = 0; idx < bs_std.size(); idx++) { auto find = store.find(bs_std[idx]); size_t res = find->second; #ifdef CHECK_RESULT if (res != idx) { state.SkipWithError("bad find"); } #endif benchmark::DoNotOptimize(res); } } } void HashMapSimSsa(benchmark::State& state) { for (auto _: state) { hashStrMapA store; for (size_t idx = 0; idx < bs_sim.size(); idx++) { store.emplace(bs_sim[idx], idx); } #ifdef CHECK_RESULT if (store.size() != bs_sim.size()) { state.SkipWithError("bad inserts"); } #endif for (size_t idx = 0; idx < bs_sim.size(); idx++) { ssa key = bs_sim[idx]; auto find = store.find(key); size_t res = find->second; #ifdef CHECK_RESULT if (res != idx) { state.SkipWithError("bad find"); } #endif benchmark::DoNotOptimize(res); } } } void HashMapStdStrView(benchmark::State& state) { for (auto _: state) { std::unordered_map store; for (size_t idx = 0; idx < bs_std.size(); idx++) { store.emplace(bs_std[idx], idx); } #ifdef CHECK_RESULT if (store.size() != bs_std.size()) { state.SkipWithError("bad inserts"); } #endif for (size_t idx = 0; idx < bs_std.size(); idx++) { std::string_view key = bs_std[idx]; auto find = store.find(std::string{key}); size_t res = find->second; #ifdef CHECK_RESULT if (res != idx) { state.SkipWithError("bad find"); } #endif benchmark::DoNotOptimize(res); } } } BENCHMARK(__)->Name("----- Hash Map insert and find ---------")->Repetitions(1); BENCHMARK(HashMapSimStr)->Name("hashStrMapA emplace & find stringa;"); BENCHMARK(HashMapStdStr)->Name("std::unordered_map emplace & find std::string;"); BENCHMARK(HashMapSimSsa)->Name("hashStrMapA emplace & find ssa;"); BENCHMARK(HashMapStdStrView)->Name("std::unordered_map emplace & find std::string_view;"); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Набор тестов, имитирующий довольно типовой сценарий, похож на то, что встречалось в работе // По имеющимся данным о неких функциях и их параметрах - построить полное имя функции ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// enum class Types { int2, int4, int8, bytea, text, char_, varchar, boolean, last, }; const ssa type_names[] = { "int2", "int4", "int8", "bytea", "text", "char", "varchar", "boolean" }; const std::string_view type_names_sv[] = { "int2", "int4", "int8", "bytea", "text", "char", "varchar", "boolean" }; constexpr bool is_power_of_two_or_zero(uint32_t value) { return !(value & (value - 1)); } struct type_set { uint32_t value; void to_simstr(mutable_str auto& str) const { if (!value) { str += "{?}"; } else if (value == 0xFFFFFFFF) { str += "any"; } else { if (!is_power_of_two_or_zero(value)) { str += "{"; } bool add_comma = false; for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) { if (value & (1 << idx)) { str += e_if(add_comma, ", ") + type_names[idx]; add_comma = true; } } if (!is_power_of_two_or_zero(value)) { str += "}"; } } } auto get_simstr() const { lstringa<128> str; if (!value) { str = "{?}"; } else if (value == 0xFFFFFFFF) { str = "any"; } else { if (!is_power_of_two_or_zero(value)) { str = "{"; } bool add_comma = false; for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) { if (value & (1 << idx)) { str += e_if(add_comma, ", ") + type_names[idx]; add_comma = true; } } if (!is_power_of_two_or_zero(value)) { str += "}"; } } return str; } void to_stdstr(std::string& str) const { if (!value) { str += "{?}"; } else if (value == 0xFFFFFFFF) { str += "any"; } else { if (!is_power_of_two_or_zero(value)) { str += "{"; } bool add_comma = false; for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) { if (value & (1 << idx)) { if (add_comma) { str += ", "; } str += type_names_sv[idx]; add_comma = true; } } if (!is_power_of_two_or_zero(value)) { str += "}"; } } } void to_stream(std::ostream& str) const { if (!value) { str << "{?}"; } else if (value == 0xFFFFFFFF) { str << "any"; } else { if (!is_power_of_two_or_zero(value)) { str << "{"; } bool add_comma = false; for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) { if (value & (1 << idx)) { if (add_comma) { str << ", "; } str << type_names_sv[idx]; add_comma = true; } } if (!is_power_of_two_or_zero(value)) { str << "}"; } } } }; struct param { type_set allowed_types; bool optional; }; struct function { stringa name; std::string std_name; std::vector params; Types ret_type; bool has_ret_type_resolver; bool unlim_params; // Построение полного имени с помощью simstr строковых объектов и выражений stringa build_full_name() const { lstringa<512> str = e_choice(has_ret_type_resolver, "any", type_names[(unsigned)ret_type]) + " " + name + "("; bool add_comma = false; for (const auto& param : params) { str += e_if(add_comma, ", ") + e_if(param.optional, "["); param.allowed_types.to_simstr(str); if (param.optional) { str += "]"; } add_comma = true; } return str + e_if(unlim_params, e_if(add_comma, ", ") + "...") + ")"; } stringa build_full_name1() const { lstringa<512> str = e_choice(has_ret_type_resolver, "any", type_names[(unsigned)ret_type]) + " " + name + "("; bool add_comma = false; for (const auto& param : params) { str += e_if(add_comma, ", ") + e_if(param.optional, "[") + param.allowed_types.get_simstr() + e_if(param.optional, "]"); add_comma = true; } return str + e_if(unlim_params, e_if(add_comma, ", ") + "...") + ")"; } // Построение полного имени с помощью std::string std::string build_full_name_std() const { std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]}; str += " "; str += std_name; str += "("; bool add_comma = false; for (const auto& param : params) { if (add_comma) { str += ", "; } if (param.optional) { str += "["; } param.allowed_types.to_stdstr(str); if (param.optional) { str += "]"; } add_comma = true; } if (unlim_params) { if (add_comma) { str += ", "; } str += "..."; } str += ")"; //std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n"; return str; } // Построение полного имени с помощью std::string std::string build_full_name_std1() const { std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]}; str += " " + std_name + "("; bool add_comma = false; for (const auto& param : params) { if (add_comma) { str += ", "; } if (param.optional) { str += "["; } param.allowed_types.to_stdstr(str); if (param.optional) { str += "]"; } add_comma = true; } if (unlim_params) { if (add_comma) { str += ", "; } str += "..."; } str += ")"; //std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n"; return str; } // Построение полного имени с помощью std::ostringstream std::string build_full_name_stream() const { std::ostringstream str; if (has_ret_type_resolver) { str << "any"; } else { str << type_names_sv[(unsigned)ret_type]; } str << " " << std_name << "("; bool add_comma = false; for (const auto& param : params) { if (add_comma) { str << ", "; } if (param.optional) { str << "["; } param.allowed_types.to_stream(str); if (param.optional) { str << "]"; } add_comma = true; } if (unlim_params) { if (add_comma) { str << ", "; } str << "..."; } str << ")"; return str.str(); } }; // Тестовые варианты функций const struct { function f; std::string_view check; } functions[] = { {{"func1", "func1", {}, Types::boolean, true, true}, "any func1(...)"}, {{"function2", "function2", {{4, false}, {12, true}}, Types::int2, false, false}, "int2 function2(int8, [{int8, bytea}])"}, {{"func3", "func3", {{16, false}, {7, false}, {32, true}}, Types::char_, false, true}, "char func3(text, {int2, int4, int8}, [char], ...)"}, {{"function4", "function4", {{10, false}, {64, false}, {31, true}}, Types::char_, true, false}, "any function4({int4, bytea}, varchar, [{int2, int4, int8, bytea, text}])"}, {{"f5", "f5", {{10, false}, {64, false}, {0xFFFFFFFF, false}}, Types::text, false, true}, "text f5({int4, bytea}, varchar, any, ...)"}, }; // Замеры скорости выполнения разных вариантов //> stringa build_full_name() const { void BuildFuncNameSimStr(benchmark::State& state) { for (auto _: state) { for (const auto& f : functions) { stringa res = f.f.build_full_name(); benchmark::DoNotOptimize(res); #ifdef CHECK_RESULT if (res != ssa{f.check}) { std::cout << res << "\n"; state.SkipWithError("not equal"); break; } #endif } } } //> stringa build_full_name1() const { void BuildFuncNameSimStr1(benchmark::State& state) { for (auto _: state) { for (const auto& f : functions) { stringa res = f.f.build_full_name1(); benchmark::DoNotOptimize(res); #ifdef CHECK_RESULT if (res != ssa{f.check}) { std::cout << res << "\n"; state.SkipWithError("not equal"); break; } #endif } } } //> std::string build_full_name_std() const { void BuildFuncNameStdStr(benchmark::State& state) { for (auto _: state) { for (const auto& f : functions) { std::string res = f.f.build_full_name_std(); benchmark::DoNotOptimize(res); #ifdef CHECK_RESULT if (res != f.check) { std::cout << res << "\n"; state.SkipWithError("not equal"); break; } #endif } } } //> std::string build_full_name_std1() const { void BuildFuncNameStdStr1(benchmark::State& state) { for (auto _: state) { for (const auto& f : functions) { std::string res = f.f.build_full_name_std1(); benchmark::DoNotOptimize(res); #ifdef CHECK_RESULT if (res != f.check) { std::cout << res << "\n"; state.SkipWithError("not equal"); break; } #endif } } } //> std::string build_full_name_stream() const { void BuildFuncNameStream(benchmark::State& state) { for (auto _: state) { for (const auto& f : functions) { std::string res = f.f.build_full_name_stream(); benchmark::DoNotOptimize(res); #ifdef CHECK_RESULT if (res != f.check) { std::cout << res << "\n"; state.SkipWithError("not equal"); break; } #endif } } } BENCHMARK(__)->Name("----- Build Full Func Name ---------")->Repetitions(1); BENCHMARK(BuildFuncNameStdStr) ->Name("Build func full name std::string;"); BENCHMARK(BuildFuncNameStdStr1) ->Name("Build func full name std::string 1;"); BENCHMARK(BuildFuncNameStream) ->Name("Build func full name std::stream;"); BENCHMARK(BuildFuncNameSimStr) ->Name("Build func full name stringa;"); BENCHMARK(BuildFuncNameSimStr1) ->Name("Build func full name stringa 1;"); void UpperCaseStd(benchmark::State& state) { static const auto& loc = std::locale("en_US.utf8"); for (auto _: state) { std::wstring test = L"TestПриветTest"; benchmark::DoNotOptimize(test); std::transform(test.begin(), test.end(), test.begin(), [](wchar_t s) { return std::toupper(s, loc); }); benchmark::DoNotOptimize(test); #ifdef CHECK_RESULT if (test != L"TESTПРИВЕТTEST") { state.SkipWithError("Bad upper case"); } #endif } } void UpperCaseSim(benchmark::State& state) { for (auto _: state) { lstringw<15> test = L"TestПриветTest"; benchmark::DoNotOptimize(test); test.upper(); benchmark::DoNotOptimize(test); #ifdef CHECK_RESULT if (test != L"TESTПРИВЕТTEST") { state.SkipWithError("Bad upper case"); } #endif } } BENCHMARK(__)->Name("----- Make Upper ---------")->Repetitions(1); BENCHMARK(UpperCaseStd)->Name("To upper case std::wstring"); BENCHMARK(UpperCaseSim)->Name("To upper case lstringw<15>"); int main(int argc, char** argv) { std::cout << "Benchmarks of simstr, version " SIMSTR_VERSION << "\n" << "Sources: https://github.com/orefkov/simstr\n" << "Results: https://orefkov.github.io/simstr/results.html\n" << "Compiler " << CXX_COMPILER_ID << " " << CXX_COMPILER_VERSION #ifdef _LIBCPP_VERSION << ", use libc++" #endif << std::endl; #ifdef EMSCRIPTEN EM_ASM({ console.log(navigator.userAgent); }); if (argc == 2 && stra{argv[1]} == "-sync") { do_sync = true; argc = 1; } #endif char arg1[] = "--benchmark_repetitions=4", arg2[] = "--benchmark_report_aggregates_only=true"; char* my_params[] = {argv[0], arg1, arg2}; if (argc < 2) { argc = 3; argv = my_params; } ::benchmark::Initialize(&argc, argv); if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; ::benchmark::RunSpecifiedBenchmarks(); ::benchmark::Shutdown(); #ifdef EMSCRIPTEN std::cout << "Done!\n"; EM_ASM({ on_done(); }); #endif return 0; }