hash_mix.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Copyright 2022 Peter Dimov
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // https://www.boost.org/LICENSE_1_0.txt
  4. #ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP
  5. #define BOOST_HASH_DETAIL_HASH_MIX_HPP
  6. #include <cstdint>
  7. #include <cstddef>
  8. #include <climits>
  9. namespace boost
  10. {
  11. namespace hash_detail
  12. {
  13. template<std::size_t Bits> struct hash_mix_impl;
  14. // hash_mix for 64 bit size_t
  15. //
  16. // The general "xmxmx" form of state of the art 64 bit mixers originates
  17. // from Murmur3 by Austin Appleby, which uses the following function as
  18. // its "final mix":
  19. //
  20. // k ^= k >> 33;
  21. // k *= 0xff51afd7ed558ccd;
  22. // k ^= k >> 33;
  23. // k *= 0xc4ceb9fe1a85ec53;
  24. // k ^= k >> 33;
  25. //
  26. // (https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp)
  27. //
  28. // It has subsequently been improved multiple times by different authors
  29. // by changing the constants. The most well known improvement is the
  30. // so-called "variant 13" function by David Stafford:
  31. //
  32. // k ^= k >> 30;
  33. // k *= 0xbf58476d1ce4e5b9;
  34. // k ^= k >> 27;
  35. // k *= 0x94d049bb133111eb;
  36. // k ^= k >> 31;
  37. //
  38. // (https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
  39. //
  40. // This mixing function is used in the splitmix64 RNG:
  41. // http://xorshift.di.unimi.it/splitmix64.c
  42. //
  43. // We use Jon Maiga's implementation from
  44. // http://jonkagstrom.com/mx3/mx3_rev2.html
  45. //
  46. // x ^= x >> 32;
  47. // x *= 0xe9846af9b1a615d;
  48. // x ^= x >> 32;
  49. // x *= 0xe9846af9b1a615d;
  50. // x ^= x >> 28;
  51. //
  52. // An equally good alternative is Pelle Evensen's Moremur:
  53. //
  54. // x ^= x >> 27;
  55. // x *= 0x3C79AC492BA7B653;
  56. // x ^= x >> 33;
  57. // x *= 0x1C69B3F74AC4AE35;
  58. // x ^= x >> 27;
  59. //
  60. // (https://mostlymangling.blogspot.com/2019/12/stronger-better-morer-moremur-better.html)
  61. template<> struct hash_mix_impl<64>
  62. {
  63. inline static std::uint64_t fn( std::uint64_t x )
  64. {
  65. std::uint64_t const m = 0xe9846af9b1a615d;
  66. x ^= x >> 32;
  67. x *= m;
  68. x ^= x >> 32;
  69. x *= m;
  70. x ^= x >> 28;
  71. return x;
  72. }
  73. };
  74. // hash_mix for 32 bit size_t
  75. //
  76. // We use the "best xmxmx" implementation from
  77. // https://github.com/skeeto/hash-prospector/issues/19
  78. template<> struct hash_mix_impl<32>
  79. {
  80. inline static std::uint32_t fn( std::uint32_t x )
  81. {
  82. std::uint32_t const m1 = 0x21f0aaad;
  83. std::uint32_t const m2 = 0x735a2d97;
  84. x ^= x >> 16;
  85. x *= m1;
  86. x ^= x >> 15;
  87. x *= m2;
  88. x ^= x >> 15;
  89. return x;
  90. }
  91. };
  92. inline std::size_t hash_mix( std::size_t v )
  93. {
  94. return hash_mix_impl<sizeof(std::size_t) * CHAR_BIT>::fn( v );
  95. }
  96. } // namespace hash_detail
  97. } // namespace boost
  98. #endif // #ifndef BOOST_HASH_DETAIL_HASH_MIX_HPP