1#![forbid(unsafe_code)]
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Strategy {
6 Fast,
8 DFast,
10}
11
12#[derive(Debug, Clone, Copy)]
14pub struct LdmParams {
15 pub hash_log: u32,
16 pub bucket_size_log: u32,
17 pub min_match_length: u32,
18 pub hash_rate_log: u32,
19}
20
21impl LdmParams {
22 pub fn default_for_window_log(window_log: u32) -> Self {
23 let hash_log = 20u32.min(window_log.saturating_sub(1));
24 let hash_rate_log = window_log.saturating_sub(hash_log).max(7);
25 Self {
26 hash_log,
27 bucket_size_log: 4,
28 min_match_length: 64,
29 hash_rate_log,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Copy)]
39pub struct LevelParams {
40 pub strategy: Strategy,
41 pub window_log: u32,
42 pub hash_log: u32,
43 pub chain_log: u32,
45 pub search_log: u32,
46 pub min_match: u32,
47 pub target_length: u32,
48 pub search_strength: u32,
49 pub force_raw_literals: bool,
50 #[cfg(feature = "ldm")]
51 pub ldm_params: Option<LdmParams>,
52}
53
54impl LevelParams {
55 #[must_use]
56 pub fn with_window_log(mut self, window_log: u32) -> Self {
57 self.window_log = window_log;
58 self
59 }
60
61 #[cfg(feature = "ldm")]
62 #[must_use]
63 pub fn with_ldm(mut self, params: LdmParams) -> Self {
64 self.ldm_params = Some(params);
65 self
66 }
67}
68
69pub const DEFAULT_LEVEL: i32 = 1;
71
72pub fn level_params(level: i32) -> Option<LevelParams> {
77 level_params_for_size(level, usize::MAX)
78}
79
80pub fn level_params_for_size(level: i32, src_len: usize) -> Option<LevelParams> {
86 let mut params = level_params_inner(level)?;
87 params.hash_log = params.hash_log.clamp(HASH_LOG_MIN, HASH_LOG_MAX);
88 params.chain_log = params.chain_log.clamp(HASH_LOG_MIN, HASH_LOG_MAX);
89 params.window_log = params.window_log.clamp(WINDOW_LOG_MIN, WINDOW_LOG_MAX);
90 if (2..usize::MAX).contains(&src_len) {
91 let src_log = 32 - ((src_len as u32) - 1).leading_zeros();
92 params.hash_log = params.hash_log.min(src_log).max(HASH_LOG_MIN);
93 params.chain_log = params.chain_log.min(src_log).max(HASH_LOG_MIN);
94 params.window_log = params.window_log.min(src_log);
95 }
96 if level == -7 && src_len <= 16 * 1024 {
98 params.hash_log = params.hash_log.min(13);
99 params.chain_log = params.chain_log.min(13);
100 params.target_length = 6;
101 }
102 if level == 3 && (32 * 1024..=128 * 1024).contains(&src_len) {
103 params.search_strength = 7;
104 }
105 Some(params)
106}
107
108pub const HASH_LOG_MIN: u32 = 6;
109pub const HASH_LOG_MAX: u32 = 30;
110pub const WINDOW_LOG_MIN: u32 = 10;
111pub const WINDOW_LOG_MAX: u32 = 27;
112
113pub fn apply_raw_literals_size_override(params: &mut LevelParams, input_len: usize) {
114 if params.strategy != Strategy::Fast || params.force_raw_literals {
115 return;
116 }
117 if params.min_match < 5 || params.target_length != 7 {
118 return;
119 }
120 if input_len <= 16384 {
121 params.force_raw_literals = true;
122 }
123}
124
125pub(crate) fn use_custom_sequence_tables(params: &LevelParams, input_len: usize) -> bool {
126 if params.strategy == Strategy::Fast && params.min_match >= 5 && params.hash_log <= 13 {
127 return false;
128 }
129
130 if (32768..=zrip_core::frame::MAX_BLOCK_SIZE).contains(&input_len)
131 && params.strategy == Strategy::DFast
132 && params.min_match == 4
133 && params.target_length == 1
134 && params.search_strength < 5
135 {
136 return false;
137 }
138 true
139}
140
141pub fn max_hash_log(level: i32) -> Option<u32> {
144 let p = level_params_inner(level)?;
145 Some(p.hash_log.max(p.chain_log))
146}
147
148fn level_params_inner(level: i32) -> Option<LevelParams> {
149 Some(match level {
150 0 => return level_params_inner(DEFAULT_LEVEL),
151 -8 => LevelParams {
152 strategy: Strategy::Fast,
153 window_log: 19,
154 hash_log: 13,
155 chain_log: 13,
156 search_log: 0,
157 min_match: 5,
158 target_length: 7,
159 search_strength: 7,
160 force_raw_literals: true,
161 #[cfg(feature = "ldm")]
162 ldm_params: None,
163 },
164 -7 => LevelParams {
165 strategy: Strategy::Fast,
166 window_log: 19,
167 hash_log: 14,
168 chain_log: 14,
169 search_log: 0,
170 min_match: 5,
171 target_length: 9,
172 search_strength: 7,
173 force_raw_literals: false,
174 #[cfg(feature = "ldm")]
175 ldm_params: None,
176 },
177 -6 => LevelParams {
178 strategy: Strategy::Fast,
179 window_log: 19,
180 hash_log: 14,
181 chain_log: 14,
182 search_log: 0,
183 min_match: 5,
184 target_length: 7,
185 search_strength: 7,
186 force_raw_literals: false,
187 #[cfg(feature = "ldm")]
188 ldm_params: None,
189 },
190 -5 => LevelParams {
191 strategy: Strategy::Fast,
192 window_log: 19,
193 hash_log: 14,
194 chain_log: 14,
195 search_log: 0,
196 min_match: 5,
197 target_length: 6,
198 search_strength: 7,
199 force_raw_literals: false,
200 #[cfg(feature = "ldm")]
201 ldm_params: None,
202 },
203 -4 => LevelParams {
204 strategy: Strategy::Fast,
205 window_log: 19,
206 hash_log: 14,
207 chain_log: 14,
208 search_log: 0,
209 min_match: 5,
210 target_length: 5,
211 search_strength: 7,
212 force_raw_literals: false,
213 #[cfg(feature = "ldm")]
214 ldm_params: None,
215 },
216 -3 => LevelParams {
217 strategy: Strategy::Fast,
218 window_log: 19,
219 hash_log: 14,
220 chain_log: 14,
221 search_log: 0,
222 min_match: 5,
223 target_length: 4,
224 search_strength: 7,
225 force_raw_literals: false,
226 #[cfg(feature = "ldm")]
227 ldm_params: None,
228 },
229 -2 => LevelParams {
230 strategy: Strategy::Fast,
231 window_log: 19,
232 hash_log: 14,
233 chain_log: 14,
234 search_log: 0,
235 min_match: 5,
236 target_length: 3,
237 search_strength: 7,
238 force_raw_literals: false,
239 #[cfg(feature = "ldm")]
240 ldm_params: None,
241 },
242 -1 => LevelParams {
243 strategy: Strategy::Fast,
244 window_log: 19,
245 hash_log: 14,
246 chain_log: 14,
247 search_log: 0,
248 min_match: 5,
249 target_length: 2,
250 search_strength: 7,
251 force_raw_literals: false,
252 #[cfg(feature = "ldm")]
253 ldm_params: None,
254 },
255 1 => LevelParams {
256 strategy: Strategy::Fast,
257 window_log: 19,
258 hash_log: 14,
259 chain_log: 14,
260 search_log: 0,
261 min_match: 4,
262 target_length: 1,
263 search_strength: 8,
264 force_raw_literals: false,
265 #[cfg(feature = "ldm")]
266 ldm_params: None,
267 },
268 2 => LevelParams {
269 strategy: Strategy::Fast,
270 window_log: 20,
271 hash_log: 17,
272 chain_log: 17,
273 search_log: 0,
274 min_match: 4,
275 target_length: 1,
276 search_strength: 8,
277 force_raw_literals: false,
278 #[cfg(feature = "ldm")]
279 ldm_params: None,
280 },
281 3 => LevelParams {
282 strategy: Strategy::DFast,
283 window_log: 21,
284 hash_log: 18,
285 chain_log: 18,
286 search_log: 1,
287 min_match: 4,
288 target_length: 1,
289 search_strength: 5,
290 force_raw_literals: false,
291 #[cfg(feature = "ldm")]
292 ldm_params: None,
293 },
294 4 => LevelParams {
295 strategy: Strategy::DFast,
296 window_log: 24,
297 hash_log: 20,
298 chain_log: 20,
299 search_log: 0,
300 min_match: 4,
301 target_length: 1,
302 search_strength: 8,
303 force_raw_literals: false,
304 #[cfg(feature = "ldm")]
305 ldm_params: None,
306 },
307 _ => return None,
308 })
309}
310
311#[derive(Debug, Clone, Default)]
316pub struct Options {
317 pub(crate) window_log: Option<u32>,
318 #[cfg_attr(not(feature = "ldm"), allow(dead_code))]
319 pub(crate) ldm: bool,
320}
321
322impl Options {
323 #[must_use]
324 pub fn window_log(mut self, log: u32) -> Self {
325 self.window_log = Some(log);
326 self
327 }
328
329 #[cfg(feature = "ldm")]
330 #[must_use]
331 pub fn ldm(mut self, enable: bool) -> Self {
332 self.ldm = enable;
333 self
334 }
335}
336
337pub fn apply_options(params: &mut LevelParams, opts: &Options) {
338 if let Some(wl) = opts.window_log {
339 params.window_log = wl.clamp(WINDOW_LOG_MIN, WINDOW_LOG_MAX);
340 }
341 #[cfg(feature = "ldm")]
342 if opts.ldm {
343 params.ldm_params = Some(LdmParams::default_for_window_log(params.window_log));
344 }
345}