perf: optimize GenerateRandomString() (#66)

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:53:42 +02:00 committed by GitHub
parent 723fd8cbef
commit 19a0a3a359
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -419,18 +419,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;
} }