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)
31 v2 += v1; v1 =
Rot<17>(v1); v1 ^= v2;
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>
90 (std::numeric_limits<I>::digits < std::numeric_limits<unsigned>::digits),
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;
130 state =
c >> (bits - out);
131 offset = 8 - (bits - 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) {
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");
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);
229template<
typename F, u
int32_t MOD>
231 typedef typename F::Repr
I;
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;
262 r ^= F::Shift(
newr, q);
263 t ^= F::UnsafeShift(
newt, q);
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;
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.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.