WPILibC++ 2024.3.2
Hashing.h
Go to the documentation of this file.
1//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the newly proposed standard C++ interfaces for hashing
10// arbitrary data and building hash functions for user-defined types. This
11// interface was originally proposed in N3333[1] and is currently under review
12// for inclusion in a future TR and/or standard.
13//
14// The primary interfaces provide are comprised of one type and three functions:
15//
16// -- 'hash_code' class is an opaque type representing the hash code for some
17// data. It is the intended product of hashing, and can be used to implement
18// hash tables, checksumming, and other common uses of hashes. It is not an
19// integer type (although it can be converted to one) because it is risky
20// to assume much about the internals of a hash_code. In particular, each
21// execution of the program has a high probability of producing a different
22// hash_code for a given input. Thus their values are not stable to save or
23// persist, and should only be used during the execution for the
24// construction of hashing datastructures.
25//
26// -- 'hash_value' is a function designed to be overloaded for each
27// user-defined type which wishes to be used within a hashing context. It
28// should be overloaded within the user-defined type's namespace and found
29// via ADL. Overloads for primitive types are provided by this library.
30//
31// -- 'hash_combine' and 'hash_combine_range' are functions designed to aid
32// programmers in easily and intuitively combining a set of data into
33// a single hash_code for their object. They should only logically be used
34// within the implementation of a 'hash_value' routine or similar context.
35//
36// Note that 'hash_combine_range' contains very special logic for hashing
37// a contiguous array of integers or pointers. This logic is *extremely* fast,
38// on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were
39// benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys
40// under 32-bytes.
41//
42//===----------------------------------------------------------------------===//
43
44#ifndef WPIUTIL_WPI_HASHING_H
45#define WPIUTIL_WPI_HASHING_H
46
47#include "wpi/ErrorHandling.h"
48#include "wpi/SwapByteOrder.h"
49#include "wpi/type_traits.h"
50#include <algorithm>
51#include <bit>
52#include <cassert>
53#include <cstring>
54#include <optional>
55#include <string>
56#include <tuple>
57#include <utility>
58
59#ifdef _WIN32
60#pragma warning(push)
61#pragma warning(disable : 26495)
62#endif
63
64namespace wpi {
65template <typename T, typename Enable> struct DenseMapInfo;
66
67/// An opaque object representing a hash code.
68///
69/// This object represents the result of hashing some entity. It is intended to
70/// be used to implement hashtables or other hashing-based data structures.
71/// While it wraps and exposes a numeric value, this value should not be
72/// trusted to be stable or predictable across processes or executions.
73///
74/// In order to obtain the hash_code for an object 'x':
75/// \code
76/// using wpi::hash_value;
77/// wpi::hash_code code = hash_value(x);
78/// \endcode
79class hash_code {
80 size_t value;
81
82public:
83 /// Default construct a hash_code.
84 /// Note that this leaves the value uninitialized.
85 hash_code() = default;
86
87 /// Form a hash code directly from a numerical value.
88 hash_code(size_t value) : value(value) {}
89
90 /// Convert the hash code to its numerical value for use.
91 /*explicit*/ operator size_t() const { return value; }
92
93 friend bool operator==(const hash_code &lhs, const hash_code &rhs) {
94 return lhs.value == rhs.value;
95 }
96 friend bool operator!=(const hash_code &lhs, const hash_code &rhs) {
97 return lhs.value != rhs.value;
98 }
99
100 /// Allow a hash_code to be directly run through hash_value.
101 friend size_t hash_value(const hash_code &code) { return code.value; }
102};
103
104/// Compute a hash_code for any integer value.
105///
106/// Note that this function is intended to compute the same hash_code for
107/// a particular value without regard to the pre-promotion type. This is in
108/// contrast to hash_combine which may produce different hash_codes for
109/// differing argument types even if they would implicit promote to a common
110/// type without changing the value.
111template <typename T>
112std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value);
113
114/// Compute a hash_code for a pointer's address.
115///
116/// N.B.: This hashes the *address*. Not the value and not the type.
117template <typename T> hash_code hash_value(const T *ptr);
118
119/// Compute a hash_code for a pair of objects.
120template <typename T, typename U>
121hash_code hash_value(const std::pair<T, U> &arg);
122
123/// Compute a hash_code for a tuple.
124template <typename... Ts>
125hash_code hash_value(const std::tuple<Ts...> &arg);
126
127/// Compute a hash_code for a standard string.
128template <typename T>
129hash_code hash_value(const std::basic_string<T> &arg);
130
131/// Compute a hash_code for a standard string.
132template <typename T> hash_code hash_value(const std::optional<T> &arg);
133
134/// Override the execution seed with a fixed value.
135///
136/// This hashing library uses a per-execution seed designed to change on each
137/// run with high probability in order to ensure that the hash codes are not
138/// attackable and to ensure that output which is intended to be stable does
139/// not rely on the particulars of the hash codes produced.
140///
141/// That said, there are use cases where it is important to be able to
142/// reproduce *exactly* a specific behavior. To that end, we provide a function
143/// which will forcibly set the seed to a fixed value. This must be done at the
144/// start of the program, before any hashes are computed. Also, it cannot be
145/// undone. This makes it thread-hostile and very hard to use outside of
146/// immediately on start of a simple program designed for reproducible
147/// behavior.
148void set_fixed_execution_hash_seed(uint64_t fixed_value);
149
150
151// All of the implementation details of actually computing the various hash
152// code values are held within this namespace. These routines are included in
153// the header file mainly to allow inlining and constant propagation.
154namespace hashing {
155namespace detail {
156
157inline uint64_t fetch64(const char *p) {
158 uint64_t result;
159 memcpy(&result, p, sizeof(result));
161 sys::swapByteOrder(result);
162 return result;
163}
164
165inline uint32_t fetch32(const char *p) {
166 uint32_t result;
167 memcpy(&result, p, sizeof(result));
169 sys::swapByteOrder(result);
170 return result;
171}
172
173/// Some primes between 2^63 and 2^64 for various uses.
174static constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
175static constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
176static constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
177static constexpr uint64_t k3 = 0xc949d7c7509e6557ULL;
178
179/// Bitwise right rotate.
180/// Normally this will compile to a single instruction, especially if the
181/// shift is a manifest constant.
182inline uint64_t rotate(uint64_t val, size_t shift) {
183 // Avoid shifting by 64: doing so yields an undefined result.
184 return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
185}
186
187inline uint64_t shift_mix(uint64_t val) {
188 return val ^ (val >> 47);
189}
190
191inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) {
192 // Murmur-inspired hashing.
193 const uint64_t kMul = 0x9ddfea08eb382d69ULL;
194 uint64_t a = (low ^ high) * kMul;
195 a ^= (a >> 47);
196 uint64_t b = (high ^ a) * kMul;
197 b ^= (b >> 47);
198 b *= kMul;
199 return b;
200}
201
202inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) {
203 uint8_t a = s[0];
204 uint8_t b = s[len >> 1];
205 uint8_t c = s[len - 1];
206 uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
207 uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
208 return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
209}
210
211inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) {
212 uint64_t a = fetch32(s);
213 return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4));
214}
215
216inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) {
217 uint64_t a = fetch64(s);
218 uint64_t b = fetch64(s + len - 8);
219 return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b;
220}
221
222inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) {
223 uint64_t a = fetch64(s) * k1;
224 uint64_t b = fetch64(s + 8);
225 uint64_t c = fetch64(s + len - 8) * k2;
226 uint64_t d = fetch64(s + len - 16) * k0;
227 return hash_16_bytes(std::rotr<uint64_t>(a - b, 43) +
228 std::rotr<uint64_t>(c ^ seed, 30) + d,
229 a + std::rotr<uint64_t>(b ^ k3, 20) - c + len + seed);
230}
231
232inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) {
233 uint64_t z = fetch64(s + 24);
234 uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0;
235 uint64_t b = std::rotr<uint64_t>(a + z, 52);
236 uint64_t c = std::rotr<uint64_t>(a, 37);
237 a += fetch64(s + 8);
238 c += std::rotr<uint64_t>(a, 7);
239 a += fetch64(s + 16);
240 uint64_t vf = a + z;
241 uint64_t vs = b + std::rotr<uint64_t>(a, 31) + c;
242 a = fetch64(s + 16) + fetch64(s + len - 32);
243 z = fetch64(s + len - 8);
244 b = std::rotr<uint64_t>(a + z, 52);
245 c = std::rotr<uint64_t>(a, 37);
246 a += fetch64(s + len - 24);
247 c += std::rotr<uint64_t>(a, 7);
248 a += fetch64(s + len - 16);
249 uint64_t wf = a + z;
250 uint64_t ws = b + std::rotr<uint64_t>(a, 31) + c;
251 uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
252 return shift_mix((seed ^ (r * k0)) + vs) * k2;
253}
254
255inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) {
256 if (length >= 4 && length <= 8)
257 return hash_4to8_bytes(s, length, seed);
258 if (length > 8 && length <= 16)
259 return hash_9to16_bytes(s, length, seed);
260 if (length > 16 && length <= 32)
261 return hash_17to32_bytes(s, length, seed);
262 if (length > 32)
263 return hash_33to64_bytes(s, length, seed);
264 if (length != 0)
265 return hash_1to3_bytes(s, length, seed);
266
267 return k2 ^ seed;
268}
269
270/// The intermediate state used during hashing.
271/// Currently, the algorithm for computing hash codes is based on CityHash and
272/// keeps 56 bytes of arbitrary state.
274 uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0;
275
276 /// Create a new hash_state structure and initialize it based on the
277 /// seed and the first 64-byte chunk.
278 /// This effectively performs the initial mix.
279 static hash_state create(const char *s, uint64_t seed) {
280 hash_state state = {0,
281 seed,
282 hash_16_bytes(seed, k1),
283 std::rotr<uint64_t>(seed ^ k1, 49),
284 seed * k1,
285 shift_mix(seed),
286 0};
287 state.h6 = hash_16_bytes(state.h4, state.h5);
288 state.mix(s);
289 return state;
290 }
291
292 /// Mix 32-bytes from the input sequence into the 16-bytes of 'a'
293 /// and 'b', including whatever is already in 'a' and 'b'.
294 static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) {
295 a += fetch64(s);
296 uint64_t c = fetch64(s + 24);
297 b = std::rotr<uint64_t>(b + a + c, 21);
298 uint64_t d = a;
299 a += fetch64(s + 8) + fetch64(s + 16);
300 b += std::rotr<uint64_t>(a, 44) + d;
301 a += c;
302 }
303
304 /// Mix in a 64-byte buffer of data.
305 /// We mix all 64 bytes even when the chunk length is smaller, but we
306 /// record the actual length.
307 void mix(const char *s) {
308 h0 = std::rotr<uint64_t>(h0 + h1 + h3 + fetch64(s + 8), 37) * k1;
309 h1 = std::rotr<uint64_t>(h1 + h4 + fetch64(s + 48), 42) * k1;
310 h0 ^= h6;
311 h1 += h3 + fetch64(s + 40);
312 h2 = std::rotr<uint64_t>(h2 + h5, 33) * k1;
313 h3 = h4 * k1;
314 h4 = h0 + h5;
315 mix_32_bytes(s, h3, h4);
316 h5 = h2 + h6;
317 h6 = h1 + fetch64(s + 16);
318 mix_32_bytes(s + 32, h5, h6);
319 std::swap(h2, h0);
320 }
321
322 /// Compute the final 64-bit hash code value based on the current
323 /// state and the length of bytes hashed.
324 uint64_t finalize(size_t length) {
326 hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0);
327 }
328};
329
330
331/// A global, fixed seed-override variable.
332///
333/// This variable can be set using the \see wpi::set_fixed_execution_seed
334/// function. See that function for details. Do not, under any circumstances,
335/// set or read this variable.
336extern uint64_t fixed_seed_override;
337
338inline uint64_t get_execution_seed() {
339 // FIXME: This needs to be a per-execution seed. This is just a placeholder
340 // implementation. Switching to a per-execution seed is likely to flush out
341 // instability bugs and so will happen as its own commit.
342 //
343 // However, if there is a fixed seed override set the first time this is
344 // called, return that instead of the per-execution seed.
345 const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
346 static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime;
347 return seed;
348}
349
350
351/// Trait to indicate whether a type's bits can be hashed directly.
352///
353/// A type trait which is true if we want to combine values for hashing by
354/// reading the underlying data. It is false if values of this type must
355/// first be passed to hash_value, and the resulting hash_codes combined.
356//
357// FIXME: We want to replace is_integral_or_enum and is_pointer here with
358// a predicate which asserts that comparing the underlying storage of two
359// values of the type for equality is equivalent to comparing the two values
360// for equality. For all the platforms we care about, this holds for integers
361// and pointers, but there are platforms where it doesn't and we would like to
362// support user-defined types which happen to satisfy this property.
363template <typename T> struct is_hashable_data
364 : std::integral_constant<bool, ((is_integral_or_enum<T>::value ||
365 std::is_pointer<T>::value) &&
366 64 % sizeof(T) == 0)> {};
367
368// Special case std::pair to detect when both types are viable and when there
369// is no alignment-derived padding in the pair. This is a bit of a lie because
370// std::pair isn't truly POD, but it's close enough in all reasonable
371// implementations for our use case of hashing the underlying data.
372template <typename T, typename U> struct is_hashable_data<std::pair<T, U> >
373 : std::integral_constant<bool, (is_hashable_data<T>::value &&
374 is_hashable_data<U>::value &&
375 (sizeof(T) + sizeof(U)) ==
376 sizeof(std::pair<T, U>))> {};
377
378/// Helper to get the hashable data representation for a type.
379/// This variant is enabled when the type itself can be used.
380template <typename T>
381std::enable_if_t<is_hashable_data<T>::value, T>
382get_hashable_data(const T &value) {
383 return value;
384}
385/// Helper to get the hashable data representation for a type.
386/// This variant is enabled when we must first call hash_value and use the
387/// result as our data.
388template <typename T>
389std::enable_if_t<!is_hashable_data<T>::value, size_t>
390get_hashable_data(const T &value) {
392 return hash_value(value);
393}
394
395/// Helper to store data from a value into a buffer and advance the
396/// pointer into that buffer.
397///
398/// This routine first checks whether there is enough space in the provided
399/// buffer, and if not immediately returns false. If there is space, it
400/// copies the underlying bytes of value into the buffer, advances the
401/// buffer_ptr past the copied bytes, and returns true.
402template <typename T>
403bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value,
404 size_t offset = 0) {
405 size_t store_size = sizeof(value) - offset;
406 if (buffer_ptr + store_size > buffer_end)
407 return false;
408 const char *value_data = reinterpret_cast<const char *>(&value);
409 memcpy(buffer_ptr, value_data + offset, store_size);
410 buffer_ptr += store_size;
411 return true;
412}
413
414/// Implement the combining of integral values into a hash_code.
415///
416/// This overload is selected when the value type of the iterator is
417/// integral. Rather than computing a hash_code for each object and then
418/// combining them, this (as an optimization) directly combines the integers.
419template <typename InputIteratorT>
420hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) {
421 const uint64_t seed = get_execution_seed();
422 char buffer[64], *buffer_ptr = buffer;
423 char *const buffer_end = std::end(buffer);
424 while (first != last && store_and_advance(buffer_ptr, buffer_end,
426 ++first;
427 if (first == last)
428 return hash_short(buffer, buffer_ptr - buffer, seed);
429 assert(buffer_ptr == buffer_end);
430
431 hash_state state = state.create(buffer, seed);
432 size_t length = 64;
433 while (first != last) {
434 // Fill up the buffer. We don't clear it, which re-mixes the last round
435 // when only a partial 64-byte chunk is left.
436 buffer_ptr = buffer;
437 while (first != last && store_and_advance(buffer_ptr, buffer_end,
439 ++first;
440
441 // Rotate the buffer if we did a partial fill in order to simulate doing
442 // a mix of the last 64-bytes. That is how the algorithm works when we
443 // have a contiguous byte sequence, and we want to emulate that here.
444 std::rotate(buffer, buffer_ptr, buffer_end);
445
446 // Mix this chunk into the current state.
447 state.mix(buffer);
448 length += buffer_ptr - buffer;
449 };
450
451 return state.finalize(length);
452}
453
454/// Implement the combining of integral values into a hash_code.
455///
456/// This overload is selected when the value type of the iterator is integral
457/// and when the input iterator is actually a pointer. Rather than computing
458/// a hash_code for each object and then combining them, this (as an
459/// optimization) directly combines the integers. Also, because the integers
460/// are stored in contiguous memory, this routine avoids copying each value
461/// and directly reads from the underlying memory.
462template <typename ValueT>
463std::enable_if_t<is_hashable_data<ValueT>::value, hash_code>
464hash_combine_range_impl(ValueT *first, ValueT *last) {
465 const uint64_t seed = get_execution_seed();
466 const char *s_begin = reinterpret_cast<const char *>(first);
467 const char *s_end = reinterpret_cast<const char *>(last);
468 const size_t length = std::distance(s_begin, s_end);
469 if (length <= 64)
470 return hash_short(s_begin, length, seed);
471
472 const char *s_aligned_end = s_begin + (length & ~63);
473 hash_state state = state.create(s_begin, seed);
474 s_begin += 64;
475 while (s_begin != s_aligned_end) {
476 state.mix(s_begin);
477 s_begin += 64;
478 }
479 if (length & 63)
480 state.mix(s_end - 64);
481
482 return state.finalize(length);
483}
484
485} // namespace detail
486} // namespace hashing
487
488
489/// Compute a hash_code for a sequence of values.
490///
491/// This hashes a sequence of values. It produces the same hash_code as
492/// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences
493/// and is significantly faster given pointers and types which can be hashed as
494/// a sequence of bytes.
495template <typename InputIteratorT>
496hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) {
498}
499
500
501// Implementation details for hash_combine.
502namespace hashing {
503namespace detail {
504
505/// Helper class to manage the recursive combining of hash_combine
506/// arguments.
507///
508/// This class exists to manage the state and various calls involved in the
509/// recursive combining of arguments used in hash_combine. It is particularly
510/// useful at minimizing the code in the recursive calls to ease the pain
511/// caused by a lack of variadic functions.
513 char buffer[64] = {};
515 const uint64_t seed;
516
517public:
518 /// Construct a recursive hash combining helper.
519 ///
520 /// This sets up the state for a recursive hash combine, including getting
521 /// the seed and buffer setup.
524
525 /// Combine one chunk of data into the current in-flight hash.
526 ///
527 /// This merges one chunk of data into the hash. First it tries to buffer
528 /// the data. If the buffer is full, it hashes the buffer into its
529 /// hash_state, empties it, and then merges the new chunk in. This also
530 /// handles cases where the data straddles the end of the buffer.
531 template <typename T>
532 char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
533 if (!store_and_advance(buffer_ptr, buffer_end, data)) {
534 // Check for skew which prevents the buffer from being packed, and do
535 // a partial store into the buffer to fill it. This is only a concern
536 // with the variadic combine because that formation can have varying
537 // argument types.
538 size_t partial_store_size = buffer_end - buffer_ptr;
539 memcpy(buffer_ptr, &data, partial_store_size);
540
541 // If the store fails, our buffer is full and ready to hash. We have to
542 // either initialize the hash state (on the first full buffer) or mix
543 // this buffer into the existing hash state. Length tracks the *hashed*
544 // length, not the buffered length.
545 if (length == 0) {
547 length = 64;
548 } else {
549 // Mix this chunk into the current state and bump length up by 64.
551 length += 64;
552 }
553 // Reset the buffer_ptr to the head of the buffer for the next chunk of
554 // data.
555 buffer_ptr = buffer;
556
557 // Try again to store into the buffer -- this cannot fail as we only
558 // store types smaller than the buffer.
559 if (!store_and_advance(buffer_ptr, buffer_end, data,
560 partial_store_size))
561 wpi_unreachable("buffer smaller than stored type");
562 }
563 return buffer_ptr;
564 }
565
566 /// Recursive, variadic combining method.
567 ///
568 /// This function recurses through each argument, combining that argument
569 /// into a single hash.
570 template <typename T, typename ...Ts>
571 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
572 const T &arg, const Ts &...args) {
573 buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
574
575 // Recurse to the next argument.
576 return combine(length, buffer_ptr, buffer_end, args...);
577 }
578
579 /// Base case for recursive, variadic combining.
580 ///
581 /// The base case when combining arguments recursively is reached when all
582 /// arguments have been handled. It flushes the remaining buffer and
583 /// constructs a hash_code.
584 hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
585 // Check whether the entire set of values fit in the buffer. If so, we'll
586 // use the optimized short hashing routine and skip state entirely.
587 if (length == 0)
588 return hash_short(buffer, buffer_ptr - buffer, seed);
589
590 // Mix the final buffer, rotating it if we did a partial fill in order to
591 // simulate doing a mix of the last 64-bytes. That is how the algorithm
592 // works when we have a contiguous byte sequence, and we want to emulate
593 // that here.
594 std::rotate(buffer, buffer_ptr, buffer_end);
595
596 // Mix this chunk into the current state.
598 length += buffer_ptr - buffer;
599
600 return state.finalize(length);
601 }
602};
603
604} // namespace detail
605} // namespace hashing
606
607/// Combine values into a single hash_code.
608///
609/// This routine accepts a varying number of arguments of any type. It will
610/// attempt to combine them into a single hash_code. For user-defined types it
611/// attempts to call a \see hash_value overload (via ADL) for the type. For
612/// integer and pointer types it directly combines their data into the
613/// resulting hash_code.
614///
615/// The result is suitable for returning from a user's hash_value
616/// *implementation* for their user-defined type. Consumers of a type should
617/// *not* call this routine, they should instead call 'hash_value'.
618template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
619 // Recursively hash each argument using a helper class.
621 return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
622}
623
624// Implementation details for implementations of hash_value overloads provided
625// here.
626namespace hashing {
627namespace detail {
628
629/// Helper to hash the value of a single integer.
630///
631/// Overloads for smaller integer types are not provided to ensure consistent
632/// behavior in the presence of integral promotions. Essentially,
633/// "hash_value('4')" and "hash_value('0' + 4)" should be the same.
634inline hash_code hash_integer_value(uint64_t value) {
635 // Similar to hash_4to8_bytes but using a seed instead of length.
636 const uint64_t seed = get_execution_seed();
637 const char *s = reinterpret_cast<const char *>(&value);
638 const uint64_t a = fetch32(s);
639 return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
640}
641
642} // namespace detail
643} // namespace hashing
644
645// Declared and documented above, but defined here so that any of the hashing
646// infrastructure is available.
647template <typename T>
648std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value) {
650 static_cast<uint64_t>(value));
651}
652
653// Declared and documented above, but defined here so that any of the hashing
654// infrastructure is available.
655template <typename T> hash_code hash_value(const T *ptr) {
657 reinterpret_cast<uintptr_t>(ptr));
658}
659
660// Declared and documented above, but defined here so that any of the hashing
661// infrastructure is available.
662template <typename T, typename U>
663hash_code hash_value(const std::pair<T, U> &arg) {
664 return hash_combine(arg.first, arg.second);
665}
666
667template <typename... Ts> hash_code hash_value(const std::tuple<Ts...> &arg) {
668 return std::apply([](const auto &...xs) { return hash_combine(xs...); }, arg);
669}
670
671// Declared and documented above, but defined here so that any of the hashing
672// infrastructure is available.
673template <typename T>
674hash_code hash_value(const std::basic_string<T> &arg) {
675 return hash_combine_range(arg.begin(), arg.end());
676}
677
678template <typename T> hash_code hash_value(const std::optional<T> &arg) {
679 return arg ? hash_combine(true, *arg) : hash_value(false);
680}
681
682template <> struct DenseMapInfo<hash_code, void> {
683 static inline hash_code getEmptyKey() { return hash_code(-1); }
684 static inline hash_code getTombstoneKey() { return hash_code(-2); }
685 static unsigned getHashValue(hash_code val) { return val; }
686 static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
687};
688
689} // namespace wpi
690
691#ifdef _WIN32
692#pragma warning(pop)
693#endif
694
695#endif
#define wpi_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:142
and restrictions which apply to each piece of software is included later in this file and or inside of the individual applicable source files The disclaimer of warranty in the WPILib license above applies to all code in and nothing in any of the other licenses gives permission to use the names of FIRST nor the names of the WPILib contributors to endorse or promote products derived from this software The following pieces of software have additional or alternate and or Google Inc All rights reserved Redistribution and use in source and binary with or without are permitted provided that the following conditions are this list of conditions and the following disclaimer *Redistributions in binary form must reproduce the above copyright this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution *Neither the name of Google Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY OR CONSEQUENTIAL WHETHER IN STRICT OR EVEN IF ADVISED OF THE POSSIBILITY OF SUCH January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source code
Definition: ThirdPartyNotices.txt:110
An opaque object representing a hash code.
Definition: Hashing.h:79
hash_code(size_t value)
Form a hash code directly from a numerical value.
Definition: Hashing.h:88
hash_code()=default
Default construct a hash_code.
friend size_t hash_value(const hash_code &code)
Allow a hash_code to be directly run through hash_value.
Definition: Hashing.h:101
friend bool operator==(const hash_code &lhs, const hash_code &rhs)
Definition: Hashing.h:93
friend bool operator!=(const hash_code &lhs, const hash_code &rhs)
Definition: Hashing.h:96
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
\rst Returns a named argument to be used in a formatting function.
Definition: core.h:1841
auto ptr(T p) -> const void *
\rst Converts p to const void* for pointer formatting.
Definition: format.h:4100
detail namespace with internal helper functions
Definition: xchar.h:20
const T & first(const T &value, const Tail &...)
Definition: compile.h:60
state
Definition: core.h:2271
uint128_t uintptr_t
Definition: format.h:484
Definition: array.h:89
WPI_BASIC_JSON_TPL_DECLARATION void swap(wpi::WPI_BASIC_JSON_TPL &j1, wpi::WPI_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< wpi::WPI_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< wpi::WPI_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.h:5219
static constexpr const velocity::meters_per_second_t c(299792458.0)
Speed of light in vacuum.
b
Definition: data.h:44
uint32_t fetch32(const char *p)
Definition: Hashing.h:165
static constexpr uint64_t k1
Definition: Hashing.h:175
uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed)
Definition: Hashing.h:211
hash_code hash_integer_value(uint64_t value)
Helper to hash the value of a single integer.
Definition: Hashing.h:634
std::enable_if_t< is_hashable_data< ValueT >::value, hash_code > hash_combine_range_impl(ValueT *first, ValueT *last)
Implement the combining of integral values into a hash_code.
Definition: Hashing.h:464
uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed)
Definition: Hashing.h:202
uint64_t rotate(uint64_t val, size_t shift)
Bitwise right rotate.
Definition: Hashing.h:182
hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last)
Implement the combining of integral values into a hash_code.
Definition: Hashing.h:420
static constexpr uint64_t k3
Definition: Hashing.h:177
static constexpr uint64_t k2
Definition: Hashing.h:176
uint64_t fixed_seed_override
A global, fixed seed-override variable.
static constexpr uint64_t k0
Some primes between 2^63 and 2^64 for various uses.
Definition: Hashing.h:174
std::enable_if_t< is_hashable_data< T >::value, T > get_hashable_data(const T &value)
Helper to get the hashable data representation for a type.
Definition: Hashing.h:382
uint64_t hash_16_bytes(uint64_t low, uint64_t high)
Definition: Hashing.h:191
uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed)
Definition: Hashing.h:216
uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed)
Definition: Hashing.h:232
uint64_t fetch64(const char *p)
Definition: Hashing.h:157
uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed)
Definition: Hashing.h:222
uint64_t get_execution_seed()
Definition: Hashing.h:338
bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T &value, size_t offset=0)
Helper to store data from a value into a buffer and advance the pointer into that buffer.
Definition: Hashing.h:403
uint64_t shift_mix(uint64_t val)
Definition: Hashing.h:187
uint64_t hash_short(const char *s, size_t length, uint64_t seed)
Definition: Hashing.h:255
void swapByteOrder(T &Value)
Definition: SwapByteOrder.h:102
constexpr bool IsBigEndianHost
Definition: SwapByteOrder.h:54
Definition: ntcore_cpp.h:26
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition: Hashing.h:496
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:618
hash_code hash_value(const std::optional< T > &arg)
Compute a hash_code for a standard string.
Definition: Hashing.h:678
std::enable_if_t< is_integral_or_enum< T >::value, hash_code > hash_value(T value)
Compute a hash_code for any integer value.
Definition: Hashing.h:648
void set_fixed_execution_hash_seed(uint64_t fixed_value)
Override the execution seed with a fixed value.
static unsigned getHashValue(hash_code val)
Definition: Hashing.h:685
static hash_code getTombstoneKey()
Definition: Hashing.h:684
static bool isEqual(hash_code LHS, hash_code RHS)
Definition: Hashing.h:686
static hash_code getEmptyKey()
Definition: Hashing.h:683
An information struct used to provide DenseMap with the various necessary components for a given valu...
Definition: DenseMapInfo.h:50
Helper class to manage the recursive combining of hash_combine arguments.
Definition: Hashing.h:512
char * combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data)
Combine one chunk of data into the current in-flight hash.
Definition: Hashing.h:532
const uint64_t seed
Definition: Hashing.h:515
hash_state state
Definition: Hashing.h:514
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end, const T &arg, const Ts &...args)
Recursive, variadic combining method.
Definition: Hashing.h:571
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end)
Base case for recursive, variadic combining.
Definition: Hashing.h:584
char buffer[64]
Definition: Hashing.h:513
hash_combine_recursive_helper()
Construct a recursive hash combining helper.
Definition: Hashing.h:522
The intermediate state used during hashing.
Definition: Hashing.h:273
static hash_state create(const char *s, uint64_t seed)
Create a new hash_state structure and initialize it based on the seed and the first 64-byte chunk.
Definition: Hashing.h:279
uint64_t h2
Definition: Hashing.h:274
uint64_t h3
Definition: Hashing.h:274
uint64_t h6
Definition: Hashing.h:274
uint64_t h5
Definition: Hashing.h:274
uint64_t finalize(size_t length)
Compute the final 64-bit hash code value based on the current state and the length of bytes hashed.
Definition: Hashing.h:324
uint64_t h4
Definition: Hashing.h:274
uint64_t h1
Definition: Hashing.h:274
void mix(const char *s)
Mix in a 64-byte buffer of data.
Definition: Hashing.h:307
uint64_t h0
Definition: Hashing.h:274
static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b)
Mix 32-bytes from the input sequence into the 16-bytes of 'a' and 'b', including whatever is already ...
Definition: Hashing.h:294
Trait to indicate whether a type's bits can be hashed directly.
Definition: Hashing.h:366