1#ifndef MINIMAL_PERFECT_HASH_HH
2#define MINIMAL_PERFECT_HASH_HH
59template<
size_t M,
typename Hash>
62 static_assert(std::has_single_bit(M));
63 static constexpr auto M2 = M / 2;
65 std::array<uint8_t, M >
tab1;
66 std::array<uint8_t, M2>
tab2;
67 [[no_unique_address]] Hash
hash;
69 [[nodiscard]]
constexpr uint8_t
lookupIndex(
const auto& key)
const {
70 const uint32_t h =
hash(key);
71 const uint8_t d =
tab1[h % M];
72 if ((d & 0x80) == 0) {
75 return tab2[(h >> (d & 31)) %
M2];
80template<
size_t N,
typename Hash,
typename GetKey>
81[[nodiscard]]
constexpr auto create(
const Hash& hash,
const GetKey& getKey)
83 static_assert(N < 128);
84 constexpr size_t M = std::bit_ceil(N);
85 constexpr auto bucket_max = size_t(2 *
cstd::sqrt(M));
91 std::array<static_vector<uint8_t, bucket_max>, r.tab1.size()> buckets;
93 buckets[hash(getKey(i)) % r.tab1.size()].push_back(uint8_t(i));
99 if (x.size() != y.size()) {
100 return x.size() > y.size();
103 return std::lexicographical_compare(x.begin(), x.end(),
108 constexpr auto UNUSED = uint8_t(-1);
110 for (
const auto& bucket : buckets) {
111 auto const bSize = bucket.size();
112 if (bSize == 0)
break;
113 auto hash1 = hash(getKey(bucket[0])) % r.tab1.size();
116 r.tab1[hash1] = bucket[0];
123 while (bucket_slots.
size() < bSize) {
124 auto hash2 = hash(getKey(bucket[bucket_slots.
size()]));
125 assert((hash2 % r.tab1.size()) == hash1);
126 auto slot = (hash2 >> shift) % r.tab2.size();
127 if (r.tab2[slot] != UNUSED ||
contains(bucket_slots, slot)) {
130 bucket_slots.
clear();
137 r.tab1[hash1] = shift | 0x80;
138 for (
auto i :
xrange(bSize)) {
139 r.tab2[bucket_slots[i]] = bucket[i];
constexpr size_t size() const
constexpr void push_back(const T &a)
constexpr auto create(const Hash &hash, const GetKey &getKey)
constexpr double sqrt(double x)
constexpr void fill(ForwardRange &&range, const T &value)
constexpr void replace(ForwardRange &&range, const T &old_value, const T &new_value)
constexpr void sort(RandomAccessRange &&range)
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
std::array< uint8_t, M > tab1
std::array< uint8_t, M2 > tab2
constexpr uint8_t lookupIndex(const auto &key) const
constexpr auto xrange(T e)