Skip to content

Commit

Permalink
2023: use a better hash combiner for Pos
Browse files Browse the repository at this point in the history
  • Loading branch information
yut23 committed Mar 22, 2024
1 parent f234ff5 commit 12676ec
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 3 deletions.
8 changes: 5 additions & 3 deletions 2023/src/lib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LIB_HPP_0IZKV7KG
#define LIB_HPP_0IZKV7KG

#include "util/hash.hpp" // for make_hash
#include <algorithm> // for max, min
#include <cassert> // for assert
#include <compare> // for strong_ordering
Expand Down Expand Up @@ -417,9 +418,10 @@ std::ifstream parse_args(int argc, char **argv) {
template <>
struct std::hash<aoc::Pos> {
std::size_t operator()(const aoc::Pos &pos) const noexcept {
std::size_t h1 = std::hash<int>{}(pos.x);
std::size_t h2 = std::hash<int>{}(pos.y);
return h1 ^ (h2 << 1);
// random number
std::size_t seed = 0xbedb5bb0b473b6b7ull;
util::make_hash(seed, pos.x, pos.y);
return seed;
}
};

Expand Down
77 changes: 77 additions & 0 deletions 2023/src/util/hash.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/******************************************************************************
* File: hash.hpp
*
* Author: Eric T. Johnson
* Created: 2024-03-18
* Description: Hashing utilities
*****************************************************************************/

#ifndef HASH_HPP_QKWFTL3O
#define HASH_HPP_QKWFTL3O

#include "util/concepts.hpp" // for Hashable
#include <algorithm> // for max // IWYU pragma: keep
#include <cstdint> // for uint64_t
#include <cstdlib> // for size_t
#include <functional> // for hash
// IWYU pragma: no_include <unordered_map> // for operator==

namespace util {

namespace hash {
/**
* Combiner from MurmurHash2, 64-bit version by Austin Appleby
* (MurmurHash64A()). Placed in the public domain.
*/
void murmurhash2_combine(std::size_t &h, std::size_t k) {
const std::uint64_t m = 0xc6a4a7935bd1e995ull;
const int r = 47;

k *= m;
k ^= k >> r;
k *= m;

h ^= k;
h *= m;
}

void murmurhash2_finalize(std::size_t &h) {
const std::uint64_t m = 0xc6a4a7935bd1e995ull;
const int r = 47;

h ^= h >> r;
h *= m;
h ^= h >> r;
}

template <util::concepts::Hashable... Ts>
void make_hash(std::size_t &seed, const Ts... components) {
(hash::murmurhash2_combine(seed, std::hash<Ts>{}(components)), ...);
hash::murmurhash2_finalize(seed);
}

/**
* From https://artificial-mind.net/blog/2021/10/09/unordered-map-badness.
*
* > A badness of roughly 0 means that the current bucket distribution is close
* > to optimal. 1 means that on average 100% more comparisons than optimal are
* > required.
*/
template <class Map>
double unordered_map_badness(Map const &map) {
auto const lambda = map.size() / double(map.bucket_count());

auto cost = 0.;
for (auto const &[k, _] : map)
cost += map.bucket_size(map.bucket(k));
cost /= map.size();

return std::max(0., cost / (1 + lambda) - 1);
}
} // namespace hash

using hash::make_hash;

} // namespace util

#endif /* end of include guard: HASH_HPP_QKWFTL3O */

0 comments on commit 12676ec

Please sign in to comment.