use alloc::vec::Vec;
use fearless_simd::Simd;
use super::context::SharedContextInner;
use crate::shared::match_len::{common_prefix_len, common_prefix_len_simd};
use crate::shared::score::{
SearchResult, backward_reference_penalty_using_last_distance, backward_reference_score,
backward_reference_score_using_last_distance,
};
const MIN_CHAIN_MATCH: usize = 4;
const MIN_CACHED_MATCH: usize = 2;
const MIN_PREFILTER_LEN: usize = 3;
const CACHED_DISTANCES: usize = 4;
impl SharedContextInner {
pub(crate) fn total_size(&self) -> usize {
self.dictionaries().prefix().total_len() as usize
}
#[expect(
clippy::too_many_arguments,
reason = "mirrors LookupCompoundDictionaryMatch, whose parameters are all needed"
)]
pub(crate) fn find_match<S: Simd>(
&self,
simd: S,
data: &[u8],
ring_buffer_mask: usize,
distance_cache: &[i32],
cur_ix: usize,
max_length: usize,
max_ring_buffer_distance: usize,
max_distance: usize,
out: &mut SearchResult,
) {
simd.vectorize(
#[inline(always)]
|| {
let sources = self.dictionaries().prefix();
let base_offset = max_ring_buffer_distance + self.total_size();
for attachment in 0..sources.segment_count() {
let Some(index) = self.prepared_prefix(attachment) else {
continue;
};
let source = sources.segment(attachment);
let chunk_start = sources.segment_start(attachment) as usize;
find_in_attachment(
simd,
index,
source,
data,
ring_buffer_mask,
distance_cache,
cur_ix,
max_length,
base_offset - chunk_start,
max_distance,
out,
);
}
},
);
}
#[expect(
clippy::too_many_arguments,
reason = "mirrors LookupAllCompoundDictionaryMatches, whose parameters are all needed"
)]
pub(crate) fn find_all_matches(
&self,
data: &[u8],
ring_buffer_mask: usize,
cur_ix: usize,
min_length: usize,
max_length: usize,
max_ring_buffer_distance: usize,
max_distance: usize,
match_limit: usize,
found: &mut Vec<(usize, usize)>,
) -> usize {
let sources = self.dictionaries().prefix();
let base_offset = max_ring_buffer_distance + self.total_size();
let mut min_length = min_length;
let mut total = 0usize;
for attachment in 0..sources.segment_count() {
if total == match_limit {
break;
}
let Some(index) = self.prepared_prefix(attachment) else {
continue;
};
let source = sources.segment(attachment);
let chunk_start = sources.segment_start(attachment) as usize;
total += find_all_in_attachment(
index,
source,
data,
ring_buffer_mask,
cur_ix,
min_length,
max_length,
base_offset - chunk_start,
max_distance,
match_limit - total,
found,
);
if total == match_limit {
break;
}
if let Some(&(_, length)) = found.last() {
min_length = length;
}
}
total
}
}
#[expect(
clippy::too_many_arguments,
reason = "mirrors FindCompoundDictionaryMatch, whose parameters are all needed"
)]
#[inline(always)]
fn find_in_attachment<S: Simd>(
simd: S,
index: &super::prepared::PreparedPrefix,
source: &[u8],
data: &[u8],
ring_buffer_mask: usize,
distance_cache: &[i32],
cur_ix: usize,
max_length: usize,
distance_offset: usize,
max_distance: usize,
out: &mut SearchResult,
) {
let source_size = source.len();
let boundary = distance_offset.saturating_sub(source_size);
let cur_ix_masked = cur_ix & ring_buffer_mask;
let Some(target) = data.get(cur_ix_masked..) else {
return;
};
let Some(head) = target
.first_chunk::<8>()
.map(|bytes| u64::from_le_bytes(*bytes))
else {
return;
};
let mut best_score = out.score;
let mut best_len = out.len;
for (rank, &cached) in distance_cache.iter().take(CACHED_DISTANCES).enumerate() {
let distance = cached as usize;
if distance <= boundary || distance > distance_offset {
continue;
}
let offset = distance_offset - distance;
let Some(candidate) = source.get(offset..) else {
continue;
};
let limit = candidate.len().min(max_length);
let length = common_prefix_len_simd(simd, candidate, target, limit);
if length < MIN_CACHED_MATCH {
continue;
}
let mut score = backward_reference_score_using_last_distance(length);
if best_score >= score {
continue;
}
if rank != 0 {
score = score.saturating_sub(backward_reference_penalty_using_last_distance(rank));
}
if best_score < score {
best_score = score;
best_len = best_len.max(length);
out.len = length;
out.len_code_delta = 0;
out.distance = distance;
out.score = score;
}
}
best_len = best_len.max(MIN_PREFILTER_LEN);
for item in index.candidates(head) {
let offset = item as usize;
let distance = distance_offset - offset;
if distance > max_distance {
continue;
}
let Some(candidate) = source.get(offset..) else {
continue;
};
let limit = candidate.len().min(max_length);
if cur_ix_masked + best_len > ring_buffer_mask || best_len >= limit {
continue;
}
let (Some(left), Some(right)) = (
candidate
.get(best_len - MIN_PREFILTER_LEN..)
.and_then(<[u8]>::first_chunk::<4>),
target
.get(best_len - MIN_PREFILTER_LEN..)
.and_then(<[u8]>::first_chunk::<4>),
) else {
continue;
};
if left != right {
continue;
}
let length = common_prefix_len_simd(simd, candidate, target, limit);
if length < MIN_CHAIN_MATCH {
continue;
}
let score = backward_reference_score(length, distance);
if best_score < score {
best_score = score;
best_len = length;
out.len = length;
out.len_code_delta = 0;
out.distance = distance;
out.score = score;
}
}
}
#[expect(
clippy::too_many_arguments,
reason = "mirrors FindAllCompoundDictionaryMatches, whose parameters are all needed"
)]
fn find_all_in_attachment(
index: &super::prepared::PreparedPrefix,
source: &[u8],
data: &[u8],
ring_buffer_mask: usize,
cur_ix: usize,
min_length: usize,
max_length: usize,
distance_offset: usize,
max_distance: usize,
match_limit: usize,
found: &mut Vec<(usize, usize)>,
) -> usize {
if match_limit == 0 {
return 0;
}
let cur_ix_masked = cur_ix & ring_buffer_mask;
let Some(target) = data.get(cur_ix_masked..) else {
return 0;
};
let Some(head) = target
.first_chunk::<8>()
.map(|bytes| u64::from_le_bytes(*bytes))
else {
return 0;
};
let mut best_len = min_length;
let mut count = 0usize;
for item in index.candidates(head) {
let offset = item as usize;
let distance = distance_offset - offset;
if distance > max_distance {
continue;
}
let Some(candidate) = source.get(offset..) else {
continue;
};
let limit = candidate.len().min(max_length);
if cur_ix_masked + best_len > ring_buffer_mask || best_len >= limit {
continue;
}
if candidate.get(best_len) != target.get(best_len) {
continue;
}
let length = common_prefix_len(candidate, target, limit);
if length > best_len {
best_len = length;
found.push((distance, length));
count += 1;
if count == match_limit {
break;
}
}
}
count
}