#pragma once #include #include #if defined(_MSC_VER) && defined(_M_X64) #include #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 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 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(a) * static_cast(b)) >> shift; } }; #if defined(_32_) using THashDivisor = ::NPrivate::TReciprocalDivisor>; #else #if defined(Y_HAVE_INT128) using THashDivisor = ::NPrivate::TReciprocalDivisor>; #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; #else template 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; #endif #endif } // namespace NPrivate Y_CONST_FUNCTION ::NPrivate::THashDivisor HashBucketCountExt(unsigned long elementCount); Y_CONST_FUNCTION ::NPrivate::THashDivisor HashBucketCountExt(unsigned long elementCount, int hint);