Skip to main content

zstd_complete/encoding/match_generator/
driver.rs

1use super::*;
2
3/// This is the default implementation of the `Matcher` trait. It allocates and reuses the buffers when possible.
4pub struct MatchGeneratorDriver {
5    pub(super) vec_pool: Vec<Vec<u8>>,
6    pub(super) suffix_pool: Vec<SuffixStore>,
7    pub(super) match_generator: MatchGenerator,
8    pub(super) slice_size: usize,
9    pub(super) suffix_store_capacity: usize,
10    pub(super) adaptive_binary_no_match_probe: bool,
11    pub(super) use_fast_small_dense_binary_probe: bool,
12    pub(super) prefer_binary_next_position_repeat_lookahead: bool,
13    pub(super) prefer_fast_binary_next_position_repeat_lookahead: bool,
14    pub(super) prefer_binary_next_position_lookahead: bool,
15    pub(super) prefer_oldest_first_window_probe: bool,
16    pub(super) use_complementary_end_insertion: bool,
17    pub(super) use_second_newest_probe: bool,
18    pub(super) use_fast_binary_small_second_newest: bool,
19    pub(super) use_text_repeat_pipeline: bool,
20    pub(super) file_type_hint: CompressionFileType,
21    pub(super) file_profile_hint: CompressionFileProfile,
22}
23
24impl MatchGeneratorDriver {
25    /// slice_size says how big the slices should be that are allocated to work with
26    /// max_slices_in_window says how many slices should at most be used while looking for matches
27    pub(crate) fn new(slice_size: usize, max_slices_in_window: usize) -> Self {
28        Self {
29            vec_pool: Vec::new(),
30            suffix_pool: Vec::new(),
31            match_generator: MatchGenerator::new(max_slices_in_window * slice_size),
32            slice_size,
33            suffix_store_capacity: slice_size / SUFFIX_STORE_CAPACITY_DIVISOR,
34            adaptive_binary_no_match_probe: false,
35            use_fast_small_dense_binary_probe: false,
36            prefer_binary_next_position_repeat_lookahead: false,
37            prefer_fast_binary_next_position_repeat_lookahead: false,
38            prefer_binary_next_position_lookahead: false,
39            prefer_oldest_first_window_probe: false,
40            use_complementary_end_insertion: false,
41            use_second_newest_probe: false,
42            use_fast_binary_small_second_newest: false,
43            use_text_repeat_pipeline: false,
44            file_type_hint: CompressionFileType::Unknown,
45            file_profile_hint: CompressionFileProfile::None,
46        }
47    }
48
49    #[cfg(test)]
50    pub(crate) fn repeat_offsets(&self) -> (u32, u32, u32) {
51        self.match_generator.offset_history.as_offsets()
52    }
53
54    #[cfg(all(test, feature = "std"))]
55    pub(crate) fn diagnostics(&self) -> Ref<'_, MatcherDiagnostics> {
56        self.match_generator.diagnostics.borrow()
57    }
58}
59
60impl Matcher for MatchGeneratorDriver {
61    fn set_file_type_hint(&mut self, file_type: CompressionFileType) {
62        self.file_type_hint = file_type;
63        self.match_generator.file_type_hint = file_type;
64    }
65
66    fn set_internal_file_profile_hint(&mut self, file_profile_code: u8) {
67        let file_profile = CompressionFileProfile::from_internal_hint_code(file_profile_code);
68        self.file_profile_hint = file_profile;
69        self.match_generator.file_profile_hint = file_profile;
70    }
71
72    fn reset(&mut self, level: CompressionLevel) {
73        let vec_pool = &mut self.vec_pool;
74        let suffix_pool = &mut self.suffix_pool;
75        let fast_window_size = self.slice_size * FASTEST_WINDOW_BLOCKS;
76        self.suffix_store_capacity = Self::suffix_store_capacity(self.slice_size, level);
77        self.adaptive_binary_no_match_probe = Self::adaptive_binary_no_match_probe(level);
78        self.use_fast_small_dense_binary_probe = Self::use_fast_small_dense_binary_probe(level);
79        self.prefer_binary_next_position_repeat_lookahead =
80            Self::prefer_binary_next_position_repeat_lookahead(level);
81        self.prefer_fast_binary_next_position_repeat_lookahead =
82            Self::prefer_fast_binary_next_position_repeat_lookahead(level);
83        self.prefer_binary_next_position_lookahead =
84            Self::prefer_binary_next_position_lookahead(level);
85        self.prefer_oldest_first_window_probe = Self::prefer_oldest_first_window_probe(level);
86        self.use_complementary_end_insertion = Self::use_complementary_end_insertion(level);
87        self.use_second_newest_probe = Self::use_second_newest_probe(level);
88        self.use_fast_binary_small_second_newest = Self::use_fast_binary_small_second_newest(level);
89        self.use_text_repeat_pipeline = Self::use_text_repeat_pipeline(level);
90
91        self.match_generator.reset(|mut data, mut suffixes| {
92            data.resize(data.capacity(), 0);
93            vec_pool.push(data);
94            suffixes.clear();
95            suffix_pool.push(suffixes);
96        });
97        self.match_generator.set_window_sizes(
98            self.slice_size * Self::window_blocks(level),
99            fast_window_size,
100        );
101        self.match_generator.adaptive_binary_no_match_probe = self.adaptive_binary_no_match_probe;
102        self.match_generator.use_fast_small_dense_binary_probe =
103            self.use_fast_small_dense_binary_probe;
104        self.match_generator
105            .prefer_binary_next_position_repeat_lookahead =
106            self.prefer_binary_next_position_repeat_lookahead;
107        self.match_generator
108            .prefer_fast_binary_next_position_repeat_lookahead =
109            self.prefer_fast_binary_next_position_repeat_lookahead;
110        self.match_generator.prefer_binary_next_position_lookahead =
111            self.prefer_binary_next_position_lookahead;
112        self.match_generator.prefer_oldest_first_window_probe =
113            self.prefer_oldest_first_window_probe;
114        self.match_generator.use_complementary_end_insertion = self.use_complementary_end_insertion;
115        self.match_generator.use_second_newest_probe = self.use_second_newest_probe;
116        self.match_generator.use_fast_binary_small_second_newest =
117            self.use_fast_binary_small_second_newest;
118        self.match_generator.use_text_repeat_pipeline = self.use_text_repeat_pipeline;
119        self.match_generator.file_type_hint = self.file_type_hint;
120        self.match_generator.file_profile_hint = self.file_profile_hint;
121    }
122
123    fn window_size(&self) -> u64 {
124        self.match_generator.max_window_size as u64
125    }
126
127    fn get_next_space(&mut self) -> Vec<u8> {
128        match self.vec_pool.pop() {
129            Some(space) => space,
130            None => {
131                let mut space = alloc::vec![0; self.slice_size];
132                space.resize(space.capacity(), 0);
133                space
134            }
135        }
136    }
137
138    fn get_last_space(&self) -> &[u8] {
139        self.match_generator.last_entry().data.as_slice()
140    }
141
142    fn commit_space(&mut self, space: Vec<u8>) {
143        let vec_pool = &mut self.vec_pool;
144        let suffix_capacity = self.suffix_store_capacity;
145        let suffixes = match self.suffix_pool.pop() {
146            Some(suffixes)
147                if suffixes.capacity() == SuffixStore::normalized_capacity(suffix_capacity) =>
148            {
149                suffixes
150            }
151            _ => SuffixStore::with_capacity(suffix_capacity),
152        };
153        let suffix_pool = &mut self.suffix_pool;
154        self.match_generator
155            .add_data(space, suffixes, |mut data, mut suffixes| {
156                data.resize(data.capacity(), 0);
157                vec_pool.push(data);
158                suffixes.clear();
159                suffix_pool.push(suffixes);
160            });
161    }
162
163    fn start_matching(&mut self, mut handle_sequence: impl for<'a> FnMut(Sequence<'a>)) {
164        while self.match_generator.next_sequence(&mut handle_sequence) {}
165    }
166
167    fn set_repeat_offsets(&mut self, newest: u32, second: u32, third: u32) {
168        self.match_generator.offset_history = OffsetHistory::from_offsets(newest, second, third);
169    }
170
171    fn skip_matching(&mut self) {
172        self.match_generator.skip_matching();
173    }
174
175    fn skip_matching_for_incompressible(&mut self) {
176        self.match_generator.skip_matching_for_incompressible();
177    }
178
179    fn skip_matching_for_rle(&mut self) {
180        self.match_generator.skip_matching_for_rle();
181    }
182}
183
184impl MatchGeneratorDriver {
185    fn window_blocks(level: CompressionLevel) -> usize {
186        if level.uses_best_legacy_profile() {
187            BEST_WINDOW_BLOCKS
188        } else {
189            FASTEST_WINDOW_BLOCKS
190        }
191    }
192
193    fn suffix_store_capacity(slice_size: usize, level: CompressionLevel) -> usize {
194        if level.uses_best_legacy_profile() {
195            slice_size * BEST_SUFFIX_STORE_CAPACITY_MULTIPLIER
196        } else {
197            slice_size / SUFFIX_STORE_CAPACITY_DIVISOR
198        }
199    }
200
201    fn adaptive_binary_no_match_probe(level: CompressionLevel) -> bool {
202        level.uses_best_legacy_profile()
203    }
204
205    fn use_fast_small_dense_binary_probe(level: CompressionLevel) -> bool {
206        level.uses_fastest_legacy_profile()
207    }
208
209    fn prefer_binary_next_position_repeat_lookahead(level: CompressionLevel) -> bool {
210        level.uses_best_legacy_profile()
211    }
212
213    fn prefer_fast_binary_next_position_repeat_lookahead(level: CompressionLevel) -> bool {
214        level.uses_fastest_legacy_profile()
215    }
216
217    fn prefer_binary_next_position_lookahead(level: CompressionLevel) -> bool {
218        level.uses_best_legacy_profile()
219    }
220
221    fn prefer_oldest_first_window_probe(level: CompressionLevel) -> bool {
222        level.uses_best_legacy_profile()
223    }
224
225    fn use_complementary_end_insertion(level: CompressionLevel) -> bool {
226        level.uses_best_legacy_profile()
227    }
228
229    fn use_second_newest_probe(level: CompressionLevel) -> bool {
230        level.uses_best_legacy_profile()
231    }
232
233    fn use_fast_binary_small_second_newest(level: CompressionLevel) -> bool {
234        level.uses_fastest_legacy_profile()
235    }
236
237    fn use_text_repeat_pipeline(level: CompressionLevel) -> bool {
238        level.uses_best_legacy_profile()
239    }
240}