Skip to main content

lzip_parallel/
deflate_scan.rs

1//! DEFLATE full-flush boundary scanner — crate-local parallel split.
2//!
3//! The SIMD scanner itself now lives in the shared `linflate` crate
4//! (`linflate::deflate_scan`); this module keeps only this codec's rayon-based
5//! parallel split-point search, which uses the crate's own thread pool.
6
7use linflate::deflate_scan::find_next_flush;
8use rayon::prelude::*;
9
10pub use linflate::deflate_scan::{FlushBoundary, find_all_flushes};
11
12/// Parallel split-point search: Nāˆ’1 rayon tasks each find the nearest flush
13/// boundary at or after their nominal byte offset.
14///
15/// `n_splits` is typically the number of physical cores.
16/// Returns up to `n_splits āˆ’ 1` boundaries, sorted and deduplicated.
17pub fn split_boundaries_parallel(buf: &[u8], n_splits: usize) -> Vec<FlushBoundary> {
18    if n_splits <= 1 || buf.len() < 8 {
19        return Vec::new();
20    }
21
22    let mut found: Vec<Option<FlushBoundary>> = crate::thread_pool().install(|| {
23        (1..n_splits)
24            .into_par_iter()
25            .map(|i| {
26                let nominal = buf.len() * i / n_splits;
27                find_next_flush(buf, nominal)
28            })
29            .collect()
30    });
31
32    let mut result: Vec<FlushBoundary> = found.drain(..).flatten().collect();
33    result.sort_by_key(|b| b.start);
34    result.dedup_by_key(|b| b.start);
35    result
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    fn make_flush_marker() -> Vec<u8> {
43        vec![0x00, 0x00, 0x00, 0xFF, 0xFF]
44    }
45
46    #[test]
47    fn split_finds_markers() {
48        let mut buf = Vec::new();
49        buf.extend_from_slice(&[0xAA; 32]);
50        buf.extend_from_slice(&make_flush_marker());
51        buf.extend_from_slice(&[0xBB; 32]);
52        // Raw pattern scan must locate the synthetic boundary.
53        let all = find_all_flushes(&buf);
54        assert_eq!(all.len(), 1);
55        assert_eq!(all[0].start, 37);
56    }
57}