P4C
The P4 Compiler
Loading...
Searching...
No Matches
hash.h
1#ifndef LIB_HASH_H_
2#define LIB_HASH_H_
3
4#include <cstddef>
5#include <cstdint>
6#include <cstring>
7#include <limits>
8#include <memory>
9#include <string>
10#include <string_view>
11#include <tuple>
12#include <type_traits>
13
14namespace P4::Util {
15
16namespace Detail {
17constexpr uint32_t PRIME32_1 = UINT32_C(0x9E3779B1);
18constexpr uint32_t PRIME32_2 = UINT32_C(0x85EBCA77);
19constexpr uint32_t PRIME32_3 = UINT32_C(0xC2B2AE3D);
20
21constexpr uint64_t PRIME64_1 = UINT64_C(11400714785074694791);
22constexpr uint64_t PRIME64_2 = UINT64_C(14029467366897019727);
23constexpr uint64_t PRIME64_3 = UINT64_C(1609587929392839161);
24constexpr uint64_t PRIME64_4 = UINT64_C(9650029242287828579);
25constexpr uint64_t PRIME64_5 = UINT64_C(2870177450012600261);
26
27constexpr uint64_t PRIME_MX1 = UINT64_C(0x165667919E3779F9);
28constexpr uint64_t PRIME_MX2 = UINT64_C(0x9FB21C651E98DF25);
29
30static constexpr uint32_t XXH32_avalanche(uint32_t hash) {
31 hash ^= hash >> 15;
32 hash *= PRIME32_2;
33 hash ^= hash >> 13;
34 hash *= PRIME32_3;
35 hash ^= hash >> 16;
36 return hash;
37}
38
39static constexpr uint64_t XXH64_avalanche(uint64_t hash) {
40 hash ^= hash >> 33;
41 hash *= PRIME64_2;
42 hash ^= hash >> 29;
43 hash *= PRIME64_3;
44 hash ^= hash >> 32;
45 return hash;
46}
47
48static constexpr uint64_t rotl64(uint64_t X, size_t R) { return (X << R) | (X >> (64 - R)); }
49
50static constexpr uint64_t XXH3_rrmxmx(uint64_t acc, uint64_t len) {
51 acc ^= rotl64(acc, 49) ^ rotl64(acc, 24);
52 acc *= PRIME_MX2;
53 acc ^= (acc >> 35) + len;
54 acc *= PRIME_MX2;
55 return acc ^ (acc >> 28);
56}
57
58template <typename Int>
60 constexpr size_t operator()(const Int &i) const noexcept {
61 static_assert(sizeof(Int) <= 16, "unsupported input type");
62 if constexpr (sizeof(Int) <= 4) {
63 return static_cast<size_t>(XXH32_avalanche(static_cast<uint32_t>(i)));
64 } else if constexpr (sizeof(Int) <= 8) {
65 return static_cast<size_t>(XXH64_avalanche(static_cast<uint64_t>(i)));
66 } else {
67 using unsigned_type = std::make_unsigned_t<Int>;
68 auto const u = static_cast<unsigned_type>(i);
69 auto const hi = static_cast<uint64_t>(u >> sizeof(Int) * 4);
70 auto const lo = static_cast<uint64_t>(u);
71 return static_cast<size_t>(XXH3_rrmxmx(hi, lo));
72 }
73 }
74};
75
76template <typename Float>
78 size_t operator()(const Float &f) const noexcept {
79 static_assert(sizeof(Float) <= 8, "unsupported input type");
80
81 // Ensure 0 and -0 get the same hash value
82 if (f == Float{}) return 0;
83
84 uint64_t u64 = 0;
85 memcpy(&u64, &f, sizeof(Float));
86 return static_cast<size_t>(XXH64_avalanche(u64));
87 }
88};
89
90class StdHasher {
91 public:
92 template <typename T>
93 size_t operator()(const T &t) const noexcept(noexcept(std::hash<T>()(t))) {
94 return std::hash<T>()(t);
95 }
96};
97} // namespace Detail
98
99uint64_t hash(const void *data, std::size_t size);
100
101static inline uint64_t hash_avalanche(uint64_t hash) { return Detail::XXH64_avalanche(hash); }
102
103static inline uint64_t hash_combine(uint64_t lhs, uint64_t rhs) {
104 return Detail::XXH3_rrmxmx(lhs, rhs);
105}
106
107template <typename T>
108auto hash(const T &obj) -> decltype(hash(obj.data(), obj.size())) {
109 return hash(obj.data(), obj.size());
110}
111
122template <class Key, class Enable = void>
123struct Hasher;
124
125struct Hash {
126 template <class T>
127 constexpr size_t operator()(const T &v) const noexcept(noexcept(Hasher<T>()(v))) {
128 return Hasher<T>()(v);
129 }
130
131 template <class T, class... Types>
132 constexpr size_t operator()(const T &t, const Types &...ts) const {
133 return hash_combine((*this)(t), (*this)(ts...));
134 }
135
136 constexpr size_t operator()() const noexcept { return 0; }
137};
138
139template <>
140struct Hasher<bool> {
141 constexpr size_t operator()(bool val) const noexcept {
142 return val ? std::numeric_limits<size_t>::max() : 0;
143 }
144};
145
146template <>
147struct Hasher<unsigned long long> : Detail::IntegerHasher<unsigned long long> {};
148
149template <>
150struct Hasher<signed long long> : Detail::IntegerHasher<signed long long> {};
151
152template <>
153struct Hasher<unsigned long> : Detail::IntegerHasher<unsigned long> {};
154
155template <>
156struct Hasher<signed long> : Detail::IntegerHasher<signed long> {};
157
158template <>
159struct Hasher<unsigned int> : Detail::IntegerHasher<unsigned int> {};
160
161template <>
162struct Hasher<signed int> : Detail::IntegerHasher<signed int> {};
163
164template <>
165struct Hasher<unsigned short> : Detail::IntegerHasher<unsigned short> {};
166
167template <>
168struct Hasher<signed short> : Detail::IntegerHasher<signed short> {};
169
170template <>
171struct Hasher<unsigned char> : Detail::IntegerHasher<unsigned char> {};
172
173template <>
174struct Hasher<signed char> : Detail::IntegerHasher<signed char> {};
175
176template <>
177struct Hasher<char> : Detail::IntegerHasher<char> {};
178
179template <>
180struct Hasher<float> : Detail::FloatHasher<float> {};
181
182template <>
183struct Hasher<double> : Detail::FloatHasher<double> {};
184
185template <>
186struct Hasher<std::string> {
187 size_t operator()(const std::string &val) const {
188 return static_cast<size_t>(hash(val.data(), val.size()));
189 }
190};
191
192template <>
193struct Hasher<std::string_view> {
194 size_t operator()(const std::string_view &val) const {
195 return static_cast<size_t>(hash(val.data(), val.size()));
196 }
197};
198
199template <typename T1, typename T2>
200struct Hasher<std::pair<T1, T2>> {
201 size_t operator()(const std::pair<T1, T2> &val) const { return Hash()(val.first, val.second); }
202};
203template <typename... Types>
204struct Hasher<std::tuple<Types...>> {
205 size_t operator()(const std::tuple<Types...> &val) const { return apply(Hash(), val); }
206};
207
213template <typename T>
214struct Hasher<T *> {
215 // FIXME: better use std::bit_cast from C++20
216 size_t operator()(T *val) const { return Hash()(reinterpret_cast<std::uintptr_t>(val)); }
217};
218
219template <typename T>
220struct Hasher<std::unique_ptr<T>> {
221 size_t operator()(const std::unique_ptr<T> &val) const { return Hash()(val.get()); }
222};
223
224template <typename T>
225struct Hasher<std::shared_ptr<T>> {
226 size_t operator()(const std::shared_ptr<T> &val) const { return Hash()(val.get()); }
227};
228
235
236template <class Iter, class Hash = std::hash<typename std::iterator_traits<Iter>::value_type>>
237uint64_t hash_range(Iter begin, Iter end, uint64_t hash = 0, Hash Hasher = Hash()) {
238 for (; begin != end; ++begin) hash = hash_combine(hash, Hasher(*begin));
239
240 return hash;
241}
242
243template <class Hasher>
244inline size_t hash_combine_generic(const Hasher &) noexcept {
245 return 0;
246}
247
248template <class Hasher, typename T, typename... Types>
249size_t hash_combine_generic(const Hasher &h, const T &t, const Types &...ts) {
250 size_t seed = h(t);
251 if (sizeof...(ts) == 0) return seed;
252
253 size_t remainder = hash_combine_generic(h, ts...);
254 if constexpr (sizeof(size_t) == sizeof(uint32_t))
255 return static_cast<size_t>(
256 hash_combine(static_cast<uint64_t>(seed) << 32, static_cast<uint64_t>(remainder)));
257 else
258 return static_cast<size_t>(hash_combine(seed, remainder));
259}
260
261template <typename T, typename... Types>
262size_t hash_combine(const T &t, const Types &...ts) {
263 return hash_combine_generic(Detail::StdHasher{}, t, ts...);
264}
265
266namespace Detail {
267template <size_t index, typename... Types>
269 size_t operator()(std::tuple<Types...> const &val) const {
270 return hash_combine(TupleHasher<index - 1, Types...>()(val), std::get<index>(val));
271 }
272};
273
274template <typename... Types>
275struct TupleHasher<0, Types...> {
276 size_t operator()(std::tuple<Types...> const &val) const {
277 return hash_combine(std::get<0>(val));
278 }
279};
280} // namespace Detail
281} // namespace P4::Util
282
283namespace std {
284template <typename T1, typename T2>
285struct hash<std::pair<T1, T2>> {
286 size_t operator()(const std::pair<T1, T2> &x) const {
287 return P4::Util::hash_combine(x.first, x.second);
288 }
289};
290
291template <typename... Types>
292struct hash<std::tuple<Types...>> {
293 public:
294 size_t operator()(std::tuple<Types...> const &key) const {
295 P4::Util::Detail::TupleHasher<sizeof...(Types) - 1, Types...> hasher;
296
297 return hasher(key);
298 }
299};
300} // namespace std
301
302#endif /* LIB_HASH_H_ */
Definition hash.h:90
STL namespace.
Definition hash.h:77
Definition hash.h:268
Definition hash.h:125
Definition hash.h:123