use super::{MatchGeneratorDriver, Sequence, owned_sink};
impl MatchGeneratorDriver {
fn search_long_distance_to(&mut self, to: usize) {
let Some(producer) = self.ldm.as_mut() else {
return;
};
let from = self.ldm_store.searched_end();
if from >= to {
return;
}
let window = self.reported_window_size;
let reach_floor = if self.ldm_dict_end != 0 && to <= window + self.ldm_dict_end {
0
} else {
to.saturating_sub(window)
};
let live_start = self.ldm_committed_end - self.storage.committed_window().len();
let live = self.storage.window_with_pending();
let floor = reach_floor.max(live_start);
debug_assert!(floor <= from, "a search range wider than the window");
self.ldm_found.clear();
producer.generate_into(
&live[floor - live_start..],
floor,
from,
to,
&mut self.ldm_found,
);
self.ldm_store.searched(&self.ldm_found, to);
}
fn align_long_distance_store(&mut self, at: usize) {
if self.ldm_store.taken_end() != at {
self.ldm_store.reset(at);
}
}
pub(super) fn take_long_distance_block(&mut self) -> usize {
let block_len = self.storage.last_block_len();
let block_end = self.ldm_committed_end;
self.align_long_distance_store(block_end - block_len);
self.search_long_distance_to(block_end);
let min_match = self.reset_shape.map_or(
crate::encoding::cost_model::HC_FORMAT_MINMATCH,
|(params, ..)| params.min_match(),
);
self.ldm_store
.take(block_len, min_match, &mut self.ldm_block);
block_len
}
pub(super) fn settle_long_distance_cut(&mut self, window: usize, cut: usize) -> usize {
if self.ldm.is_none() {
return cut;
}
let start = self.ldm_committed_end;
self.align_long_distance_store(start);
self.search_long_distance_to(start + window);
self.ldm_store.cut_outside_matches(window, cut)
}
pub(super) fn start_matching_long_distance(
&mut self,
handle_sequence: &mut impl FnMut(Sequence),
) -> bool {
let block_len = self.take_long_distance_block();
if self.ldm_block.is_empty() {
return false;
}
let sequences = core::mem::take(&mut self.ldm_block);
self.storage.uncommit_block(block_len);
let mut consumed = 0usize;
for seq in &sequences {
let mut gap = Some(0usize);
if seq.lit_length != 0 {
self.storage.commit_piece(seq.lit_length);
self.start_matching_owned(&mut owned_sink(handle_sequence, &mut gap));
}
let gap_literals = gap.expect("the gap sink only ever writes Some");
self.storage.commit_piece(seq.match_length);
self.storage.skip_long_match();
handle_sequence(Sequence::Triple {
literal_len: gap_literals,
offset: seq.offset,
match_len: seq.match_length,
});
self.storage.note_long_match(seq.offset, gap_literals);
consumed += seq.lit_length + seq.match_length;
}
let tail = block_len - consumed;
if tail != 0 {
self.storage.commit_piece(tail);
let mut forward = None;
self.start_matching_owned(&mut owned_sink(handle_sequence, &mut forward));
}
self.ldm_block = sequences;
self.ldm_split_block = Some(block_len);
true
}
}