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