perf: optimize GenerateRandomString()

The previous implementation used an std::stringstream to concatenate
the generated random string.

The new one uses a simple preallocated std::string, as the size of the
output is already known - it is the length parameter.

It also uses std::generate_n() instead of an explicit loop, making the
code more concise and potentially faster, as no calls to
std::string::operator+= are needed.

Calling GenerateRandomString(1'000'000) with the std::stringstream-based
implementation allocated 16 times, for a total of 3'173'516 bytes.
The new one cuts this down to 4 allocs, for a total of 1'076'864 bytes.
This commit is contained in:
Andrea Pappacoda 2022-08-26 12:29:10 +02:00
parent fb0c36f714
commit f7f6f48f4d
No known key found for this signature in database
GPG key ID: 4A9208A2455077A7

View file

@ -417,18 +417,20 @@ std::string GenerateRandomString(size_t length)
return GenerateRandomString(length, kCharacters); return GenerateRandomString(length, kCharacters);
} }
std::string GenerateRandomString(size_t length, std::string_view characters) std::string GenerateRandomString(const size_t length, const std::string_view characters)
{ {
assert(!characters.empty()); assert(!characters.empty());
std::stringstream result; std::string result;
result.resize(length);
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
std::uniform_int_distribution<decltype(characters.size())> index_dist(0, characters.size() - 1); std::uniform_int_distribution<decltype(characters.size())> index_dist(0, characters.size() - 1);
for (uint32_t i = 0; i < length; ++i) std::generate_n(
{ result.begin(),
result << characters[index_dist(gen)]; length,
} [&] { return characters[index_dist(gen)]; }
);
return result.str(); return result;
} }