use alloc::vec::Vec;
use crate::encoding::opt::ldm::HcRawSeq;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct LongMatch {
start: usize,
end: usize,
offset: usize,
}
#[derive(Default)]
pub(crate) struct LdmSequenceStore {
matches: Vec<LongMatch>,
pos: usize,
taken_end: usize,
searched_end: usize,
}
impl LdmSequenceStore {
pub(crate) fn reset(&mut self, at: usize) {
self.matches.clear();
self.pos = 0;
self.taken_end = at;
self.searched_end = at;
}
pub(crate) fn searched_end(&self) -> usize {
self.searched_end
}
pub(crate) fn taken_end(&self) -> usize {
self.taken_end
}
pub(crate) fn heap_size(&self) -> usize {
self.matches.capacity() * core::mem::size_of::<LongMatch>()
}
pub(crate) fn searched(&mut self, found: &[HcRawSeq], to: usize) {
let mut at = self.searched_end;
for seq in found {
let start = at + seq.lit_length;
let end = start + seq.match_length;
self.matches.push(LongMatch {
start,
end,
offset: seq.offset,
});
at = end;
}
debug_assert!(at <= to, "a sequence reaches past the searched range");
self.searched_end = to;
}
pub(crate) fn cut_outside_matches(&self, window: usize, cut: usize) -> usize {
let cut_at = self.taken_end + cut;
for found in &self.matches[self.pos..] {
if found.start >= cut_at {
break;
}
if cut_at < found.end {
return (found.end - self.taken_end).min(window);
}
}
cut
}
pub(crate) fn take(&mut self, len: usize, min_match: usize, out: &mut Vec<HcRawSeq>) {
out.clear();
let block_end = self.taken_end + len;
let mut at = self.taken_end;
while let Some(&found) = self.matches.get(self.pos) {
if found.start >= block_end {
break;
}
let start = found.start.max(self.taken_end);
let end = found.end.min(block_end);
if end - start >= min_match {
out.push(HcRawSeq {
lit_length: start - at,
offset: found.offset,
match_length: end - start,
});
at = end;
}
if found.end > block_end {
break;
}
self.pos += 1;
}
self.taken_end = block_end;
if self.pos > self.matches.len() / 2 {
self.matches.drain(..self.pos);
self.pos = 0;
}
}
}
#[cfg(test)]
mod tests;