Skip to content

Instantly share code, notes, and snippets.

@eao197
Created May 15, 2025 12:51
Show Gist options
  • Save eao197/8c562f62877142d27f46a2a5c51ec240 to your computer and use it in GitHub Desktop.
Save eao197/8c562f62877142d27f46a2a5c51ec240 to your computer and use it in GitHub Desktop.
Замеры производительности emplace/try_emplace для std::unordered_map
#include <array>
#include <chrono>
#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
namespace test
{
using key_t = std::pair<std::size_t, std::string>;
using values_map_t = std::unordered_map< key_t, int >;
} /* namespace test */
template<>
struct std::hash<test::key_t>
{
std::size_t
operator()(const test::key_t & k) const noexcept
{
return std::hash<std::size_t>{}(k.first) + 0x9e3779b9 +
std::hash<std::string>{}(k.second);
}
};
namespace test
{
const std::array<std::string, 10> strings{
"a rather long string value to avoid small string optimization 001",
"a rather long string value to avoid small string optimization 002",
"a rather long string value to avoid small string optimization 003",
"a rather long string value to avoid small string optimization 004",
"a rather long string value to avoid small string optimization 005",
"a rather long string value to avoid small string optimization 006",
"a rather long string value to avoid small string optimization 007",
"a rather long string value to avoid small string optimization 008",
"a rather long string value to avoid small string optimization 009",
"a rather long string value to avoid small string optimization 010"
};
const std::size_t map_size = 100;
const std::size_t insertions = 10'000'000;
[[nodiscard]]
values_map_t
make_values()
{
values_map_t result;
int value = 0;
for(std::size_t i = 0; i != map_size; ++i, ++value)
{
const std::string & sk = strings[i % std::size(strings)];
result.emplace(key_t{ i, sk }, value);
}
return result;
}
[[nodiscard]]
std::pair<std::size_t, const std::string &>
keys_from_i(std::size_t i)
{
return { i % map_size, strings[i % std::size(strings)] };
}
void
simple_emplace(
values_map_t & to)
{
int value = 0;
for(std::size_t i = 0; i != insertions; ++i, ++value)
{
const auto keys = keys_from_i(i);
to.emplace(key_t{ keys.first, keys.second }, value);
}
}
void
try_emplace(
values_map_t & to)
{
int value = 0;
for(std::size_t i = 0; i != insertions; ++i, ++value)
{
const auto keys = keys_from_i(i);
to.try_emplace(key_t{ keys.first, keys.second }, value);
}
}
void
emplace_via_piecewise_construct(
values_map_t & to)
{
int value = 0;
for(std::size_t i = 0; i != insertions; ++i, ++value)
{
const auto keys = keys_from_i(i);
to.emplace(
std::piecewise_construct,
std::forward_as_tuple(keys.first, keys.second),
std::forward_as_tuple(value) );
}
}
} /* namespace test */
class duration_meter
{
const char * _name;
const std::chrono::high_resolution_clock::time_point _started_at;
public:
duration_meter( const char * name )
: _name{ name }
, _started_at{ std::chrono::high_resolution_clock::now() }
{}
~duration_meter()
{
const auto f = std::chrono::high_resolution_clock::now();
std::cout << "*** " << _name << ": "
<< std::chrono::duration_cast<std::chrono::microseconds>(
f - _started_at ).count()
<< "us *** " << std::endl;
}
};
template<typename Lambda>
decltype(auto)
measure( const char * name, Lambda && lambda )
{
duration_meter meter{ name };
return lambda();
}
using namespace test;
int main()
{
auto values = make_values();
measure( "simple_emplace", [&values]() {
simple_emplace(values);
});
std::cout << "values size: " << values.size() << std::endl;;
measure( "try_emplace", [&values]() {
try_emplace(values);
});
std::cout << "values size: " << values.size() << std::endl;;
measure( "emplace_via_piecewise_construct", [&values]() {
emplace_via_piecewise_construct(values);
});
std::cout << "values size: " << values.size() << std::endl;;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment