simstr benchmarks results

simstr is a powerful and convenient library for productive work with strings in C++.
All times in ns. Source for benchmarks
Group tests by platforms in charts:

Test configurations:

# Concatenate string + Number + "Literal"

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat std::string and number by std to std::stringvoid 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); } } }2112022723191035
Concat std::string and number by StrExpr to std::stringvoid 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); } } }102101154207505
Concat stringa and number by StrExpr to simstr::stringavoid 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); } } } >> stringa в отличии от std::string, вмещает в SSO 23 символа вместо 15, поэтому в конце теста std::string приходится аллоцировать память, а в stringa весь тест входит в SSO. Unlike std::string, stringa holds 23 characters in SSO instead of 15, so at the end of the std::string test, memory has to be allocated, while in stringa , the entire test is included in SSO.63.172.168.4106224
Concat stringa and number by e_concat to simstr::stringavoid 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); } } }69.575.973.2116224

# Concatenate string + Hex Number + "Literal"

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat std::string and format hex number and literal to std::stringvoid 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); } } }68065172410202034
std::format std::string and hex number by literal to std::stringvoid 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); } } }865922150518352519
Concat std::string and std::to_chars and string to std::stringvoid 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); } } }198176194248617
Concat std::string and hex number and literal by StrExpr to std::stringvoid 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); } } }13112579.4116473
Concat stringa and hex number and literal by StrExpr to simstr::stringavoid 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); } } }11512073.6101184
Concat stringa and hex number and literal by e_concat to simstr::stringavoid 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); } } }12112480.7106190
Subst stringa and hex number by e_subst literal to simstr::stringavoid 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); } } }183167148172333
Subst stringa and hex number by e_vsubst stra to simstr::stringavoid 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); } } }308296286355833

# format/vformat and subst/vsubst octal number to 32 symbols result

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
"abcdefghihklmopqr "_ss + i / 0x8a010_fmt + " end"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); } } }276339669681380
e_subst("abcdefghihklmopqr {} end", i / 0x8a010_fmt)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); } } }354320745787580
e_vsubst(pattern, i / 0x8a010_fmt)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); } } }618582103611281424
fmt::format(FMT_COMPILE("abcdefghihklmopqr {:#010o} end"), i)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); } } }882727140515762133
fmt::format("abcdefghihklmopqr {:#010o} end", i)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); } } }819786133114322874
std::format("abcdefghihklmopqr {:#010o} end", i)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); } } }9521222154019042951
std::vformat(pattern, std::make_format_args(i))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); } } }9571143160819323034
strm << "abcdefghihklmopqr 0" << std::oct << std::setw(9) << std::setfill('0') << i << " end"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); } } }20192092643576518267

# Concatenate string + "Literal"

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat std::string by std to std::stringvoid 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); } } }45.149.839.660.5104
Concat std::string by StrExpr to std::stringvoid 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); } } }34.830.341.179.0119
Concat stringa by StrExpr to stringavoid 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); } } }28.326.628.551.195.1

# Find three concatenated string in string_view

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Find concat three std::stringsize_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"); }111192200244217
Find concat three strexprsize_t find_pos_exp(ssa src, ssa name) { return src.find(std::string{"\n- " + name + " -\n"}); }49.241.1116121107
Find concat three simstrsize_t find_pos_sim(ssa src, ssa name) { return src.find(lstringa<200>{"\n- " + name + " -\n"}); } >> Если результат конкатенации меньше 207 символов, он собирается в буфере на стеке, без аллокации и деалокации. If the concatenation result is less than 207 characters, it is collected in a stack-based buffer, without allocation or deallocation.19.119.528.229.061.5

# Build Type Name

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
BuildTypeNameStr 0/0std::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; }7.0210.17.9817.321.3
BuildTypeNameExp 0/0std::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; }7.316.627.4413.123.4
BuildTypeNameSim 0/0stringa buildTypeNameSim(ssa type_name, size_t prec, size_t scale) { if (prec) { return type_name + "(" + prec + e_if(scale, ","_ss + scale) + ")"; } return type_name; }4.804.897.7415.219.2
BuildTypeNameStr 10/10std::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; }54.882.358.781.8374
BuildTypeNameExp 10/10std::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; }30.225.332.238.8109
BuildTypeNameSim 10/10stringa buildTypeNameSim(ssa type_name, size_t prec, size_t scale) { if (prec) { return type_name + "(" + prec + e_if(scale, ","_ss + scale) + ")"; } return type_name; }22.521.625.336.463.6

# Replace string by copy

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat with replace strstd::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) + ">"; }207225309351495
Concat with replace expstd::string make_str_exp(std::string_view from, std::string_view pattern, std::string_view repl) { return "<" + e_repl(from, pattern, repl) + ">"; } >> В simstr строковое выражение для замены подстрок есть "из коробки". simstr has a string expression for replacing substrings out of the box.138135214222239

# Create Empty Str

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } } >> Пустые строки, ничего необычного. Empty lines, nothing unusual.1.101.131.092.862.14
std::string_view e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }0.3720.7390.3641.810.730
ssa e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }0.3630.1820.3601.500.364
stringa e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }0.7350.7360.7332.232.17
lstringa<20> e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }1.101.111.092.572.18
lstringa<40> e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }1.101.101.102.582.26

# Create Str from short literal (9 symbols)

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "Test text";template<typename T> void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } } >> Короткий литерал помещается во внутренний буфер std::string, время тратится только на копирование 10 байтов. The short literal is placed in the internal std::string buffer; time is spent only copying 10 bytes.1.841.821.832.562.43
std::string_view e = "Test text";template<typename T> void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } } >> И string_view, и ssa - по сути одно и то же: указатель на текст и его длина. Both string_view and ssa are essentially the same thing: a pointer to text and its length.0.7390.7420.7531.811.10
ssa e = "Test text";template<typename T> void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } }0.3630.7360.3601.820.732
stringa e = "Test text";template<typename T> void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } } >> stringa при инициализации константным литералом так же сохраняет только указатель на текст и его длину. When initialized with a constant literal, stringa also stores only a pointer to the text and its length.1.111.101.102.842.19
lstringa<20> e = "Test text";template<typename T> void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } } >> Внутреннего буфера хватает для размещения символов, время уходит только на копирование байтов. The internal buffer is sufficient to accommodate characters; time is spent only on copying bytes.1.871.851.822.562.57
lstringa<40> e = "Test text";template<typename T> void CreateShortLiteral(benchmark::State& state) { for (auto _: state) { T empty_string = TEST_TEXT; benchmark::DoNotOptimize(empty_string); } }1.901.831.822.542.62

# Create Str from long literal (30 symbols)

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } >> Вот тут уже литерал не помещается во внутренний буфер, возникает аллокация и копирование 30-и байтов. Но как же отстает аллокация под Windows от Linux'а, 20 vs 70 ns... Here, the literal doesn't fit into the internal buffer, and 30 bytes are allocated and copied. But how much slower is allocation under Windows than under Linux, 20 ns vs. 70 ns...19.919.573.479.422.4
std::string_view e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } >> string_view и ssa по прежнему ничего не делают, кроме запоминания указателя на текст и его размера. string_view and ssa still do nothing except remember the pointer to the text and its size.0.7290.7300.7291.821.18
ssa e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } }0.3660.7390.3641.790.778
stringa e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } >> stringa на константных литералах не отстает! stringa doesn't lag behind on constant literals!1.121.131.082.552.22
lstringa<20> e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } >> lstringa<20> может вместить в себя до 23 символов, Очевидно, что для 30-и символов уже нужна аллокация. Obviously, 30 characters already require allocation.20.319.974.876.324.8
lstringa<40> e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } >> А в lstringa<40> влезает до 47 символов, так что просто копируется 30 байтов. And lstringa<40> can hold up to 47 characters, so 30 bytes are simply copied.2.541.872.563.253.16

# Create copy of Str with 9 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Строка в пределах SSO, так что просто копирует байты. The string is within the SSO, so it just copies the bytes.4.785.761.825.083.86
std::string_view e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }0.3630.4430.3633.791.14
ssa e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> ssa и string_view не владеют строкой, копируется только информация о строке. ssa and string_view don't own the string; only the string information is copied.0.3680.3950.3633.761.19
stringa e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Копирование stringa происходит быстро, особенно если она инициализирована литералом. Copying a stringa is fast, especially if it is initialized with a literal.1.081.351.284.032.53
lstringa<20> e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> В обоих случаях хватает внутреннего буфера. In both cases, the internal buffer is sufficient.1.471.251.464.274.78
lstringa<40> e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Только копируются байты. Only bytes are copied.1.471.251.464.544.80

# Create copy of Str with 30 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } } >> Копирования длинной строки вызывает аллокацию, SSO уже не хватает. И снова как же отстаёт аллокация под Windows... Copying a long string causes allocations, SSO is no longer sufficient. And again, how allocation lags under Windows...18.422.874.777.146.7
std::string_view e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } }0.7380.7860.7321.821.09
ssa e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } }0.3670.8200.3681.850.737
stringa e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } } >> А вот у stringa копирование литерала не зависит от его длины, сравни с предыдущим бенчмарком. But with stringa, literal copying doesn't depend on its length, compare with the previous benchmark.1.101.111.802.972.16
lstringa<20> e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } } >> Не влезает, аллокация. Doesn't fit, allocation.19.420.673.777.321.9
lstringa<40> e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } } >> Уложили во внутренний буфер. Placed in the internal buffer.4.474.704.797.4015.0

# Find 9 symbols text in end of 99 symbols text

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string::find;template<typename T> 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); } } >> Здесь "победила дружба", у всех типов по колонке примерно одинаково. Однако, Windows и Linux явно в разных весовых категориях. Here, "friendship wins," with all types scoring roughly equally. However, Windows and Linux are clearly in different weight classes.6.796.9238.541.343.3
std::string_view::find;template<typename T> 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); } }7.096.7537.739.245.3
ssa::find;template<typename T> 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); } }6.796.5217.520.443.4
stringa::find;template<typename T> 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); } }7.436.6217.929.343.5
lstringa<20>::find;template<typename T> 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); } }6.266.3218.220.738.7
lstringa<40>::find;template<typename T> 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); } }6.266.3317.522.140.2

# Copy not literal Str with N symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }4.746.031.834.4249.3
std::string copy{str_with_len_N};/16template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Явно виден скачок, где заканчивается SSO и начинается аллокация. Обратите внимание, что WASM - 32-битный, и там размер SSO у std::string меньше, 10 символов + 0. The jump where SSO ends and allocation begins is clearly visible. Note that WASM is 32-bit, and the size of the SSO for std::string is smaller, as far as I remember: 11 characters + 0.22.825.977.782.248.3
std::string copy{str_with_len_N};/23template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Дальше просто добавляется время на копирование байтов. Then the time for copying bytes is simply added.22.625.076.483.349.1
std::string copy{str_with_len_N};/24template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }22.625.377.980.748.1
std::string copy{str_with_len_N};/32template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }22.624.281.784.351.5
std::string copy{str_with_len_N};/64template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }21.924.184.688.853.0
std::string copy{str_with_len_N};/128template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }24.225.685.590.452.6
std::string copy{str_with_len_N};/256template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }24.425.884.389.859.2
std::string copy{str_with_len_N};/512template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }28.730.488.093.059.5
std::string copy{str_with_len_N};/1024template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }44.747.010410968.5
std::string copy{str_with_len_N};/2048template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }12213113113190.5
std::string copy{str_with_len_N};/4096template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Чем длиннее строка, тем дольше создаётся копия. The longer the string, the longer it takes to create a copy.158159178181133
stringa copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Здесь stringa инициализируется не литералом, а значит, должна сама хранить символы. Here, stringa is not initialized with a literal, meaning it must store characters itself.1.111.301.274.042.36
stringa copy{str_with_len_N};/16template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Под WASM SSO у stringa составляет 15 символов. Кроме того, собиралось без поддержки потоков, поэтому атомарный инкремент заменён на обычный, судя по времени. Under WASM, stringa has a 15-character SSO. Furthermore, it was built without thread support, so the atomic increment was replaced with a regular one, judging by the time.1.101.301.284.084.79
stringa copy{str_with_len_N};/23template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> SSO в stringa до 23 символов, и даже 23 копируются быстрее, чем 15 в std::string. SSO in stringa is up to 23 characters, and even 23 copies faster than 15 in std::string.1.091.301.283.964.82
stringa copy{str_with_len_N};/24template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Всё, не влезаем в SSO, а значит, используем shared буфер. Добавляется время на атомарный инкремент счётчика. That's it, we're not using SSO, so we're using a shared buffer. Time is added for the atomic counter increment.16.116.115.818.24.79
stringa copy{str_with_len_N};/32template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }15.916.015.818.24.81
stringa copy{str_with_len_N};/64template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.016.015.818.34.83
stringa copy{str_with_len_N};/128template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.116.015.818.44.77
stringa copy{str_with_len_N};/256template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.216.215.818.34.81
stringa copy{str_with_len_N};/512template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.116.215.818.44.77
stringa copy{str_with_len_N};/1024template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }15.916.115.919.14.83
stringa copy{str_with_len_N};/2048template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.216.215.818.34.82
stringa copy{str_with_len_N};/4096template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> И как видно, кроме инкремента нет накладных расходов, время копирования не зависит от длины строки. And as you can see, there are no overhead costs other than the increment; copying time does not depend on the string length.16.016.315.818.44.77
lstringa<16> copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> lstringa<16> использует SSO до 23 символов. А в WASM 32-битная архитектура, SSO до 19 символов. lstringa<16> uses SSO up to 23 characters. WASM has a 32-bit architecture, so SSO is up to 19 characters.1.461.111.504.914.05
lstringa<16> copy{str_with_len_N};/16template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }5.215.125.069.0114.5
lstringa<16> copy{str_with_len_N};/23template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }5.095.055.099.1535.6
lstringa<16> copy{str_with_len_N};/24template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> И после начинает вести себя при копировании, как std::string. And then it starts to behave like std::string when copied.22.924.475.979.335.4
lstringa<16> copy{str_with_len_N};/32template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }22.624.778.181.438.4
lstringa<16> copy{str_with_len_N};/64template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }24.126.380.489.538.3
lstringa<16> copy{str_with_len_N};/128template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }24.726.582.086.739.6
lstringa<16> copy{str_with_len_N};/256template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }25.928.483.486.345.5
lstringa<16> copy{str_with_len_N};/512template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }29.231.184.490.044.0
lstringa<16> copy{str_with_len_N};/1024template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }10210994.499.454.9
lstringa<16> copy{str_with_len_N};/2048template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }11512012712876.6
lstringa<16> copy{str_with_len_N};/4096template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }127128184189122
lstringa<512> copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }1.511.141.474.074.44
lstringa<512> copy{str_with_len_N};/16template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }5.174.925.109.1715.0
lstringa<512> copy{str_with_len_N};/23template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }5.165.055.259.3315.0
lstringa<512> copy{str_with_len_N};/24template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }4.894.585.159.1115.1
lstringa<512> copy{str_with_len_N};/32template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }4.784.738.2512.117.8
lstringa<512> copy{str_with_len_N};/64template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }6.276.238.1312.318.4
lstringa<512> copy{str_with_len_N};/128template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }6.658.448.4212.518.5
lstringa<512> copy{str_with_len_N};/256template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }8.269.0310.113.420.5
lstringa<512> copy{str_with_len_N};/512template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Даже 512 символов копируются быстрее, чем одна аллокация или атомарный инкремент. Even 512 characters are copied faster than a single allocation or atomic increment.10.512.811.115.323.2
lstringa<512> copy{str_with_len_N};/1024template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> А дальше уже как у всех. And then it's like everyone else.10511096.699.855.2
lstringa<512> copy{str_with_len_N};/2048template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }11611612913676.0
lstringa<512> copy{str_with_len_N};/4096template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }128130184191122

# Convert to int '1234567'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = "123456789"; int res = std::strtol(s.c_str(), 0, 10);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); } } >> В simstr для конвертации в число достаточно куска строки, нет нужды в null терминированности. Ближайший аналог такого поведения "std::from_chars", но он к сожалению очень ограничен по возможностям. Здесь я попытался произвести тесты, близкие по логике к работе std::from_chars In simstr, a string fragment is sufficient for conversion to a number; there's no need for null termination. The closest analog to this behavior is "std::from_chars," but unfortunately, it is very limited in its capabilities. Here, I attempted to run tests that are similar in logic to std::from_chars.26.426.431.031.793.0
std::string_view s = "123456789"; std::from_chars(s.data(), s.data() + s.size(), res, 10);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); } } >> from_chars требует точного указания основания счисления, не допускает знаков плюс, пробелов, префиксов 0x и т.п. from_chars requires an exact radix specification and does not allow plus signs, spaces, 0x prefixes, etc.14.911.413.313.626.7
stringa s = "123456789"; int res = s.to_int<int, true, 10, false>template<typename T> void ToIntSimStr10(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int, true, 10, false, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } } >> Здесь для to_int заданы такие же ограничения - проверять переполнение, десятичная система, без лидирующих пробелов и знака плюс Here, to_int has the same restrictions: check for overflow, decimal system, no leading spaces, and no plus sign.12.68.3613.915.119.1
ssa s = "123456789"; int res = s.to_int<int, true, 10, false>template<typename T> void ToIntSimStr10(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int, true, 10, false, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }12.37.8312.914.818.6
lstringa<20> s = "123456789"; int res = s.to_int<int, true, 10, false>template<typename T> void ToIntSimStr10(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int, true, 10, false, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }12.28.3813.315.018.9

# Convert to unsigned 'abcDef'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = "abcDef"; int res = std::strtol(s.c_str(), 0, 16);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); } } >> Всё то же, только для 16ричной системы Everything is the same, only for the hexadecimal system23.523.534.435.467.9
std::string_view s = "abcDef"; std::from_chars(s.data(), s.data() + s.size(), res, 16);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); } }9.659.898.719.4525.8
stringa s = "abcDef"; int res = s.to_int<int, true, 16, false>template<typename T> void ToIntSimStr16(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int, true, 16, false, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }12.58.1912.013.419.2
ssa s = "abcDef"; int res = s.to_int<int, true, 16, false>template<typename T> void ToIntSimStr16(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int, true, 16, false, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }13.07.7711.812.519.0
lstringa<20> s = "abcDef"; int res = s.to_int<int, true, 16, false>template<typename T> void ToIntSimStr16(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int, true, 16, false, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }12.58.1212.313.819.6

# Convert to int ' 1234567'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = " 123456789"; int res = std::strtol(s.c_str(), 0, 0);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); } } >> А здесь уже парсинг произвольного числа. And here we have parsing of an arbitrary number.28.628.444.244.898.4
stringa s = " 123456789"; int res = s.to_int<int>; // Check overflowtemplate<typename T> void ToIntSimStr0(benchmark::State& state, T t, int c) { for (auto _: state) { int res = t. template to_int<int>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }18.514.917.721.624.4
ssa s = " 123456789"; int res = s.to_int<int, false>; // No check overflowvoid ToIntNoOverflow(benchmark::State& state, ssa t, int c) { for (auto _: state) { int res = t.to_int<int, false>().value; #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); benchmark::DoNotOptimize(t); } }15.513.715.916.919.3

# Convert to double '1234.567e10'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = "1234.567e10"; double res = std::strtod(s.c_str(), nullptr);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); } }63.766.8102105308
std::string_view s = "1234.567e10"; std::from_chars(s.data(), s.data() + s.size(), res);void ToDoubleFromChars(benchmark::State& state, const std::string_view& s, double c) { for (auto _: state) { double res = 0; if (std::from_chars(s.data(), s.data() + s.size(), res).ec != std::errc{}) { state.SkipWithError("not equal"); } #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } }25.025.058.779.8109
ssa s = "1234.567e10"; double res = *s.to_double()template<typename T> void ToDoubleSimStr(benchmark::State& state, T t, double c) { for (auto _: state) { auto r = t.template to_double<false>(); 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); } }25.425.235.236.242.1

# Append const literal of 16 bytes 64 times, 1024 total length

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << "abbaabbaabbaabba";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); } }13511359462558686617
std::string str; ... str += "abbaabbaabbaabba";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); } }38338010671286775
lstringa<8> str; ... str += "abbaabbaabbaabba";template<unsigned N> void AppendLstringConstLiteral(benchmark::State& state) { for (auto _: state) { lstringa<N> 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); } }378435746948700
lstringa<128> str; ... str += "abbaabbaabbaabba";template<unsigned N> void AppendLstringConstLiteral(benchmark::State& state) { for (auto _: state) { lstringa<N> 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); } } >> Чем больше внутренний буфер, тем меньше раз требуется аллокация, тем быстрее результат. The larger the internal buffer, the fewer allocations are required, and the faster the result.253280388542574
lstringa<512> str; ... str += "abbaabbaabbaabba";template<unsigned N> void AppendLstringConstLiteral(benchmark::State& state) { for (auto _: state) { lstringa<N> 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); } }223255227366519
lstringa<1024> str; ... str += "abbaabbaabbaabba";template<unsigned N> void AppendLstringConstLiteral(benchmark::State& state) { for (auto _: state) { lstringa<N> 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); } }136141135229420

# Append string of 16 bytes and const literal of 16 bytes 32 times, 1024 total length

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << str_var << "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); } }13371357451756217050
std::string str; ... str += str_var + "abbaabbaabbaabba";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); } }12691291376338322182
lstringa<8> str; ... str += str_var + "abbaabbaabbaabba";template<unsigned N> void AppendLstringStrConstLiteral(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }479450703813978
lstringa<128> str; ... str += str_var + "abbaabbaabbaabba";template<unsigned N> void AppendLstringStrConstLiteral(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }354373450538838
lstringa<512> str; ... str += str_var + "abbaabbaabbaabba";template<unsigned N> void AppendLstringStrConstLiteral(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }329337300385735
lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba";template<unsigned N> void AppendLstringStrConstLiteral(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }236246209269663

# Append string of 16 bytes and const literal of 16 bytes 2048 times, 65536 total length

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << str_var << "abbaabbaabbaabba"; 2048 timesvoid 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); } }7387776165221538278650346232
std::string str; ... str += str_var + "abbaabbaabbaabba"; 2048 timesvoid 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); } }7120374730187478196731119182
lstringa<8> str; ... str += str_var + "abbaabbaabbaabba"; 2048 timestemplate<unsigned N> void AppendLstringStrConstLiteralBig(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }1865320473184902380350289
lstringa<128> str; ... str += str_var + "abbaabbaabbaabba"; 2048 timestemplate<unsigned N> void AppendLstringStrConstLiteralBig(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }1901817347168422256847056
lstringa<512> str; ... str += str_var + "abbaabbaabbaabba"; 2048 timestemplate<unsigned N> void AppendLstringStrConstLiteralBig(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }1590517337161402162547969
lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba"; 2048 timestemplate<unsigned N> void AppendLstringStrConstLiteralBig(benchmark::State& state) { stringa p1 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }1572417747161872118247909

# Append 2 string of 16 bytes 32 times, 1024 total length

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << str_var1 << str_var2;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); } }13991390454252487139
std::string str; ... str += str_var1 + str_var2;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); } }13561351383740212572
lstringa<16> str; ... str += str_var1 + str_var2;template<unsigned N> void AppendLstring2String(benchmark::State& state) { stra s1 = TEXT_16; stra s2 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }5365478169001204
lstringa<128> str; ... str += str_var1 + str_var2;template<unsigned N> void AppendLstring2String(benchmark::State& state) { stra s1 = TEXT_16; stra s2 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }4314555266221079
lstringa<512> str; ... str += str_var1 + str_var2;template<unsigned N> void AppendLstring2String(benchmark::State& state) { stra s1 = TEXT_16; stra s2 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }404428382462993
lstringa<1024> str; ... str += str_var1 + str_var2;template<unsigned N> void AppendLstring2String(benchmark::State& state) { stra s1 = TEXT_16; stra s2 = TEXT_16; for (auto _: state) { lstringa<N> 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); } }283318277351947

# Append text, number, text

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; str << "test = " << k << " times";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); } } }29753118108081162511745
std::string str = "test = " + std::to_string(k) + " times";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); } } }470444104412331627
char buf[100]; sprintf(buf, "test = %u times", k); std::string str = buf;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); } } }13631517281228065392
std::string str = std::format("test = {} times", 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); } } }11121221191323672823
lstringa<8> str; str.format("test = {} times", k);template<typename T> 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); } } } >> В simstr format с первого раза не помещается в такую строку без аллокации. In simstr format, the first time it doesn't fit into such a string without allocation.13061732207126244756
lstringa<32> str; str.format("test = {} times", k);template<typename T> 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); } } } >> А в такую помещается. Используйте сразу буфера подходящего размера. And it fits in this one. Use buffers of the appropriate size right away.9461099100614814212
lstringa<8> str = "test = " + k + " times";template<typename T> 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); } } } >> Результат не помещается в SSO, возникает аллокация. The result does not fit into SSO, an allocation occurs.292299836898565
lstringa<32> str = "test = " + k + " times";template<typename T> 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); } } } >> А здесь и ниже - результат укладывается в SSO. Ещё раз - используйте сразу буфера подходящего размера. And here and below, the result fits within SSO. Once again, use appropriately sized buffers from the start.151180155194338
stringa str = "test = " + k + " times";template<typename T> 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); } } } >> Под WASM размер SSO 15 символов, что явно не хватает для размещения результата, отсюда и такое время. Under WASM, the SSO size is 15 characters, which is clearly not enough to accommodate the result, hence the long time.154189156236564

# Split text and convert to int

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string::find + substr + std::strtolvoid 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); } }287290541543693
ssa::splitter + ssa::as_intvoid 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<int>(); } #ifdef CHECK_RESULT if (total != 218) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(total); benchmark::DoNotOptimize(numbers); } }150147158296250
ssa::splitf + functorvoid SplitConvertIntSplitf(benchmark::State& state) { stra numbers = NUMBER_LIST; for (auto _: state) { int total = 0; numbers.splitf<void>("-!-", [&](ssa& part){total += part.as_int<int>();}); #ifdef CHECK_RESULT if (total != 218) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(total); benchmark::DoNotOptimize(numbers); } }204136181213277

# Replace symbols in text ~400 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Naive (and wrong) replace symbols with std::string find + replacevoid 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<std::pair<u8s, std::string_view>> repl = { {'&', "&amp;"}, {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"} }; 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 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } >> Это наивная реализация, которая неверно отработает на таких заменах, как 'a'->'b' и 'b'->'a'. Но если замены не конфликтуют, то работает быстро. This is a naive implementation that will fail to handle substitutions such as 'a'->'b' and 'b'->'a'. But if the substitutions don't conflict, it works quickly.847925117112503150
replace symbols with std::string find_first_of + replacevoid 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<std::pair<u8s, std::string_view>> repl = { {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"}, {'&', "&amp;"}, }; 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 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } >> Дальше уже правильные реализации, не зависящие от конфликтующих замен. Further, there are correct implementations that do not depend on conflicting replacements.24052787204921604982
replace symbols with std::string_view find_first_of + copyvoid 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[] = {"", "&lt;", "&gt;", "&#39;", "&quot;", "&amp;"}; 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 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } }10811082235725593246
replace runtime symbols with string expressions and without remembering all search resultstemplate<bool UseVector> 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<std::pair<u8s, ssa>> repl = { {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"}, {'&', "&amp;"}, }; for (auto _: state) { stringa result = expr_replace_symbols<u8s, UseVector>{source, repl}; #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }12341483145115853117
replace runtime symbols with simstr and memorization of all search resultstemplate<bool UseVector> 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<std::pair<u8s, ssa>> repl = { {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"}, {'&', "&amp;"}, }; for (auto _: state) { stringa result = expr_replace_symbols<u8s, UseVector>{source, repl}; #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }9891047134614232534
replace const symbols with string expressions and without remembering all search resultstemplate<bool UseVector> 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<UseVector>(source, '-', "", '<', "&lt;", '>', "&gt;", '\'', "&#39;", '\"', "&quot;", '&', "&amp;" ); #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } }10991228122813062608
replace const symbols with string expressions and memorization of all search resultstemplate<bool UseVector> 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<UseVector>(source, '-', "", '<', "&lt;", '>', "&gt;", '\'', "&#39;", '\"', "&quot;", '&', "&amp;" ); #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } }862850112112402259

# Replace symbols in text ~40 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Short Naive (and wrong) replace symbols with std::string find + replacevoid ShortReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector<std::pair<u8s, std::string_view>> repl = { {'&', "&amp;"}, {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"} }; 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 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }163165320327449
Short replace symbols with std::string find_first_of + replacevoid ShortReplaceSymbolsStdStringNaiveRight(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector<std::pair<u8s, std::string_view>> repl = { {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"}, {'&', "&amp;"}, }; 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 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }319313364434628
Short replace symbols with std::string_view find_first_of + copyvoid 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[] = {"", "&lt;", "&gt;", "&#39;", "&quot;", "&amp;"}; 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 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } }162156319368474
Short replace runtime symbols with string expressions and without remembering all search resultstemplate<bool UseVector> void ShortReplaceSymbolsDynPatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector<std::pair<u8s, ssa>> repl = { {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"}, {'&', "&amp;"}, }; for (auto _: state) { stringa result = expr_replace_symbols<u8s, UseVector>{source, repl}; #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }175188266306376
Short replace runtime symbols with simstr and memorization of all search resultstemplate<bool UseVector> void ShortReplaceSymbolsDynPatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector<std::pair<u8s, ssa>> repl = { {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"}, {'&', "&amp;"}, }; for (auto _: state) { stringa result = expr_replace_symbols<u8s, UseVector>{source, repl}; #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }180193355409435
Short replace const symbols with string expressions and without remembering all search resultstemplate<bool UseVector> void ShortReplaceSymbolsCons2PatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; for (auto _: state) { stringa result = e_repl_const_symbols<UseVector>(source, '-', "", '<', "&lt;", '>', "&gt;", '\'', "&#39;", '\"', "&quot;", '&', "&amp;" ); #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } }137150225268285
Short replace const symbols with string expressions and memorization of all search resultstemplate<bool UseVector> void ShortReplaceSymbolsCons2PatternSimStr(benchmark::State& state) { stra source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; for (auto _: state) { stringa result = e_repl_const_symbols<UseVector>(source, '-', "", '<', "&lt;", '>', "&gt;", '\'', "&#39;", '\"', "&quot;", '&', "&amp;" ); #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); } }142143292346312

# Replace All Str To Longer Size

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
replace bb to ---- in std::string|64template<size_t Long> 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); } }158159224246422
replace bb to ---- in std::string|256template<size_t Long> 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); } }5325027567971229
replace bb to ---- in std::string|512template<size_t Long> 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); } }10231124143114842359
replace bb to ---- in std::string|1024template<size_t Long> 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); } }23572263311231875079
replace bb to ---- in std::string|2048template<size_t Long> 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); } }578958987873826412214
replace bb to ---- in lstringa<8>|64template<size_t N, size_t Count> 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<N> 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); } }141163217234311
replace bb to ---- in lstringa<8>|256template<size_t N, size_t Count> 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<N> 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); } }441480622674964
replace bb to ---- in lstringa<8>|512template<size_t N, size_t Count> 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<N> 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); } }828909105011321801
replace bb to ---- in lstringa<8>|1024template<size_t N, size_t Count> 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<N> 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); } }16891860190620703329
replace bb to ---- in lstringa<8>|2048template<size_t N, size_t Count> 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<N> 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); } }31623465360439286478
replace bb to ---- by init stringa|64template<size_t Count> 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.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); } }95.598.5184204205
replace bb to ---- by init stringa|256template<size_t Count> 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.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); } }305302373483620
replace bb to ---- by init stringa|512template<size_t Count> 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.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); } }72972981410601395
replace bb to ---- by init stringa|1024template<size_t Count> 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.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); } }15021639162922792995
replace bb to ---- by init stringa|2048template<size_t Count> 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.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); } }31503376302945265944

# Replace All Str To Same Size

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
replace bb to -- in std::string|64template<size_t Long> 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); } }125117193213282
replace bb to -- in std::string|256template<size_t Long> 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); } }392392561540853
replace bb to -- in std::string|512template<size_t Long> 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); } }75870510229751670
replace bb to -- in std::string|1024template<size_t Long> 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); } }14151346159618123119
replace bb to -- in std::string|2048template<size_t Long> 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); } }30322835348935626498
replace bb to -- in lstringa<8>|64template<size_t N, size_t Long> 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<N> 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); } }97.7102184196221
replace bb to -- in lstringa<8>|256template<size_t N, size_t Long> 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<N> 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); } }290284435459671
replace bb to -- in lstringa<8>|512template<size_t N, size_t Long> 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<N> 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); } }5515257467911237
replace bb to -- in lstringa<8>|1024template<size_t N, size_t Long> 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<N> 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); } }11291047136115192398
replace bb to -- in lstringa<8>|2048template<size_t N, size_t Long> 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<N> 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); } }21461993264828884661
replace bb to -- by init stringa|64template<size_t Count> 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); } }84.593.5155176171
replace bb to -- by init stringa|256template<size_t Count> 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); } }239268349389528
replace bb to -- by init stringa|512template<size_t Count> 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); } }424506599647881
replace bb to -- by init stringa|1024template<size_t Count> 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); } }8961045105612221721
replace bb to -- by init stringa|2048template<size_t Count> 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); } }16852003202422803318

# Hash Map insert and find

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
hashStrMapA<size_t> emplace & find stringa;void HashMapSimStr(benchmark::State& state) { for (auto _: state) { hashStrMapA<size_t> 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); } } } >> Вставляем в hashStrMapA 10000 stringa длиной от 30 до 50 символов, а потом ищем их в ней We insert 10,000 strings of length from 30 to 50 characters into hashStrMapA, and then search for them in it.35473423717070399026042403703294169
std::unordered_map<std::string, size_t> emplace & find std::string;void HashMapStdStr(benchmark::State& state) { for (auto _: state) { std::unordered_map<std::string, size_t> 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); } } } >> То же самое c std::string и std::unordered_map Same thing with std::string and std::unordered_map35237323567358569677054650213593372
hashStrMapA<size_t> emplace & find ssa;void HashMapSimSsa(benchmark::State& state) { for (auto _: state) { hashStrMapA<size_t> 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); } } } >> Теперь вставляем stringa, а ищем ssa Now we insert stringa and search for ssa35544033701465345356239256463280453
std::unordered_map<std::string, size_t> emplace & find std::string_view;void HashMapStdStrView(benchmark::State& state) { for (auto _: state) { std::unordered_map<std::string, size_t> 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); } } } >> Вставляем std::string, а ищем std::string_view We insert std::string and look for std::string_view39556013941394629366562426933999371

# Build Full Func Name

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Build func full name 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. A common task, similar to this one, can often be encountered in work: Generate text from given data. In this case, using data on certain functions, generate their full names with parameter types and return values. The algorithm uses std::string.721971159316643564
Build func full name std::string 1;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; } >> Почти тот же алгоритм, но несколько последовательных += к строке заменены на одно += + + +. Almost the same algorithm, but several consecutive += to a string are replaced with a single += + + +.8281015158517693650
Build func full name std::stream;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(); } >> Строим имя функции через std::ostringstream и << We construct the function name through std::ostringstream and <<256125698042977812092
Build func full name stringa;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, ", ") + "...") + ")"; } >> Реализация на simstr строках и строковых выражениях. Инфа о параметрах добавляется в текущую строку Implementation using simstr strings and string expressions. Parameter information is appended to the current line.5034638078731696
Build func full name stringa 1;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, ", ") + "...") + ")"; } >> Реализация на simstr строках и строковых выражениях. Инфа о параметрах добавляется во временную строку, а потом разом добавляется в текущую строку. Позволяет операции в цикле записать в одну строку, но чуть проигрывает по времени выполнения. Implementation using simstr strings and string expressions. Parameter information is added to a temporary string, and then all at once to the current string. This allows loop operations to be written in a single string, but is slightly slower in execution time.67166490010402029