7#ifndef _MINISKETCH_INT_UTILS_H_
8#define _MINISKETCH_INT_UTILS_H_
17#if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
19#elif defined(_MSC_VER)
24static constexpr inline uint64_t
Rot(uint64_t x) {
return (x << bits) | (x >> (64 - bits)); }
26static inline void SipHashRound(uint64_t& v0, uint64_t& v1, uint64_t& v2, uint64_t& v3) {
27 v0 += v1; v1 = Rot<13>(v1); v1 ^= v0;
29 v2 += v3; v3 = Rot<16>(v3); v3 ^= v2;
30 v0 += v3; v3 = Rot<21>(v3); v3 ^= v0;
31 v2 += v1; v1 = Rot<17>(v1); v1 ^= v2;
35inline uint64_t
SipHash(uint64_t k0, uint64_t k1, uint64_t
data) {
36 uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
37 uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
38 uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
39 uint64_t v3 = 0x7465646279746573ULL ^ k1 ^
data;
43 v3 ^= 0x800000000000000ULL;
46 v0 ^= 0x800000000000000ULL;
52 return v0 ^ v1 ^ v2 ^ v3;
60 template<
int BITS,
typename I>
63 static_assert(std::numeric_limits<I>::digits > 8,
"BitWriter::WriteInner needs I > 8 bits");
86 template<
int BITS,
typename I>
89 using compute_type =
typename std::conditional<
90 (std::numeric_limits<I>::digits < std::numeric_limits<unsigned>::digits),
92 return WriteInner<BITS, compute_type>(val);
107 const unsigned char*
in;
112 template<
int BITS,
typename I>
123 while (
out + 8 <= bits) {
124 val |= ((I(*(
in++))) <<
out);
128 unsigned char c = *(
in++);
129 val |= (c & ((I(1) << (bits -
out)) - 1)) <<
out;
141template<
int BITS,
typename I>
142constexpr inline I
Mask() {
return ((I((I(-1)) << (std::numeric_limits<I>::digits - BITS))) >> (std::numeric_limits<I>::digits - BITS)); }
147#if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
150 return std::bit_width(val);
151#elif defined(_MSC_VER)
155 if (std::numeric_limits<I>::digits <= 32) {
156 ret = _BitScanReverse(&index, val);
158 ret = _BitScanReverse64(&index, val);
162#elif defined(HAVE_CLZ)
164 if (val == 0)
return 0;
165 if (std::numeric_limits<unsigned>::digits >= std::numeric_limits<I>::digits) {
166 return std::numeric_limits<unsigned>::digits - __builtin_clz(val);
167 }
else if (std::numeric_limits<unsigned long>::digits >= std::numeric_limits<I>::digits) {
168 return std::numeric_limits<unsigned long>::digits - __builtin_clzl(val);
170 return std::numeric_limits<unsigned long long>::digits - __builtin_clzll(val);
173 while (max && (val >> (max - 1) == 0)) --max;
178template<
typename I,
int BITS>
181 static_assert(std::is_integral<I>::value && std::is_unsigned<I>::value,
"BitsInt requires an unsigned integer type");
182 static_assert(BITS > 0 && BITS <= std::numeric_limits<I>::digits,
"BitsInt requires 1 <= Bits <= representation type size");
184 static constexpr I
MASK = Mask<BITS, I>();
190 static constexpr int SIZE = BITS;
192 static void inline Swap(I& a, I& b) {
196 static constexpr inline bool IsZero(I a) {
return a == 0; }
197 static constexpr inline bool IsOne(I a) {
return a == 1; }
198 static constexpr inline I
Mask(I val) {
return val &
MASK; }
199 static constexpr inline I
Shift(I val,
int bits) {
return ((val << bits) &
MASK); }
200 static constexpr inline I
UnsafeShift(I val,
int bits) {
return (val << bits); }
202 template<
int Offset,
int Count>
204 static_assert(Count > 0,
"BITSInt::MidBits needs Count > 0");
205 static_assert(Count + Offset <= BITS,
"BitsInt::MidBits overflow of Count+Offset");
206 return (val >> Offset) & ((I(1) << Count) - 1);
211 static_assert(Count > 0,
"BitsInt::TopBits needs Count > 0");
212 static_assert(Count <= BITS,
"BitsInt::TopBits needs Offset <= BITS");
213 return static_cast<int>(val >> (BITS - Count));
217 return val ^ (-I(cond) & v);
222 return val ^ (-I(cond) & MOD);
225 static inline int Bits(I val,
int max) {
return CountBits<I>(val, max); }
229template<
typename F, u
int32_t MOD>
231 typedef typename F::Repr
I;
233 static inline constexpr I Call(
const I& a) {
234 return F::template CondXorWith<MOD>(F::Shift(a, 1), F::template TopBits<1>(a));
239template<
typename I,
int N,
typename L,
typename F,
int K>
struct GFMulHelper;
240template<
typename I,
int N,
typename L,
typename F>
struct GFMulHelper<I, N, L, F, 0>
242 static inline constexpr I
Run(
const I& a,
const I& b) {
return I(0); }
244template<
typename I,
int N,
typename L,
typename F,
int K>
struct GFMulHelper
253template<
typename I,
typename F,
int BITS, u
int32_t MOD>
256 if (F::IsZero(x) || F::IsOne(x))
return x;
259 int rlen = BITS + 1, newrlen = F::Bits(newr, BITS);
261 int q = rlen - newrlen;
262 r ^= F::Shift(newr, q);
263 t ^= F::UnsafeShift(newt, q);
264 rlen = F::Bits(r, rlen - 1);
268 std::swap(rlen, newrlen);
279template<
typename I,
typename F,
int BITS, I (*MUL)(I, I), I (*SQR)(I), I (*SQR2)(I), I(*SQR4)(I), I(*SQR8)(I), I(*SQR16)(I)>
282 static constexpr int INV_EXP = BITS - 1;
283 I x2 = (INV_EXP >= 2) ? MUL(SQR(x1), x1) : I();
284 I x4 = (INV_EXP >= 4) ? MUL(SQR2(x2), x2) : I();
285 I x8 = (INV_EXP >= 8) ? MUL(SQR4(x4), x4) : I();
286 I x16 = (INV_EXP >= 16) ? MUL(SQR8(x8), x8) : I();
287 I x32 = (INV_EXP >= 32) ? MUL(SQR16(x16), x16) : I();
291 }
else if (INV_EXP >= 16) {
293 }
else if (INV_EXP >= 8) {
295 }
else if (INV_EXP >= 4) {
297 }
else if (INV_EXP >= 2) {
302 if (INV_EXP >= 32 && (INV_EXP & 16)) r = MUL(SQR16(r), x16);
303 if (INV_EXP >= 16 && (INV_EXP & 8)) r = MUL(SQR8(r), x8);
304 if (INV_EXP >= 8 && (INV_EXP & 4)) r = MUL(SQR4(r), x4);
305 if (INV_EXP >= 4 && (INV_EXP & 2)) r = MUL(SQR2(r), x2);
306 if (INV_EXP >= 2 && (INV_EXP & 1)) r = MUL(SQR(r), x1);
BitReader(const unsigned char *input)
BitWriter(unsigned char *output)
static int Bits(I val, int max)
static constexpr I CondXorWith(I val, bool cond)
static constexpr int TopBits(I val)
static constexpr int SIZE
static constexpr I Shift(I val, int bits)
static constexpr I CondXorWith(I val, bool cond, I v)
static constexpr bool IsZero(I a)
static constexpr I Mask(I val)
static constexpr bool IsOne(I a)
static constexpr I UnsafeShift(I val, int bits)
static constexpr int MidBits(I val)
static void Swap(I &a, I &b)
I InvLadder(I x1)
Compute the inverse of x1 using an exponentiation ladder.
I InvExtGCD(I x)
Compute the inverse of x using an extgcd algorithm.
static void SipHashRound(uint64_t &v0, uint64_t &v1, uint64_t &v2, uint64_t &v3)
static int CountBits(I val, int max)
Compute the smallest power of two that is larger than val.
constexpr I GFMul(const I &a, const I &b)
Compute the carry-less multiplication of a and b, with N bits, using L as LFSR type.
uint64_t SipHash(uint64_t k0, uint64_t k1, uint64_t data)
static constexpr uint64_t Rot(uint64_t x)
constexpr I Mask()
Return a value of type I with its bits lowest bits set (bits must be > 0).
static constexpr I Run(const I &a, const I &b)
Helper class for carryless multiplications.
static constexpr I Run(const I &a, const I &b)
Class which implements a stateless LFSR for generic moduli.
static constexpr I Call(const I &a)
Shift a value a up once, treating it as an N-bit LFSR, with pattern MOD.