SimStr benchmarks results

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 Firefox, 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); } } }219209265386862
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); } } }105104178266384
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.66.381.566.5128196
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); } } }68.880.274.9145193

# 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 Firefox, Clang-21
Concat std::string and hex number by std to std::stringvoid ConcatStdToStdHex(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); // What is standard method to get hex number? std::string str = std::format("{}0x{:x} end", s1, i); benchmark::DoNotOptimize(str); } } }861935151820921594
Concat std::string and hex number 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); std::string str = +s1 + e_hex<HexFlags::Short>(i) + " end"; benchmark::DoNotOptimize(str); } } }86.469.681.0182371
Concat stringa and hex number 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); stringa str = s1 + e_hex<HexFlags::Short>(i) + " end"; benchmark::DoNotOptimize(str); } } }75.870.476.6124185
Concat stringa and hex number 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); stringa str = e_concat("", s1, e_hex<HexFlags::Short>(i), " end"); benchmark::DoNotOptimize(str); } } }75.078.978.3180197
Concat stringa and hex number by e_subst 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(S_FRM("{}{} end"), s1, e_hex<HexFlags::Short>(i)); benchmark::DoNotOptimize(str); } } }150157150266402

# 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 Firefox, 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.245.540.172.587.7
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); } } }33.936.839.491.497.9
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); } } }29.127.228.760.191.9

# 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 Firefox, 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"); }112135205265173
Find concat three strexprsize_t find_pos_exp(ssa src, ssa name) { return src.find(std::string{"\n- " + name + " -\n"}); }50.644.3114150110
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.22.853.421.532.476.2

# 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 Firefox, 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.1710.18.2220.915.2
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; }6.737.227.6214.815.8
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; }5.575.458.1918.315.6
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; }57.286.464.1100253
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; }31.124.933.948.092.7
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; }24.722.225.344.665.5

# 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 Firefox, 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) + ">"; }202231312430411
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.151139228278243

# 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 Firefox, 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.161.151.172.852.14
std::string_view e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }0.3840.7720.3632.020.972
ssa e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }0.3780.1900.3602.050.939
stringa e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }0.7620.7500.7402.422.15
lstringa<20> e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }1.141.111.112.912.19
lstringa<40> e;template<typename T> void CreateEmpty(benchmark::State& state) { for (auto _: state) { T empty_string; benchmark::DoNotOptimize(empty_string); } }1.121.121.103.012.58

# 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 Firefox, 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.871.822.902.33
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.8060.7692.051.24
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.3690.7500.3652.030.968
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.151.121.082.872.16
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.941.921.852.962.65
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.881.881.872.952.61

# 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 Firefox, 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.619.572.196.316.0
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.7710.7440.7342.061.28
ssa e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } }0.3820.7380.3602.060.971
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.131.111.083.002.18
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.24.323.074.597.116.5
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.601.962.523.653.00

# 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 Firefox, 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.5.674.971.845.612.21
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.3770.3990.3733.951.26
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.3870.3810.3633.921.24
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.141.151.284.442.55
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.4.294.564.749.7215.2
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.4.204.614.709.6114.5

# 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 Firefox, 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...21.225.376.694.633.3
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.7370.7310.7141.941.27
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.3790.7310.3621.970.981
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.131.131.843.362.19
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.20.722.579.197.115.7
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.484.614.468.1614.2

# 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 Firefox, 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.8.537.7438.246.354.4
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.926.6838.245.056.9
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); } }7.086.4517.825.556.5
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.656.7818.734.460.3
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); } }7.066.9519.634.152.4
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.796.8717.524.051.0

# 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 Firefox, 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.985.031.804.9134.4
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 меньше, насколько я помню, 11 символов + 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.23.523.780.710734.6
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.23.123.281.510035.2
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); } }23.123.279.110434.8
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); } }25.325.681.010841.2
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); } }22.724.782.111337.9
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); } }25.825.984.910439.8
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.625.584.911059.6
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.629.895.711057.3
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); } }47.046.495.912559.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); } }12412413115082.2
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.168158175206111
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.101.121.314.442.54
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.111.131.294.434.81
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.121.131.294.454.84
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.819.14.89
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); } }16.016.216.019.04.85
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.116.615.719.04.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.316.115.918.94.93
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.116.116.019.24.97
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.115.918.95.06
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); } }16.216.616.119.14.81
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.916.118.94.86
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.516.516.019.14.76
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.4.724.445.028.4914.1
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); } }4.564.464.968.6813.9
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); } }4.734.535.429.2228.7
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.25.626.978.195.629.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); } }24.123.884.710331.9
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); } }25.525.682.410432.0
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); } }29.027.187.210932.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); } }27.230.693.770655.0
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); } }30.430.093.010851.9
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); } }10598.899.612254.2
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); } }12011812714979.1
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); } }134135198211106
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); } }4.935.214.949.8315.4
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.055.224.9310.215.5
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.295.394.719.6915.2
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); } }5.075.854.8710.215.0
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.544.857.6914.118.3
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.087.007.7913.717.7
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.397.118.6814.118.1
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.4216.49.4815.220.7
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.11.510.610.916.721.8
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.94.198.498.511252.9
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); } }11211713215376.5
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); } }129137199208105

# 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 Firefox, 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.828.431.838.873.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.15.012.514.116.227.8
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.69.3314.417.319.0
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.68.0613.817.517.0
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.38.3113.817.417.0

# 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 Firefox, 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.423.733.840.856.5
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.809.698.3611.028.3
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.6013.015.617.3
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); } }12.68.2012.416.316.2
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); } }13.08.1912.316.116.7

# 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 Firefox, 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.29.728.545.754.177.7
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.315.019.522.624.6
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.010.815.918.523.6

# 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 Firefox, 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); } }64.765.2104118196
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); } }27.525.662.195.8106
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); } }26.124.835.841.043.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 Firefox, 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); } }15871362544872624557
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); } }37836810581589598
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); } }4023997841249705
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.264274397639564
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); } }257254241511472
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); } }157139152255396

# 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 Firefox, 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); } }14411381453468654433
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); } }12661279380345071926
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); } }4824756981082804
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); } }366413446664726
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); } }325323293538597
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); } }235243205319523

# 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 Firefox, 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); } }7535975087226006323116218832
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); } }7562074728202060236019104650
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); } }1877720069180252627739563
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); } }2018619059162172473738589
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); } }1602817233158262381037622
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); } }1579817586161772410338473

# 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 Firefox, 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); } }14391393460462334648
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); } }13981436379744362346
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); } }54056081311981150
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); } }4654465276731100
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); } }398400381595934
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); } }323307278399867

# 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 Firefox, 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); } } }3053307610665132406486
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); } } }479470105214041576
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); } } }14121714278932092894
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); } } }12081289190425392063
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.13791588216831933409
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.10791059102916592460
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.313332807975611
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.154160155217345
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.145167151276541

# 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 Firefox, 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); } }283271539633609
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); } }159133173329269
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); } }204131191240338

# 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 Firefox, 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.848845118514283726
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.24322401216524435016
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); } }10701157229829483479
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); } }13091495143918043472
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); } }10661055127016123043
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); } }10301238113514412845
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); } }898872121014382739

# 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 Firefox, 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); } }155175321384470
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); } }337319385475494
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); } }164183330388413
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); } }193225269302380
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); } }205206348434401
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); } }139162232260257
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); } }144156323345302

# 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 Firefox, 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); } }160164232249371
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); } }5684927578101351
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); } }11771119148215562646
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); } }22942211315032295606
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); } }590359598049817412254
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); } }245148304312332
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); } }7774856066601116
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); } }1500893105411382117
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); } }29071845183920564092
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); } }59293614350339177783
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); } }129110183206212
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); } }356305374475725
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); } }77475182410561687
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); } }15831630168121523720
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); } }33953440311143217469

# 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 Firefox, 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); } }119118196215259
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); } }451418487552941
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); } }7827738999691842
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); } }14921538168718203695
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); } }30102919314835936890
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); } }209100179193219
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); } }855298440465797
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); } }18285517977881465
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); } }36611105154214472845
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); } }76702117292728575530
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); } }83.895.6156185178
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); } }236270349387634
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); } }4855535836511214
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); } }8831031109911962270
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); } }17171966207324084529

# 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 Firefox, 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.35955923722226379577342395543204846
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_map35992863711685581456358436693332883
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 ssa37410653706802350748039630343197797
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_view41881764055890677439362800803669143

# 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 Firefox, 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.709943161117162854
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 += + + +.8291022168118022988
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 <<255226718266100116634
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.50361282110611333
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.67065796312451547