hash_mix.hpp 3.2 KB

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