container_hash.h 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // SPDX-FileCopyrightText: 2005-2014 Daniel James
  2. // SPDX-FileCopyrightText: 2016 Austin Appleby
  3. // SPDX-License-Identifier: BSL-1.0
  4. #include <array>
  5. #include <climits>
  6. #include <cstdint>
  7. #include <limits>
  8. #include <type_traits>
  9. #include <vector>
  10. namespace Common {
  11. namespace detail {
  12. template <typename T>
  13. requires std::is_unsigned_v<T>
  14. inline std::size_t HashValue(T val) {
  15. const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
  16. const unsigned int length =
  17. (std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
  18. std::size_t seed = 0;
  19. for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits) {
  20. seed ^= static_cast<size_t>(val >> i) + (seed << 6) + (seed >> 2);
  21. }
  22. seed ^= static_cast<size_t>(val) + (seed << 6) + (seed >> 2);
  23. return seed;
  24. }
  25. template <size_t Bits>
  26. struct HashCombineImpl {
  27. template <typename T>
  28. static inline T fn(T seed, T value) {
  29. seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  30. return seed;
  31. }
  32. };
  33. template <>
  34. struct HashCombineImpl<64> {
  35. static inline std::uint64_t fn(std::uint64_t h, std::uint64_t k) {
  36. const std::uint64_t m = (std::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
  37. const int r = 47;
  38. k *= m;
  39. k ^= k >> r;
  40. k *= m;
  41. h ^= k;
  42. h *= m;
  43. // Completely arbitrary number, to prevent 0's
  44. // from hashing to 0.
  45. h += 0xe6546b64;
  46. return h;
  47. }
  48. };
  49. } // namespace detail
  50. template <typename T>
  51. inline void HashCombine(std::size_t& seed, const T& v) {
  52. seed = detail::HashCombineImpl<sizeof(std::size_t) * CHAR_BIT>::fn(seed, detail::HashValue(v));
  53. }
  54. template <typename It>
  55. inline std::size_t HashRange(It first, It last) {
  56. std::size_t seed = 0;
  57. for (; first != last; ++first) {
  58. HashCombine<typename std::iterator_traits<It>::value_type>(seed, *first);
  59. }
  60. return seed;
  61. }
  62. template <typename T, size_t Size>
  63. std::size_t HashValue(const std::array<T, Size>& v) {
  64. return HashRange(v.cbegin(), v.cend());
  65. }
  66. template <typename T, typename Allocator>
  67. std::size_t HashValue(const std::vector<T, Allocator>& v) {
  68. return HashRange(v.cbegin(), v.cend());
  69. }
  70. } // namespace Common