diff --git a/CMakeLists.txt b/CMakeLists.txt index 624bfa4..40fa1ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ if (PHMAP_BUILD_EXAMPLES) add_executable(ex_knucleotide examples/knucleotide.cc phmap.natvis) add_executable(ex_dump_load examples/dump_load.cc phmap.natvis) add_executable(ex_btree examples/btree.cc phmap.natvis) + add_executable(ex_hash_bench examples/hash_bench.cc phmap.natvis) add_executable(ex_matt examples/matt.cc phmap.natvis) add_executable(ex_mt_word_counter examples/mt_word_counter.cc phmap.natvis) diff --git a/examples/hash_bench.cc b/examples/hash_bench.cc new file mode 100644 index 0000000..deeef3f --- /dev/null +++ b/examples/hash_bench.cc @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#define PHMAP_ALLOCATOR_NOTHROW 1 +#include + +// this is probably the fastest high quality 64bit random number generator that exists. +// Implements Small Fast Counting v4 RNG from PractRand. +class sfc64 { +public: + using result_type = uint64_t; + + // no copy ctors so we don't accidentally get the same random again + sfc64(sfc64 const&) = delete; + sfc64& operator=(sfc64 const&) = delete; + + sfc64(sfc64&&) = default; + sfc64& operator=(sfc64&&) = default; + + sfc64(std::array const& _state) + : m_a(_state[0]) + , m_b(_state[1]) + , m_c(_state[2]) + , m_counter(_state[3]) {} + + static constexpr uint64_t(min)() { + return (std::numeric_limits::min)(); + } + static constexpr uint64_t(max)() { + return (std::numeric_limits::max)(); + } + + sfc64() + : sfc64(UINT64_C(0x853c49e6748fea9b)) {} + + sfc64(uint64_t _seed) + : m_a(_seed) + , m_b(_seed) + , m_c(_seed) + , m_counter(1) { + for (int i = 0; i < 12; ++i) { + operator()(); + } + } + + void seed() { + *this = sfc64{std::random_device{}()}; + } + + uint64_t operator()() noexcept { + auto const tmp = m_a + m_b + m_counter++; + m_a = m_b ^ (m_b >> right_shift); + m_b = m_c + (m_c << left_shift); + m_c = rotl(m_c, rotation) + tmp; + return tmp; + } + + std::array state() const { + return {{m_a, m_b, m_c, m_counter}}; + } + + void state(std::array const& s) { + m_a = s[0]; + m_b = s[1]; + m_c = s[2]; + m_counter = s[3]; + } + +private: + template + T rotl(T const x, int k) { + return (x << k) | (x >> (8 * sizeof(T) - k)); + } + + static constexpr int rotation = 24; + static constexpr int right_shift = 11; + static constexpr int left_shift = 3; + uint64_t m_a; + uint64_t m_b; + uint64_t m_c; + uint64_t m_counter; +}; + +static inline std::string to_str(uint64_t x) { + std::string res(4, '1'); + x = (x >> 48) ^ (x >> 32) ^ (x >> 16) ^ x; // combine 64 bits > 16 lsb + for (size_t i=0; i<4; ++i) { + res[i] = 'a' + (x & 0xF); + x >>= 4; + } + return res; +} + +int main() +{ + using Map = phmap::flat_hash_map; + Map map; + map.reserve((size_t)(65536 * 1.1)); // we will create a maximun of 65536 different strings + + sfc64 rng(123); + constexpr size_t const n = 50000000; + for (size_t i = 0; i < n; ++i) { + auto s = to_str(rng()); + map[s]++; + map[s]++; + map[s]++; + map[s]++; + map[s]++; + map[s]++; + map[s]++; + map[s]++; + map[s]++; + map[s]++; + } + + uint64_t cnt = 0; + for (const auto& s : map) { + if (++cnt == 6) break; + std::cout << s.first << ": " << s.second << '\n'; + } + + return 0; +}