Skip to content

Instantly share code, notes, and snippets.

@BillyONeal
Created September 15, 2020 00:51
Show Gist options
  • Save BillyONeal/b26b6af908e4230db222cf1502bb7170 to your computer and use it in GitHub Desktop.
Save BillyONeal/b26b6af908e4230db222cf1502bb7170 to your computer and use it in GitHub Desktop.
Herb Sutter's basic_string const& vs. && etc. benchmark
#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