FE
0.15.0
A C++23 toolkit for writing compiler/interpreter frontends.
Toggle main menu visibility
Loading...
Searching...
No Matches
hash.h
Go to the documentation of this file.
1
#pragma once
2
3
#include <concepts>
4
#include <cstddef>
5
#include <cstdint>
6
7
#include <algorithm>
8
#include <array>
9
#include <bit>
10
#include <string_view>
11
12
namespace
fe
{
13
14
static_assert
(
sizeof
(size_t) == 4 ||
sizeof
(size_t) == 8,
"unsupported sizeof(size_t)"
);
15
16
/// @name Bit Mixers
17
/// These finalizers scramble a single word.
18
/// They are bijective, i.e., they don't introduce any collisions on their own - they merely spread the input bits.
19
///@{
20
21
/// [MurmurHash3](https://en.wikipedia.org/wiki/MurmurHash)'s 32-bit finalizer `fmix32`.
22
constexpr
uint32_t
murmur3
(uint32_t h)
noexcept
{
23
h ^= h >> 16;
24
h *= UINT32_C(0x85ebca6b);
25
h ^= h >> 13;
26
h *= UINT32_C(0xc2b2ae35);
27
h ^= h >> 16;
28
return
h;
29
}
30
31
/// [SplitMix64](https://prng.di.unimi.it/splitmix64.c)'s 64-bit finalizer.
32
constexpr
uint64_t
splitmix64
(uint64_t h)
noexcept
{
33
h ^= h >> 30;
34
h *= UINT64_C(0xbf58476d1ce4e5b9);
35
h ^= h >> 27;
36
h *= UINT64_C(0x94d049bb133111eb);
37
h ^= h >> 31;
38
return
h;
39
}
40
41
/// Mixes @p h with murmur3 or splitmix64 - whichever matches `sizeof(size_t)`.
42
constexpr
size_t
hash
(
size_t
h)
noexcept
{
43
if
constexpr
(
sizeof
(size_t) == 4)
44
return
size_t
(
murmur3
(uint32_t(h)));
45
else
46
return
size_t(
splitmix64
(uint64_t(h)));
47
}
48
///@}
49
50
/// @name FNV-1 Hash
51
/// See [Wikipedia](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash).
52
/// Use hash_begin to seed a hash chain and hash_combine to fold in one value after another:
53
/// ```
54
/// auto h = fe::hash_begin(x);
55
/// for (auto elem : elems) h = fe::hash_combine(h, elem);
56
/// ```
57
/// @note These hashes are *not* stable:
58
/// they differ between 32- and 64-bit builds and may change between fe releases.
59
/// Never serialize them and never rely on the iteration order they induce.
60
///@{
61
62
// clang-format off
63
/// FNV-1 [magic numbers](http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-var) for `sizeof(size_t)`.
64
inline
constexpr
size_t
fnv1_offset
=
sizeof
(size_t) == 4 ?
size_t
(UINT32_C(2166136261)) : size_t(UINT64_C(14695981039346656037));
65
inline
constexpr
size_t
fnv1_prime
=
sizeof
(size_t) == 4 ?
size_t
(UINT32_C( 16777619)) : size_t(UINT64_C( 1099511628211));
66
// clang-format on
67
68
/// Seeds a hash chain with the FNV-1 offset basis.
69
constexpr
size_t
hash_begin
() noexcept {
return
fnv1_offset
; }
70
71
/// Mixes @p v into @p seed word-wise, reusing the FNV-1 prime as multiplier.
72
template
<std::
int
egral T>
73
constexpr
size_t
hash_combine
(
size_t
seed, T v)
noexcept
{
74
return
hash
(seed ^ (
size_t
(v) *
fnv1_prime
));
75
}
76
77
/// Shorthand for `hash_combine(hash_begin(), v)`.
78
template
<std::
int
egral T>
79
constexpr
size_t
hash_begin
(T v)
noexcept
{
80
return
hash_combine
(
hash_begin
(), v);
81
}
82
83
/// Mixes the bytes of @p sv into @p seed a machine word at a time.
84
constexpr
size_t
hash_combine
(
size_t
seed, std::string_view sv)
noexcept
{
85
auto
h = seed ^ (sv.size() *
fnv1_prime
);
// the size too, or "a" and "a\0" would agree
86
87
for
(; sv.size() >=
sizeof
(
size_t
); sv.remove_prefix(
sizeof
(
size_t
))) {
88
std::array<char,
sizeof
(size_t)> bytes;
89
std::copy_n(sv.begin(), bytes.size(), bytes.begin());
90
h = (h ^ std::bit_cast<size_t>(bytes)) *
fnv1_prime
;
91
}
92
93
if
(!sv.empty()) {
94
std::array<char,
sizeof
(size_t)> bytes{};
// the last word is a partial one, so zero-pad it
95
std::copy(sv.begin(), sv.end(), bytes.begin());
96
h = (h ^ std::bit_cast<size_t>(bytes)) *
fnv1_prime
;
97
}
98
99
return
hash
(h);
// one finalizer for the whole range instead of one per word
100
}
101
102
/// Shorthand for `hash_combine(hash_begin(), sv)`.
103
constexpr
size_t
hash_begin
(std::string_view sv)
noexcept
{
return
hash_combine
(
hash_begin
(), sv); }
104
///@}
105
106
}
// namespace fe
fe
Definition
algo.h:17
fe::hash
constexpr size_t hash(size_t h) noexcept
Mixes h with murmur3 or splitmix64 - whichever matches sizeof(size_t).
Definition
hash.h:42
fe::fnv1_offset
constexpr size_t fnv1_offset
FNV-1 magic numbers for sizeof(size_t).
Definition
hash.h:64
fe::hash_begin
constexpr size_t hash_begin() noexcept
Seeds a hash chain with the FNV-1 offset basis.
Definition
hash.h:69
fe::fnv1_prime
constexpr size_t fnv1_prime
Definition
hash.h:65
fe::murmur3
constexpr uint32_t murmur3(uint32_t h) noexcept
MurmurHash3's 32-bit finalizer fmix32.
Definition
hash.h:22
fe::hash_combine
constexpr size_t hash_combine(size_t seed, T v) noexcept
Mixes v into seed word-wise, reusing the FNV-1 prime as multiplier.
Definition
hash.h:73
fe::splitmix64
constexpr uint64_t splitmix64(uint64_t h) noexcept
SplitMix64's 64-bit finalizer.
Definition
hash.h:32
fe
hash.h
Generated by
1.18.0