hash_primes.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #pragma once
  2. #include <util/system/compiler.h>
  3. #include <util/system/types.h>
  4. #if defined(_MSC_VER) && defined(_M_X64)
  5. #include <intrin.h>
  6. #endif
  7. /**
  8. * Calculates the number of buckets for the hash table that will hold the given
  9. * number of elements.
  10. *
  11. * @param elementCount Number of elements that the hash table will hold.
  12. * @returns Number of buckets, a prime number that is
  13. * greater or equal to `elementCount`.
  14. */
  15. Y_CONST_FUNCTION
  16. unsigned long HashBucketCount(unsigned long elementCount);
  17. namespace NPrivate {
  18. /// Implementation of algorithm 4.1 from: Torbjörn Granlund and Peter L. Montgomery. 1994. Division by invariant integers using multiplication.
  19. /// @see https://gmplib.org/~tege/divcnst-pldi94.pdf
  20. template <typename TDivisor, typename TDividend, typename MulUnsignedUpper>
  21. class TReciprocalDivisor {
  22. static_assert(sizeof(TDivisor) <= sizeof(TDividend), "TDivisor and TDividend should have the same size");
  23. public:
  24. constexpr TReciprocalDivisor() noexcept = default;
  25. constexpr TReciprocalDivisor(TDividend reciprocal, ui8 reciprocalShift, i8 hint, TDivisor divisor) noexcept
  26. : Reciprocal(reciprocal)
  27. , Divisor(divisor)
  28. , ReciprocalShift(reciprocalShift)
  29. , Hint(hint)
  30. {
  31. }
  32. /// Return (dividend % Divisor)
  33. Y_FORCE_INLINE TDividend Remainder(TDividend dividend) const noexcept {
  34. if (Y_UNLIKELY(Divisor == 1)) {
  35. return 0;
  36. }
  37. TDividend r = dividend - Quotent(dividend) * Divisor;
  38. return r;
  39. }
  40. Y_FORCE_INLINE TDivisor operator()() const noexcept {
  41. return Divisor;
  42. }
  43. Y_FORCE_INLINE static constexpr TReciprocalDivisor One() noexcept {
  44. return {1u, 0u, -1, 1u};
  45. }
  46. private:
  47. /// returns (dividend / Divisor)
  48. Y_FORCE_INLINE TDividend Quotent(TDividend dividend) const noexcept {
  49. const TDividend t = MulUnsignedUpper{}(dividend, Reciprocal);
  50. const TDividend q = (t + ((dividend - t) >> 1)) >> ReciprocalShift;
  51. return q;
  52. }
  53. public:
  54. TDividend Reciprocal = 0;
  55. TDivisor Divisor = 0;
  56. ui8 ReciprocalShift = 0;
  57. i8 Hint = 0; ///< Additional data: needless for division, but useful for the adjacent divisors search
  58. };
  59. template <typename T, typename TExtended, size_t shift>
  60. struct TMulUnsignedUpper {
  61. /// Return the high bits of the product of two unsigned integers.
  62. Y_FORCE_INLINE T operator()(T a, T b) const noexcept {
  63. return (static_cast<TExtended>(a) * static_cast<TExtended>(b)) >> shift;
  64. }
  65. };
  66. #if defined(_32_)
  67. using THashDivisor = ::NPrivate::TReciprocalDivisor<ui32, ui32, TMulUnsignedUpper<ui32, ui64, 32>>;
  68. #else
  69. #if defined(Y_HAVE_INT128)
  70. using THashDivisor = ::NPrivate::TReciprocalDivisor<ui32, ui64, TMulUnsignedUpper<ui64, unsigned __int128, 64>>;
  71. #elif defined(_MSC_VER) && defined(_M_X64)
  72. struct TMulUnsignedUpperVCIntrin {
  73. /// Return the high 64 bits of the product of two 64-bit unsigned integers.
  74. Y_FORCE_INLINE ui64 operator()(ui64 a, ui64 b) const noexcept {
  75. return __umulh(a, b);
  76. }
  77. };
  78. using THashDivisor = ::NPrivate::TReciprocalDivisor<ui32, ui64, TMulUnsignedUpperVCIntrin>;
  79. #else
  80. template <typename TDivisor, typename TDividend>
  81. class TNaiveDivisor {
  82. public:
  83. constexpr TNaiveDivisor() noexcept = default;
  84. constexpr TNaiveDivisor(TDivisor divisor) noexcept
  85. : Divisor(divisor)
  86. {
  87. }
  88. constexpr TNaiveDivisor(TDividend reciprocal, ui8 reciprocalShift, i8 hint, TDivisor divisor) noexcept
  89. : TNaiveDivisor(divisor)
  90. {
  91. Y_UNUSED(reciprocal);
  92. Y_UNUSED(reciprocalShift);
  93. Y_UNUSED(hint);
  94. }
  95. Y_FORCE_INLINE TDividend Remainder(TDividend dividend) const noexcept {
  96. return dividend % Divisor;
  97. }
  98. Y_FORCE_INLINE TDivisor operator()() const noexcept {
  99. return Divisor;
  100. }
  101. Y_FORCE_INLINE static constexpr TNaiveDivisor One() noexcept {
  102. return {1u};
  103. }
  104. public:
  105. TDivisor Divisor = 0;
  106. static constexpr i8 Hint = -1;
  107. };
  108. using THashDivisor = ::NPrivate::TNaiveDivisor<ui32, ui64>;
  109. #endif
  110. #endif
  111. } // namespace NPrivate
  112. Y_CONST_FUNCTION
  113. ::NPrivate::THashDivisor HashBucketCountExt(unsigned long elementCount);
  114. Y_CONST_FUNCTION
  115. ::NPrivate::THashDivisor HashBucketCountExt(unsigned long elementCount, int hint);