pub(crate) const NO_POSITION: usize = usize::MAX;
#[derive(Debug, Clone)]
pub(crate) struct MatchFinder<const MIN_MATCH: usize> {
head: Vec<usize>,
prev: Vec<usize>,
}
impl<const MIN_MATCH: usize> MatchFinder<MIN_MATCH> {
const HASH_BITS: u32 = match MIN_MATCH {
3 => 16,
4 => 17,
_ => panic!("match finder supports MIN_MATCH of 3 or 4"),
};
pub(crate) fn new(len: usize) -> Self {
Self {
head: vec![NO_POSITION; 1 << Self::HASH_BITS],
prev: vec![NO_POSITION; len],
}
}
fn hash(input: &[u8], pos: usize) -> usize {
let value = if MIN_MATCH == 3 {
u32::from(input[pos])
| (u32::from(input[pos + 1]) << 8)
| (u32::from(input[pos + 2]) << 16)
} else {
u32::from_le_bytes([input[pos], input[pos + 1], input[pos + 2], input[pos + 3]])
};
(value.wrapping_mul(0x9E37_79B1) >> (32 - Self::HASH_BITS)) as usize
}
pub(crate) fn insert(&mut self, input: &[u8], pos: usize) {
if pos + MIN_MATCH <= input.len() {
let hash = Self::hash(input, pos);
self.prev[pos] = self.head[hash];
self.head[hash] = pos;
}
}
pub(crate) fn first(&self, input: &[u8], pos: usize) -> usize {
self.head[Self::hash(input, pos)]
}
pub(crate) fn previous(&self, candidate: usize) -> usize {
self.prev[candidate]
}
}