pub const PRIME: [u64; 9] = [0, 0, 0, 0, 0x9E37_79B1, 889_523_592_379, 227_718_039_650_203, 58_295_818_150_454_627, 0xCF1B_BCDC_B7A5_6463];
#[inline(always)]
pub fn hash(v: u64, mls: u32, log: u32) -> usize {
if mls == 4 {
(((v as u32).wrapping_mul(0x9E37_79B1)) >> (32 - log)) as usize
} else {
((v << (64 - 8 * mls)).wrapping_mul(PRIME[mls as usize]) >> (64 - log)) as usize
}
}
#[inline(always)]
pub fn read32(s: &[u8], i: usize) -> u32 {
u32::from_le_bytes([s[i], s[i + 1], s[i + 2], s[i + 3]])
}
#[inline(always)]
pub fn read64(s: &[u8], i: usize) -> u64 {
let mut a = [0u8; 8];
a.copy_from_slice(&s[i..i + 8]);
u64::from_le_bytes(a)
}
#[inline(always)]
pub fn count(s: &[u8], mut a: usize, mut b: usize, end: usize) -> usize {
let start = b;
while b + 8 <= end {
let x = read64(s, a) ^ read64(s, b);
if x != 0 {
return b - start + (x.trailing_zeros() / 8) as usize;
}
a += 8;
b += 8;
}
while b < end && s[a] == s[b] {
a += 1;
b += 1;
}
b - start
}
#[inline(always)]
pub fn count_dict(dict: &[u8], d: usize, src: &[u8], ip: usize, end: usize) -> usize {
let dlen = dict.len() - d;
let limit = end.min(ip + dlen);
let mut n = 0;
while ip + n + 8 <= limit {
let x = read64(dict, d + n) ^ read64(src, ip + n);
if x != 0 {
return n + (x.trailing_zeros() / 8) as usize;
}
n += 8;
}
while ip + n < limit && dict[d + n] == src[ip + n] {
n += 1;
}
if n == dlen && ip + n < end {
n += count(src, 0, ip + n, end);
}
n
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts() {
let s = b"abcdefghabcdefghabcdXfgh";
assert_eq!(count(s, 0, 8, s.len()), 12);
assert_eq!(count(s, 0, 16, s.len()), 4);
let dict = b"__abc";
let src = b"abcabcabc";
assert_eq!(count_dict(dict, 2, src, 3, src.len()), 6);
}
}