Created
September 15, 2020 00:51
-
-
Save BillyONeal/b26b6af908e4230db222cf1502bb7170 to your computer and use it in GitHub Desktop.
Herb Sutter's basic_string const& vs. && etc. benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <stdlib.h> | |
#include <stddef.h> | |
#include <iostream> | |
#include <iomanip> | |
#include <string> | |
#include <vector> | |
#include <chrono> | |
#include <random> | |
using namespace std; | |
using namespace std::chrono; | |
using sstring = std::string; | |
//------------------------------------------------------------------------------ | |
struct option1 | |
{ | |
static void print() { cout << "Option 1: const string&\n"; } | |
sstring name_; | |
void set_name(const sstring &name) { name_ = name; } | |
}; | |
struct option2 | |
{ | |
static void print() { cout << "Option 2: const string& + string&& overloads\n"; } | |
sstring name_; | |
void set_name(const sstring &name) { name_ = name; } | |
void set_name(sstring &&name) /*noexcept*/ { name_ = std::move(name); } | |
}; | |
struct option3 | |
{ | |
static void print() { cout << "Option 3: string\n"; } | |
sstring name_; | |
void set_name(sstring name) /*noexcept*/ { name_ = std::move(name); } | |
}; | |
struct option4 | |
{ | |
static void print() { cout << "Option 4: String&& perfect forwarding\n"; } | |
sstring name_; | |
template <class String> | |
void set_name(String &&name) | |
/*noexcept(std::is_nothrow_assignable<sstring&, String>::value)*/ | |
{ | |
name_ = std::forward<String>(name); | |
} | |
}; | |
//------------------------------------------------------------------------------ | |
static auto baseline = 0ll; | |
template <class Code> | |
void test(int N, sstring description, const Code &code) | |
{ | |
auto start = high_resolution_clock::now(); | |
while (N--) | |
{ | |
code(); | |
} | |
auto ms = duration_cast<milliseconds>(high_resolution_clock::now() - start).count(); | |
if (baseline == 0) | |
baseline = ms; | |
cout << setw(5) << ms << "ms [" << setw(5) << setprecision(3) << ((double)ms / baseline) << "] - " | |
<< description << endl; | |
} | |
//------------------------------------------------------------------------------ | |
std::mt19937 gen(1792); | |
template <int N, int M = 100> | |
int rand() | |
{ | |
static auto v = [] { | |
std::uniform_int_distribution<> dis(1, N); | |
vector<int> vec(M); // pre-roll M random numbers from 1 to N inclusive | |
for (auto &&e : vec) | |
e = dis(gen); | |
return vec; | |
}(); | |
static auto i = 0; | |
return v[i = (i + 1) % M]; // cough up next pre-rolled number on each call | |
} | |
template <class E> | |
void test_option() | |
{ | |
#define N 100000 | |
#define M 100 | |
E::print(); | |
{ | |
vector<E> v(M); | |
for (auto &&e : v) | |
e.set_name(sstring(rand<10>(), 'a')); | |
test(N, "lvalue - length 1-10 (rotation)", [&] { | |
auto temp = v.front().name_; | |
for (auto i = 1u; i < v.size(); ++i) | |
v[i - 1].set_name(v[i].name_); | |
v.back().set_name(temp); | |
}); | |
} | |
{ | |
vector<E> v(M); | |
for (auto &&e : v) | |
e.set_name(sstring(rand<50>(), 'a')); | |
test(N, "lvalue - length 1-50 (rotation)", [&] { | |
auto temp = v.front().name_; | |
for (auto i = 1u; i < v.size(); ++i) | |
v[i - 1].set_name(v[i].name_); | |
v.back().set_name(temp); | |
}); | |
} | |
{ | |
vector<E> v(M); | |
for (auto &&e : v) | |
e.set_name(sstring(rand<10>(), 'a')); | |
test(N, "xvalue - length 1-10 (rotation)", [&] { | |
auto temp = move(v.front().name_); | |
for (auto i = 1u; i < v.size(); ++i) | |
v[i - 1].set_name(move(v[i].name_)); | |
v.back().set_name(move(temp)); | |
}); | |
} | |
{ | |
vector<E> v(M); | |
for (auto &&e : v) | |
e.set_name(sstring(rand<50>(), 'a')); | |
test(N, "xvalue - length 1-50 (rotation)", [&] { | |
auto temp = move(v.front().name_); | |
for (auto i = 1u; i < v.size(); ++i) | |
v[i - 1].set_name(move(v[i].name_)); | |
v.back().set_name(move(temp)); | |
}); | |
} | |
{ | |
vector<E> v(M); | |
vector<char *> vs(M); | |
for (auto &&e : vs) | |
{ | |
auto size = rand<10>(); | |
e = new char[size]; | |
for (auto i = 0; i < size - 2; ++i) | |
e[i] = 'a'; | |
e[size - 1] = '\0'; | |
} | |
test(N, "char* string - length 1-10", [&] { | |
for (auto &&e : v) | |
e.set_name(vs[rand<M>() - 1]); | |
}); | |
} | |
{ | |
vector<E> v(M); | |
vector<char *> vs(M); | |
for (auto &&e : vs) | |
{ | |
auto size = rand<50>(); | |
e = new char[size]; | |
for (auto i = 0; i < size - 2; ++i) | |
e[i] = 'a'; | |
e[size - 1] = '\0'; | |
} | |
test(N, "char* string - length 1-50", [&] { | |
for (auto &&e : v) | |
e.set_name(vs[rand<M>() - 1]); | |
}); | |
} | |
cout << endl; | |
} | |
template class basic_string<char>; | |
//------------------------------------------------------------------------------ | |
int main() | |
{ | |
test_option<option1>(); | |
test_option<option2>(); | |
test_option<option3>(); | |
test_option<option4>(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment