simstr benchmarks results

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

Test configurations:

# Concatenate email

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat email std::formatstd::string email_concat_format(std::string_view name, std::string_view domain, std::string_view tld) { return std::format("{}@{}.{}", name, domain, tld); }167176210254529
Concat email std::stringstreamstd::string email_concat_stream(std::string_view name, std::string_view domain, std::string_view tld) { std::stringstream s; s << name << "@" << domain << "." << tld; return s.str(); }3243328569341155
Concat email stringzilla appendsz::string email_concat_stringzilla_app(sz::string name, sz::string_view domain, sz::string_view tld) { return name.append("@").append(domain).append(".").append(tld); }135115271268249
Concat email stringzilla concatsz::string email_concat_stringzilla_exp(sz::string name, sz::string_view domain, sz::string_view tld) { return sz::string{name | sz::string_view{"@"} | domain | sz::string_view{"."} | tld}; } >> В stringzilla тоже есть конкатенация строковыми выражениями, но не так удобна и развита, как в simstr. Stringzilla also has concatenation by expression templates, but it's not as convenient or advanced as simstr.53.546.612812995.2
Concat email std::string appendstd::string email_concat_std(std::string name, std::string_view domain, std::string_view tld) { return name.append("@").append(domain).append(".").append(tld); }72.999.0187197324
Concat email std::string by strexprstd::string email_concat_std_expr(std::string_view name, std::string_view domain, std::string_view tld) { return +name + "@" + domain + "." + tld; }43.535.610711092.7
Concat email stringastringa email_concat_sim_expr(ssa name, ssa domain, ssa tld) { return name + "@" + domain + "." + tld; }39.440.593.199.571.3

# Concatenate string + Number + "Literal"

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat std::string and number by std to std::stringvoid ConcatStdToStd(benchmark::State& state) { std::string s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); std::string str = s1 + std::to_string(i) + " end"; benchmark::DoNotOptimize(str); } } }2142092643371115
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); } } }10498.1156219530
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.67.773.069.1111227
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); } } }70.879.774.9116258

# Concatenate string + Hex Number + "Literal"

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat std::string and format hex number and literal to std::stringvoid ConcatStdToFmtHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // It is not worked for char8_t, char16_t, char32_t :( std::string str = s1 + std::format("{:#x}", i) + " end"; benchmark::DoNotOptimize(str); } } }68974671510432114
std::format std::string and hex number by literal to std::stringvoid ConcatAllFmtToHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // It is not worked for char8_t, char16_t, char32_t :( std::string str = std::format("{}{:#x} end", s1, i); benchmark::DoNotOptimize(str); } } }889970149618592763
Concat std::string and std::to_chars and string to std::stringvoid ConcatStdToCharsHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // it worked only for char :( char buf[40]; size_t len = std::to_chars(buf, buf + std::size(buf), i, 16).ptr - buf; std::string str = s1 + "0x" + std::string(buf, len) + " end"; benchmark::DoNotOptimize(str); } } }199254194256743
Concat std::string and hex number and literal by StrExpr to std::stringvoid ConcatSimToStdHex(benchmark::State& state) { // We use a short string so that the longest result is 15 characters and fits in the std::string SSO buffer. std::string s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // Can work for all types of symbols std::string str = +s1 + i / 1_f16 + " end"; benchmark::DoNotOptimize(str); } } }13412689.2136547
Concat stringa and hex number and literal by StrExpr to simstr::stringavoid ConcatSimToSimHex(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // Can work for all types of symbols stringa str = s1 + i / 1_f16 + " end"; benchmark::DoNotOptimize(str); } } }11712070.7105220
Concat stringa and hex number and literal by e_concat to simstr::stringavoid ConcatSimToSimHexC(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); // Can work for all types of symbols stringa str = e_concat("", s1, i / 1_f16, " end"); benchmark::DoNotOptimize(str); } } }12312877.7103211
Subst stringa and hex number by e_subst literal to simstr::stringavoid ConcatSimToSimHexS(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = e_subst("{}{} end", s1, i / 1_f16); benchmark::DoNotOptimize(str); } } }188169156176354
Subst stringa and hex number by e_vsubst stra to simstr::stringavoid ConcatSimToSimHexVS(benchmark::State& state) { // stringa SSO buffer is 23, but we use a short string to compare under the same conditions stra s1 = "art "; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = e_vsubst("{}{} end"_ss, s1, i / 1_f16); benchmark::DoNotOptimize(str); } } }310292291362936

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

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
"abcdefghihklmopqr "_ss + i / 0x8a010_fmt + " end"void ConcatSimToSimOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { stringa str = "abcdefghihklmopqr "_ss + i / 0x8a010_fmt + " end"; benchmark::DoNotOptimize(str); } } }277261685701434
e_subst("abcdefghihklmopqr {} end", i / 0x8a010_fmt)void SubstSimToSimOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { stringa str = e_subst("abcdefghihklmopqr {} end", i / 0x8a010_fmt); benchmark::DoNotOptimize(str); } } }353320758798634
e_vsubst(pattern, i / 0x8a010_fmt)void VSubstSimToSimOct(benchmark::State& state) { ssa pattern = "abcdefghihklmopqr {} end"; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { stringa str = e_vsubst(pattern, i / 0x8a010_fmt); benchmark::DoNotOptimize(str); } } }615614112811111530
fmt::format(FMT_COMPILE("abcdefghihklmopqr {:#010o} end"), i)void FmtFormatComp(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = fmt::format(FMT_COMPILE("abcdefghihklmopqr {:#010o} end"), i); benchmark::DoNotOptimize(str); } } }685745142416172320
fmt::format("abcdefghihklmopqr {:#010o} end", i)void FmtFormat(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = fmt::format("abcdefghihklmopqr {:#010o} end", i); benchmark::DoNotOptimize(str); } } }854847137514403086
std::format("abcdefghihklmopqr {:#010o} end", i)void FormatStdToStdOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = std::format("abcdefghihklmopqr {:#010o} end", i); benchmark::DoNotOptimize(str); } } }10161276165718853154
std::vformat(pattern, std::make_format_args(i))void VFormatStdToStdOct(benchmark::State& state) { std::string_view pattern = "abcdefghihklmopqr {:#010o} end"; for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::string str = std::vformat(pattern, std::make_format_args(i)); benchmark::DoNotOptimize(str); } } }10161145157419573173
strm << "abcdefghihklmopqr 0" << std::oct << std::setw(9) << std::setfill('0') << i << " end"void StreamStdToStdOct(benchmark::State& state) { for (auto _: state) { for (unsigned i = 1; i <= 100'000; i *= 10) { std::stringstream strm; strm << "abcdefghihklmopqr 0" << std::oct << std::setw(9) << std::setfill('0') << i << " end"; std::string str = strm.str(); benchmark::DoNotOptimize(str); } } }20572189677371698797

# Concatenate string + "Literal"

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat std::string by std to std::stringvoid ConcatStdToStdS(benchmark::State& state) { std::string s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); std::string str = s1 + " end"; benchmark::DoNotOptimize(str); } } }45.649.444.059.3115
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); } } }32.231.839.277.1128
Concat stringa by StrExpr to stringavoid ConcatSimToSimS(benchmark::State& state) { stra s1 = "start "; for (auto _: state) { for (int i = 1; i <= 100'000; i *= 10) { benchmark::DoNotOptimize(s1); stringa str = s1 + " end"; benchmark::DoNotOptimize(str); } } }28.527.928.951.4110

# Find three concatenated string in string_view

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Find concat three std::stringsize_t find_pos_str(std::string_view src, std::string_view name) { // before C++26 we can not concatenate string and string_view... return src.find("\n- "s + std::string{name} + " -\n"); }114140206212226
Find concat three strexprsize_t find_pos_exp(ssa src, ssa name) { return src.find(std::string{"\n- " + name + " -\n"}); }49.638.1117123117
Find concat three simstrsize_t find_pos_sim(ssa src, ssa name) { return src.find(lstringa<200>{"\n- " + name + " -\n"}); } >> Если результат конкатенации меньше 207 символов, он собирается в буфере на стеке, без аллокации и деалокации. If the concatenation result is less than 207 characters, it is collected in a stack-based buffer, without allocation or deallocation.19.516.121.428.371.5
Find concat three stringzilla stringsize_t find_pos_sz(sz::string_view src, sz::string_view name) { return src.find(sz::string{"\n- "}.append(name).append(" -\n")); }145130217231288

# Build Type Name

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
BuildTypeNameStr 0/0std::string buildTypeNameStr(std::string_view type_name, size_t prec, size_t scale) { std::string res{type_name}; if (prec) { res += "(" + std::to_string(prec); if (scale) { res += "," + std::to_string(scale); } res += ")"; } return res; }7.3310.08.4017.323.4
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.788.417.5913.527.3
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.045.957.7415.220.9
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.979.660.180.4403
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.026.733.039.4122
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; }23.623.725.537.375.6

# Replace string by copy

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Concat with replace strstd::string make_str_str(std::string_view from, std::string_view pattern, std::string_view repl) { auto str_replace = [](std::string_view from, std::string_view pattern, std::string_view repl) { std::string result; for (size_t offset = 0; ;) { size_t pos = from.find(pattern, offset); if (pos == std::string::npos) { result += from.substr(offset); break; } result += from.substr(offset, pos - offset); result += repl; offset = pos + pattern.length(); } return result; }; return "<" + str_replace(from, pattern, repl) + ">"; }203233317359544
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.147136214220258

# Create Empty Str

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

# Create Str from short literal (9 symbols)

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

# Create Str from long literal (30 symbols)

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } } >> Вот тут уже литерал не помещается во внутренний буфер, возникает аллокация и копирование 30-и байтов. Но как же отстает аллокация под Windows от Linux'а, 20 vs 70 ns... Here, the literal doesn't fit into the internal buffer, and 30 bytes are allocated and copied. But how much slower is allocation under Windows than under Linux, 20 ns vs. 70 ns...20.020.875.880.526.1
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.7440.7330.7271.801.15
ssa e = "123456789012345678901234567890";template<typename T> void CreateLongLiteral(benchmark::State& state) { for (auto _: state) { T empty_string{LONG_TEXT}; benchmark::DoNotOptimize(empty_string); } }0.3730.7480.3691.870.737
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.111.131.092.892.21
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.21.220.276.576.224.2
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.591.862.523.402.92

# Create copy of Str with 9 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Строка в пределах SSO, так что просто копирует байты. The string is within the SSO, so it just copies the bytes.5.244.891.865.983.78
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.3710.3820.3703.491.08
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.3760.3820.3653.511.21
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.101.311.324.072.70
lstringa<20> e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> В обоих случаях хватает внутреннего буфера. In both cases, the internal buffer is sufficient.1.501.141.504.754.86
lstringa<40> e = "Test text"; auto c{e};template<typename T> void CopyShortString(benchmark::State& state) { T x{TEST_TEXT}; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Только копируются байты. Only bytes are copied.1.481.121.504.914.84

# Create copy of Str with 30 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string e = "123456789012345678901234567890"; auto c{e};template<typename T> void CopyLongString(benchmark::State& state) { T x = LONG_TEXT; for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); } } >> Копирования длинной строки вызывает аллокацию, SSO уже не хватает. И снова как же отстаёт аллокация под Windows... Copying a long string causes allocations, SSO is no longer sufficient. And again, how allocation lags under Windows...19.324.579.477.853.4
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.7440.7460.7431.851.12
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.7460.3741.850.746
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.111.111.833.012.18
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.721.276.482.222.5
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.594.204.957.9717.0

# Find 9 symbols text in end of 99 symbols text

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
sz::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); } } >> stringzilla более заточена на поиск больших строк в больших строках. stringzilla is more focused on searching large strings within large strings.94.792.997.9116123
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.7.156.9740.240.440.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.657.2752.239.543.8
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.316.7419.322.241.7
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); } }8.306.8519.431.441.7
lstringa<20>::find;template<typename T> void Find(benchmark::State& state) { T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT}; for (auto _: state) { int i = (int)x.find(TEST_TEXT); #ifdef CHECK_RESULT if (i != 90) { state.SkipWithError("not find?"); break; } #endif benchmark::DoNotOptimize(i); benchmark::DoNotOptimize(x); } }6.706.4517.922.439.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.756.4218.122.039.6

# Copy not literal Str with N symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }5.798.621.875.2654.0
std::string copy{str_with_len_N};/16template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Явно виден скачок, где заканчивается SSO и начинается аллокация. Обратите внимание, что WASM - 32-битный, и там размер SSO у std::string меньше, 10 символов + 0. The jump where SSO ends and allocation begins is clearly visible. Note that WASM is 32-bit, and the size of the SSO for std::string is smaller, as far as I remember: 11 characters + 0.23.728.182.883.150.8
std::string copy{str_with_len_N};/23template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Дальше просто добавляется время на копирование байтов. Then the time for copying bytes is simply added.22.827.680.282.550.7
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.427.978.882.751.0
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); } }23.027.686.083.957.8
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.826.484.485.257.0
std::string copy{str_with_len_N};/128template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }24.928.290.986.357.2
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); } }31.433.587.488.968.5
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); } }29.233.290.093.365.9
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); } }33.837.810099.388.6
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); } }77.681.0129131113
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.117121180184159
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.311.324.062.40
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.091.301.334.114.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.101.301.333.974.81
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.016.215.918.54.86
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.115.819.04.81
stringa copy{str_with_len_N};/64template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.116.215.818.55.13
stringa copy{str_with_len_N};/128template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }16.116.115.918.95.28
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.016.215.818.55.19
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.016.215.918.54.80
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.016.115.918.84.86
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.516.315.818.54.82
stringa copy{str_with_len_N};/4096template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> И как видно, кроме инкремента нет накладных расходов, время копирования не зависит от длины строки. And as you can see, there are no overhead costs other than the increment; copying time does not depend on the string length.16.116.116.018.74.82
lstringa<16> copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> lstringa<16> использует SSO до 23 символов. А в WASM 32-битная архитектура, SSO до 19 символов. lstringa<16> uses SSO up to 23 characters. WASM has a 32-bit architecture, so SSO is up to 19 characters.1.511.091.554.594.09
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.984.545.549.6916.1
lstringa<16> copy{str_with_len_N};/23template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }5.024.545.659.5638.4
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.324.579.981.839.6
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); } }25.324.687.185.041.7
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); } }26.826.283.383.642.5
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); } }27.126.689.289.746.0
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); } }28.327.590.089.556.1
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); } }31.130.792.990.554.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); } }53.554.110399.968.5
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); } }64.264.512412997.6
lstringa<16> copy{str_with_len_N};/4096template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }90.287.1188189143
lstringa<512> copy{str_with_len_N};/15template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }1.501.131.474.414.74
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); } }4.924.865.249.3316.3
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); } }4.884.795.289.4716.0
lstringa<512> copy{str_with_len_N};/24template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }4.604.735.189.3516.2
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.584.598.2712.419.5
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); } }5.955.998.1712.419.3
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.426.998.4312.819.5
lstringa<512> copy{str_with_len_N};/256template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } }7.928.239.9813.922.1
lstringa<512> copy{str_with_len_N};/512template<typename T> void CopyDynString(benchmark::State& state) { T x(state.range(0), 'a'); for (auto _: state) { T copy{x}; benchmark::DoNotOptimize(copy); benchmark::DoNotOptimize(x); } } >> Даже 512 символов копируются быстрее, чем одна аллокация или атомарный инкремент. Even 512 characters are copied faster than a single allocation or atomic increment.10.310.411.215.623.7
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.53.255.598.099.773.4
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); } }63.266.3128128102
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); } }89.490.6189190150

# Convert to int '1234567'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = "123456789"; int res = std::strtol(s.c_str(), 0, 10);void ToIntStr10(benchmark::State& state, const std::string& s, int c) { for (auto _: state) { int res = std::strtol(s.c_str(), nullptr, 10); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } >> В simstr для конвертации в число достаточно куска строки, нет нужды в null терминированности. Ближайший аналог такого поведения "std::from_chars", но он к сожалению очень ограничен по возможностям. Здесь я попытался произвести тесты, близкие по логике к работе std::from_chars In simstr, a string fragment is sufficient for conversion to a number; there's no need for null termination. The closest analog to this behavior is "std::from_chars," but unfortunately, it is very limited in its capabilities. Here, I attempted to run tests that are similar in logic to std::from_chars.27.427.831.331.891.8
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.12.911.313.612.00.732
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.9.547.9413.417.318.7
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); } }9.238.5412.515.417.2
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); } }9.457.9013.414.817.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 Chrome 143, Clang-21
std::string s = "abcDef"; int res = std::strtol(s.c_str(), 0, 16);void ToIntStr16(benchmark::State& state, const std::string& s, int c) { for (auto _: state) { int res = std::strtol(s.c_str(), nullptr, 16); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } >> Всё то же, только для 16ричной системы Everything is the same, only for the hexadecimal system23.723.533.435.166.6
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.439.038.218.9518.0
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); } }7.597.9312.314.517.9
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); } }7.577.497.4912.316.3
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); } }7.567.4911.813.116.2

# Convert to int ' 1234567'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = " 123456789"; int res = std::strtol(s.c_str(), 0, 0);void ToIntStr0(benchmark::State& state, const std::string& s, int c) { for (auto _: state) { int res = std::strtol(s.c_str(), nullptr, 0); #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } } >> А здесь уже парсинг произвольного числа. And here we have parsing of an arbitrary number.28.529.244.046.9106
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); } }11.515.416.322.214.7
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); } }13.313.513.018.815.5

# Convert to double '1234.567e10'

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string s = "1234.567e10"; double res = std::strtod(s.c_str(), nullptr);void ToDoubleStr(benchmark::State& state, const std::string& s, double c) { for (auto _: state) { char* ptr = nullptr; double res = std::strtod(s.c_str(), &ptr); if (ptr == s.c_str()) { state.SkipWithError("not equal"); } #ifdef CHECK_RESULT if (res != c) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(res); } }66.564.397.7100301
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); } }24.023.860.587.4106
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.024.836.238.041.1

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

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << "abbaabbaabbaabba";void AppendStreamConstLiteral(benchmark::State& state) { for (auto _: state) { std::string result; std::stringstream str; for (size_t c = 0; c < 64; c++) { str << TEXT_16; } result = str.str(); #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(str); } }13881348471357296596
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); } }36832610831363858
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); } }374358824970782
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.233236391542591
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); } }237211254369461
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); } }163140134230372

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

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << str_var << "abbaabbaabbaabba";void AppendStreamStrConstLiteral(benchmark::State& state) { std::string s1 = TEXT_16; for (auto _: state) { std::string result; std::stringstream s; for (size_t c = 0; c < 32; c++) { s << s1 << TEXT_16; } result = s.str(); #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); } }14781373460658407324
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); } }12861249382538412429
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); } }4354017468561035
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); } }336355468542886
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); } }280300303391745
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); } }214249184288685

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

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << str_var << "abbaabbaabbaabba"; 2048 timesvoid AppendStreamStrConstLiteralBig(benchmark::State& state) { std::string s1 = TEXT_16; for (auto _: state) { std::string result; std::stringstream s; for (size_t c = 0; c < 2048; c++) { s << s1 << TEXT_16; } result = s.str(); #ifdef CHECK_RESULT if (result.size() != 1024 * 64) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); } }119217118986224278288424367555
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); } }7273473469192363189131128555
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); } }4667947566209742495551145
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); } }2814526208168892198748871
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); } }1909020362162872209949022
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); } }1608316214162802337647869

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

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; ... str << str_var1 << str_var2;void AppendStream2String(benchmark::State& state) { std::string s1 = TEXT_16; std::string s2 = TEXT_16; for (auto _: state) { std::string result; std::stringstream s; for (size_t c = 0; c < 32; c++) { s << s1 << s2; } result = s.str(); #ifdef CHECK_RESULT if (result.size() != 1024) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(s1); benchmark::DoNotOptimize(s2); } }13981401449154717371
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); } }13961418404840912705
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); } }4894848139331272
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); } }4044185266411198
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); } }3743713984831033
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); } }292320295389960

# Append text, number, text

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::stringstream str; str << "test = " << k << " times";void AppendStreamStrNumStr(benchmark::State& state) { for (auto _: state) { for (unsigned k = 1; k <= 1'000'000'000; k *= 10) { std::stringstream t; t << "test = " << k << " times"; std::string result = t.str(); #ifdef CHECK_RESULT if (!result.starts_with("test = ") || !result.ends_with(" times")) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(k); } } }30753267105551266811807
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); } } }444434106112701850
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); } } }13771519284328065459
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); } } }11251497190823762886
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.13861586205626304975
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.10211126102915464261
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.282315832925592
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.127154138173376
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.123133123180573

# Split text and convert to int

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
std::string::find + substr + std::strtolvoid SplitConvertIntStdString(benchmark::State& state) { std::string numbers = NUMBER_LIST; for (auto _: state) { int total = 0; for (size_t start = 0; start < numbers.length(); ) { int delim = numbers.find("-!-", start); if (delim == std::string::npos) { delim = numbers.size(); } std::string part = numbers.substr(start, delim - start); total += std::strtol(part.c_str(), nullptr, 0); start = delim + 3; } #ifdef CHECK_RESULT if (total != 218) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(total); benchmark::DoNotOptimize(numbers); } }265265549556693
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); } }155143164302240
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); } }206125188216281

# Replace symbols in text ~400 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Naive (and wrong) replace symbols with std::string find + replacevoid ReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" " ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf" ; std::vector<std::pair<u8s, std::string_view>> repl = { {'&', "&amp;"}, {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"} }; auto repl_all = [](std::string& str, char s, std::string_view repl) { size_t start_pos = 0; while((start_pos = str.find(s, start_pos)) != std::string::npos) { str.replace(start_pos, 1, repl); start_pos += repl.length(); } }; for (auto _: state) { std::string result{source}; for (const auto& r : repl) { repl_all(result, r.first, r.second); } #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" " ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } } >> Это наивная реализация, которая неверно отработает на таких заменах, как 'a'->'b' и 'b'->'a'. Но если замены не конфликтуют, то работает быстро. This is a naive implementation that will fail to handle substitutions such as 'a'->'b' and 'b'->'a'. But if the substitutions don't conflict, it works quickly.841837116112592875
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.24502361201222625461
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); } }1078965238526183004
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); } }12741436160716892942
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); } }10531067137114902367
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); } }10091246122912552442
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); } }883850114912172031

# Replace symbols in text ~40 symbols

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Short Naive (and wrong) replace symbols with std::string find + replacevoid ShortReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) { std::string_view source = "abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >" ; std::vector<std::pair<u8s, std::string_view>> repl = { {'&', "&amp;"}, {'-', ""}, {'<', "&lt;"}, {'>', "&gt;"}, {'\'', "&#39;"}, {'\"', "&quot;"} }; auto repl_all = [](std::string& str, char s, std::string_view repl) { size_t start_pos = 0; while((start_pos = str.find(s, start_pos)) != std::string::npos) { str.replace(start_pos, 1, repl); start_pos += repl.length(); } }; for (auto _: state) { std::string result{source}; for (const auto& r : repl) { repl_all(result, r.first, r.second); } #ifdef CHECK_RESULT if (result != "abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;" ) { state.SkipWithError("not equal"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(repl); } }165158307330516
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); } }318338358423774
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); } }152160313350439
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); } }163204276312389
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); } }187193345418439
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); } }126150212252292
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); } }147140294325320

# Replace All Str To Longer Size

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
replace bb to ---- in std::string|64template<size_t Long> void ReplaceAllLongerStdString(benchmark::State& state) { std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a"; std::string_view pattern = "bb"; std::string_view repl = "----"; std::string big_source, big_sample; for (int i = 0; i < Long; i++) { big_source += source; big_sample += sample; } for (auto _: state) { std::string result{big_source}; size_t start_pos = 0; while((start_pos = result.find(pattern, start_pos)) != std::string::npos) { result.replace(start_pos, pattern.length(), repl); start_pos += repl.length(); } #ifdef CHECK_RESULT if (result != big_sample) { state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(pattern); benchmark::DoNotOptimize(repl); } }152157219239394
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); } }5384927507961197
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); } }1070990135215222361
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); } }23842325302831214872
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); } }607260647680789411862
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); } }129145217230306
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); } }430475609671953
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); } }825862105211191732
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); } }16131756187820323256
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); } }31743286354838676323
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, "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); } }94.587.1162200162
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, "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); } }299267363463527
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, "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); } }69665178910751213
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, "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); } }15461455158721672565
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, "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); } }31762933291243575315

# Replace All Str To Same Size

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
replace bb to -- in std::string|64template<size_t Long> void ReplaceAllEqualStdString(benchmark::State& state) { std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba"; std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a"; std::string_view pattern = "bb"; std::string_view repl = "--"; std::string big_source, big_sample; for (int i = 0; i < Long; i++) { big_source += source; big_sample += sample; } for (auto _: state) { std::string result{big_source}; size_t start_pos = 0; while((start_pos = result.find(pattern, start_pos)) != std::string::npos) { result.replace(start_pos, pattern.length(), repl); start_pos += repl.length(); } #ifdef CHECK_RESULT if (result != big_sample) { state.SkipWithError("error in replace"); break; } #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); benchmark::DoNotOptimize(pattern); benchmark::DoNotOptimize(repl); } }106111181201256
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); } }382366480517819
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); } }7247388269241546
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); } }14571431159817712954
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); } }28552775382235115749
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); } }94.195.4174189206
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); } }282282429434650
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); } }5205317337791202
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); } }10691029137714652364
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); } }21002008265528104378
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); } }76.183.6150166147
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); } }234265325375472
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); } }439501519621912
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); } }8541004101011121712
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); } }16461944174121252832

# Hash Map insert and find

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
hashStrMapA<size_t> emplace & find stringa;void HashMapSimStr(benchmark::State& state) { for (auto _: state) { hashStrMapA<size_t> store; for (size_t idx = 0; idx < bs_sim.size(); idx++) { store.try_emplace(bs_sim[idx], idx); } #ifdef CHECK_RESULT if (store.size() != bs_sim.size()) { state.SkipWithError("bad inserts"); } #endif for (size_t idx = 0; idx < bs_sim.size(); idx++) { auto find = store.find(bs_sim[idx]); size_t res = find->second; #ifdef CHECK_RESULT if (res != idx) { state.SkipWithError("bad find"); } #endif benchmark::DoNotOptimize(res); } } } >> Вставляем в hashStrMapA 10000 stringa длиной от 30 до 50 символов, а потом ищем их в ней We insert 10,000 strings of length from 30 to 50 characters into hashStrMapA, and then search for them in it.36060143698007402036644282533227313
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_map35235753645916559876058980023640106
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 ssa35935133708079343970640821783237505
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_view40683994189102706885563035344135414

# Build Full Func Name

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
Build func full name std::string;std::string build_full_name_std() const { std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]}; str += " "; str += std_name; str += "("; bool add_comma = false; for (const auto& param : params) { if (add_comma) { str += ", "; } if (param.optional) { str += "["; } param.allowed_types.to_stdstr(str); if (param.optional) { str += "]"; } add_comma = true; } if (unlim_params) { if (add_comma) { str += ", "; } str += "..."; } str += ")"; //std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n"; return str; } >> Обыденная задача, подобные часто могут встретится в работе: По неким данным сгенерировать текст. В этом случае по данным о неких функциях сформировать их полное имя с типами параметров и возвращаемого значения. Алгоритм на std::string. A common task, similar to this one, can often be encountered in work: Generate text from given data. In this case, using data on certain functions, generate their full names with parameter types and return values. The algorithm uses std::string.678853150616043605
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 += + + +.776912158216973610
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 <<2611250281671005412391
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.4844597908791610
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.6106278779821874

# Make Upper

Benchmark nameCommentXeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13Xeon E5-2682 v4, Windows 10, Clang-19Xeon E5-2682 v4, Windows 10, MSVC-19Xeon E5-2682 v4, WASM Chrome 143, Clang-21
To upper case std::wstringvoid UpperCaseStd(benchmark::State& state) { static const auto& loc = std::locale("en_US.utf8"); for (auto _: state) { std::wstring test = L"TestПриветTest"; benchmark::DoNotOptimize(test); std::transform(test.begin(), test.end(), test.begin(), [](wchar_t s) { return std::toupper(s, loc); }); benchmark::DoNotOptimize(test); #ifdef CHECK_RESULT if (test != L"TESTПРИВЕТTEST") { state.SkipWithError("Bad upper case"); } #endif } }15116615261424203
To upper case lstringw<15>void UpperCaseSim(benchmark::State& state) { for (auto _: state) { lstringw<15> test = L"TestПриветTest"; benchmark::DoNotOptimize(test); test.upper(); benchmark::DoNotOptimize(test); #ifdef CHECK_RESULT if (test != L"TESTПРИВЕТTEST") { state.SkipWithError("Bad upper case"); } #endif } }41.442.040.350.563.5