FE 0.13.1
Header-only C++ frontend library
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
7namespace fe {
8
9static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "unsupported sizeof(size_t)");
10
11/// @name Bit Mixers
12/// These finalizers scramble a single word.
13/// They are bijective, i.e., they don't introduce any collisions on their own - they merely spread the input bits.
14///@{
15
16/// [MurmurHash3](https://en.wikipedia.org/wiki/MurmurHash)'s 32-bit finalizer `fmix32`.
17constexpr uint32_t murmur3(uint32_t h) noexcept {
18 h ^= h >> 16;
19 h *= UINT32_C(0x85ebca6b);
20 h ^= h >> 13;
21 h *= UINT32_C(0xc2b2ae35);
22 h ^= h >> 16;
23 return h;
24}
25
26/// [SplitMix64](https://prng.di.unimi.it/splitmix64.c)'s 64-bit finalizer.
27constexpr uint64_t splitmix64(uint64_t h) noexcept {
28 h ^= h >> 30;
29 h *= UINT64_C(0xbf58476d1ce4e5b9);
30 h ^= h >> 27;
31 h *= UINT64_C(0x94d049bb133111eb);
32 h ^= h >> 31;
33 return h;
34}
35
36/// Mixes @p h with murmur3 or splitmix64 - whichever matches `sizeof(size_t)`.
37constexpr size_t hash(size_t h) noexcept {
38 if constexpr (sizeof(size_t) == 4)
39 return size_t(murmur3(uint32_t(h)));
40 else
41 return size_t(splitmix64(uint64_t(h)));
42}
43///@}
44
45/// @name FNV-1 Hash
46/// See [Wikipedia](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash).
47/// Use hash_begin to seed a hash chain and hash_combine to fold in one value after another:
48/// ```
49/// auto h = fe::hash_begin(x);
50/// for (auto elem : elems) h = fe::hash_combine(h, elem);
51/// ```
52/// @note These hashes are *not* stable:
53/// they differ between 32- and 64-bit builds and may change between fe releases.
54/// Never serialize them and never rely on the iteration order they induce.
55///@{
56
57// clang-format off
58/// FNV-1 [magic numbers](http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-var) for `sizeof(size_t)`.
59inline constexpr size_t fnv1_offset = sizeof(size_t) == 4 ? size_t(UINT32_C(2166136261)) : size_t(UINT64_C(14695981039346656037));
60inline constexpr size_t fnv1_prime = sizeof(size_t) == 4 ? size_t(UINT32_C( 16777619)) : size_t(UINT64_C( 1099511628211));
61// clang-format on
62
63/// Seeds a hash chain with the FNV-1 offset basis.
64constexpr size_t hash_begin() noexcept { return fnv1_offset; }
65
66/// Mixes @p v into @p seed word-wise, reusing the FNV-1 prime as multiplier.
67template<std::integral T>
68constexpr size_t hash_combine(size_t seed, T v) noexcept {
69 return hash(seed ^ (size_t(v) * fnv1_prime));
70}
71
72/// Shorthand for `hash_combine(hash_begin(), v)`.
73template<std::integral T>
74constexpr size_t hash_begin(T v) noexcept {
75 return hash_combine(hash_begin(), v);
76}
77///@}
78
79} // namespace fe
Definition algo.h:17
constexpr size_t hash(size_t h) noexcept
Mixes h with murmur3 or splitmix64 - whichever matches sizeof(size_t).
Definition hash.h:37
constexpr size_t fnv1_offset
FNV-1 magic numbers for sizeof(size_t).
Definition hash.h:59
constexpr size_t hash_begin() noexcept
Seeds a hash chain with the FNV-1 offset basis.
Definition hash.h:64
constexpr size_t fnv1_prime
Definition hash.h:60
constexpr uint32_t murmur3(uint32_t h) noexcept
MurmurHash3's 32-bit finalizer fmix32.
Definition hash.h:17
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:68
constexpr uint64_t splitmix64(uint64_t h) noexcept
SplitMix64's 64-bit finalizer.
Definition hash.h:27