123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- #pragma once
- #include <util/system/compiler.h>
- #include <util/system/types.h>
- #if defined(_MSC_VER) && defined(_M_X64)
- #include <intrin.h>
- #endif
- /**
- * Calculates the number of buckets for the hash table that will hold the given
- * number of elements.
- *
- * @param elementCount Number of elements that the hash table will hold.
- * @returns Number of buckets, a prime number that is
- * greater or equal to `elementCount`.
- */
- Y_CONST_FUNCTION
- unsigned long HashBucketCount(unsigned long elementCount);
- namespace NPrivate {
- /// Implementation of algorithm 4.1 from: Torbjörn Granlund and Peter L. Montgomery. 1994. Division by invariant integers using multiplication.
- /// @see https://gmplib.org/~tege/divcnst-pldi94.pdf
- template <typename TDivisor, typename TDividend, typename MulUnsignedUpper>
- class TReciprocalDivisor {
- static_assert(sizeof(TDivisor) <= sizeof(TDividend), "TDivisor and TDividend should have the same size");
- public:
- constexpr TReciprocalDivisor() noexcept = default;
- constexpr TReciprocalDivisor(TDividend reciprocal, ui8 reciprocalShift, i8 hint, TDivisor divisor) noexcept
- : Reciprocal(reciprocal)
- , Divisor(divisor)
- , ReciprocalShift(reciprocalShift)
- , Hint(hint)
- {
- }
- /// Return (dividend % Divisor)
- Y_FORCE_INLINE TDividend Remainder(TDividend dividend) const noexcept {
- if (Y_UNLIKELY(Divisor == 1)) {
- return 0;
- }
- TDividend r = dividend - Quotent(dividend) * Divisor;
- return r;
- }
- Y_FORCE_INLINE TDivisor operator()() const noexcept {
- return Divisor;
- }
- Y_FORCE_INLINE static constexpr TReciprocalDivisor One() noexcept {
- return {1u, 0u, -1, 1u};
- }
- private:
- /// returns (dividend / Divisor)
- Y_FORCE_INLINE TDividend Quotent(TDividend dividend) const noexcept {
- const TDividend t = MulUnsignedUpper{}(dividend, Reciprocal);
- const TDividend q = (t + ((dividend - t) >> 1)) >> ReciprocalShift;
- return q;
- }
- public:
- TDividend Reciprocal = 0;
- TDivisor Divisor = 0;
- ui8 ReciprocalShift = 0;
- i8 Hint = 0; ///< Additional data: needless for division, but useful for the adjacent divisors search
- };
- template <typename T, typename TExtended, size_t shift>
- struct TMulUnsignedUpper {
- /// Return the high bits of the product of two unsigned integers.
- Y_FORCE_INLINE T operator()(T a, T b) const noexcept {
- return (static_cast<TExtended>(a) * static_cast<TExtended>(b)) >> shift;
- }
- };
- #if defined(_32_)
- using THashDivisor = ::NPrivate::TReciprocalDivisor<ui32, ui32, TMulUnsignedUpper<ui32, ui64, 32>>;
- #else
- #if defined(Y_HAVE_INT128)
- using THashDivisor = ::NPrivate::TReciprocalDivisor<ui32, ui64, TMulUnsignedUpper<ui64, unsigned __int128, 64>>;
- #elif defined(_MSC_VER) && defined(_M_X64)
- struct TMulUnsignedUpperVCIntrin {
- /// Return the high 64 bits of the product of two 64-bit unsigned integers.
- Y_FORCE_INLINE ui64 operator()(ui64 a, ui64 b) const noexcept {
- return __umulh(a, b);
- }
- };
- using THashDivisor = ::NPrivate::TReciprocalDivisor<ui32, ui64, TMulUnsignedUpperVCIntrin>;
- #else
- template <typename TDivisor, typename TDividend>
- class TNaiveDivisor {
- public:
- constexpr TNaiveDivisor() noexcept = default;
- constexpr TNaiveDivisor(TDivisor divisor) noexcept
- : Divisor(divisor)
- {
- }
- constexpr TNaiveDivisor(TDividend reciprocal, ui8 reciprocalShift, i8 hint, TDivisor divisor) noexcept
- : TNaiveDivisor(divisor)
- {
- Y_UNUSED(reciprocal);
- Y_UNUSED(reciprocalShift);
- Y_UNUSED(hint);
- }
- Y_FORCE_INLINE TDividend Remainder(TDividend dividend) const noexcept {
- return dividend % Divisor;
- }
- Y_FORCE_INLINE TDivisor operator()() const noexcept {
- return Divisor;
- }
- Y_FORCE_INLINE static constexpr TNaiveDivisor One() noexcept {
- return {1u};
- }
- public:
- TDivisor Divisor = 0;
- static constexpr i8 Hint = -1;
- };
- using THashDivisor = ::NPrivate::TNaiveDivisor<ui32, ui64>;
- #endif
- #endif
- } // namespace NPrivate
- Y_CONST_FUNCTION
- ::NPrivate::THashDivisor HashBucketCountExt(unsigned long elementCount);
- Y_CONST_FUNCTION
- ::NPrivate::THashDivisor HashBucketCountExt(unsigned long elementCount, int hint);
|