use vyre_libs::scan::LiteralMatch;
pub const DENSE_PHASE2_MIN_HITS: usize = 100_000;
pub const DENSE_PHASE2_BYTES_PER_HIT: usize = 128;
#[must_use]
pub fn gpu_phase2_hits_are_dense(
match_count: usize,
buffer_len: usize,
chunk_count: usize,
) -> bool {
match_count >= DENSE_PHASE2_MIN_HITS
&& chunk_count > 1
&& match_count.saturating_mul(DENSE_PHASE2_BYTES_PER_HIT) >= buffer_len
}
pub fn fold_overlapping_same_pid_inplace(matches: &mut Vec<LiteralMatch>) {
matches.sort_unstable_by(|a, b| {
a.pattern_id
.cmp(&b.pattern_id)
.then(a.start.cmp(&b.start))
.then(a.end.cmp(&b.end))
});
let mut write = 0;
for read in 1..matches.len() {
if matches[read].pattern_id == matches[write].pattern_id
&& matches[read].start <= matches[write].end
{
if matches[read].end > matches[write].end {
matches[write].end = matches[read].end;
}
} else {
write += 1;
matches[write] = matches[read];
}
}
if !matches.is_empty() {
matches.truncate(write + 1);
}
matches.sort_unstable_by_key(|matched| matched.start);
}
pub fn attribute_matches_to_chunks(
matches: &[LiteralMatch],
entries: &[(usize, usize, usize)],
total_patterns: usize,
chunk_count: usize,
) -> Vec<Vec<(u32, u32, u32)>> {
let mut per_chunk_hits: Vec<Vec<(u32, u32, u32)>> =
(0..chunk_count).map(|_| Vec::new()).collect();
let mut cursor = 0usize;
for matched in matches {
let global_start = matched.start as usize;
let global_end = matched.end as usize;
while cursor < entries.len() {
let (_, offset, len) = entries[cursor];
if global_start < offset + len {
break;
}
cursor += 1;
}
if cursor >= entries.len() {
break;
}
let (chunk_index, offset, len) = entries[cursor];
if global_start < offset || global_end > offset + len {
continue;
}
let pattern_index = matched.pattern_id as usize;
if pattern_index < total_patterns {
let local_start = (global_start - offset) as u32;
let local_end = (global_end - offset) as u32;
per_chunk_hits[chunk_index].push((matched.pattern_id, local_start, local_end));
}
}
per_chunk_hits
}