1use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
2use core;
3use core::cmp::min;
4
5use super::{
6 fix_unbroken_len, kHashMul32, AnyHasher, BrotliEncoderParams, CloneWithAlloc, H9Opts,
7 HasherSearchResult, HowPrepared, Struct1,
8};
9use crate::enc::combined_alloc::allocate;
10use crate::enc::static_dict::{
11 BrotliDictionary, FindMatchLengthWithLimit, BROTLI_UNALIGNED_LOAD32,
12};
13use crate::enc::util::floatX;
14
15pub const kInfinity: floatX = 1.7e38;
16
17#[derive(Clone, Copy, Debug)]
18pub enum Union1 {
19 cost(floatX),
20 next(u32),
21 shortcut(u32),
22}
23
24#[derive(Clone, Copy, Debug)]
25pub struct ZopfliNode {
26 pub length: u32,
28 pub distance: u32,
30 pub dcode_insert_length: u32,
32 pub u: Union1,
33}
34impl Default for ZopfliNode {
35 fn default() -> Self {
36 ZopfliNode {
37 length: 1,
38 distance: 0,
39 dcode_insert_length: 0,
40 u: Union1::cost(kInfinity),
41 }
42 }
43}
44
45pub trait Allocable<T: Copy, AllocT: Allocator<T>> {
46 fn new(m: &mut AllocT, init: T) -> Self;
47 fn new_uninit(m: &mut AllocT) -> Self;
48 fn free(&mut self, m: &mut AllocT);
49}
50pub trait H10Params {
51 fn max_tree_search_depth() -> u32;
52 fn max_tree_comp_length() -> u32;
53}
54
55pub struct H10DefaultParams {}
56impl H10Params for H10DefaultParams {
57 #[inline(always)]
58 fn max_tree_search_depth() -> u32 {
59 64
60 }
61 #[inline(always)]
62 fn max_tree_comp_length() -> u32 {
63 128
64 }
65}
66
67const BUCKET_BITS: usize = 17;
68
69pub struct H10Buckets<AllocU32: Allocator<u32>>(AllocU32::AllocatedMemory);
70
71impl<AllocU32: Allocator<u32>> Allocable<u32, AllocU32> for H10Buckets<AllocU32> {
72 fn new(m: &mut AllocU32, initializer: u32) -> H10Buckets<AllocU32> {
73 let mut ret = m.alloc_cell(1 << BUCKET_BITS);
74 for item in ret.slice_mut().iter_mut() {
75 *item = initializer;
76 }
77 H10Buckets::<AllocU32>(ret)
78 }
79 fn new_uninit(m: &mut AllocU32) -> H10Buckets<AllocU32> {
80 H10Buckets::<AllocU32>(m.alloc_cell(1 << BUCKET_BITS))
81 }
82 fn free(&mut self, m: &mut AllocU32) {
83 m.free_cell(core::mem::take(&mut self.0));
84 }
85}
86
87impl<AllocU32: Allocator<u32>> PartialEq<H10Buckets<AllocU32>> for H10Buckets<AllocU32> {
88 fn eq(&self, other: &H10Buckets<AllocU32>) -> bool {
89 return self.0.slice() == other.0.slice();
90 }
91}
92
93impl<AllocU32: Allocator<u32>> SliceWrapper<u32> for H10Buckets<AllocU32> {
94 #[inline(always)]
95 fn slice(&self) -> &[u32] {
96 self.0.slice()
97 }
98}
99impl<AllocU32: Allocator<u32>> SliceWrapperMut<u32> for H10Buckets<AllocU32> {
100 #[inline(always)]
101 fn slice_mut(&mut self) -> &mut [u32] {
102 self.0.slice_mut()
103 }
104}
105
106pub struct H10<
107 AllocU32: Allocator<u32>,
108 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
109 Params: H10Params,
110> where
111 Buckets: PartialEq<Buckets>,
112{
113 pub window_mask_: usize,
114 pub ringbuffer_break: Option<core::num::NonZeroUsize>,
115 pub common: Struct1,
116 pub buckets_: Buckets,
117 pub invalid_pos_: u32,
118 pub forest: AllocU32::AllocatedMemory,
119 pub _params: core::marker::PhantomData<Params>,
120}
121
122impl<
123 AllocU32: Allocator<u32>,
124 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
125 Params: H10Params,
126 > PartialEq<H10<AllocU32, Buckets, Params>> for H10<AllocU32, Buckets, Params>
127where
128 Buckets: PartialEq<Buckets>,
129{
130 fn eq(&self, other: &H10<AllocU32, Buckets, Params>) -> bool {
131 self.window_mask_ == other.window_mask_
132 && self.common == other.common
133 && self.buckets_ == other.buckets_
134 && self.invalid_pos_ == other.invalid_pos_
135 && self.forest.slice() == other.forest.slice()
136 && self._params == other._params
137 && self.ringbuffer_break == other.ringbuffer_break
138 }
139}
140
141pub fn InitializeH10<AllocU32: Allocator<u32>>(
142 m32: &mut AllocU32,
143 one_shot: bool,
144 params: &BrotliEncoderParams,
145 ringbuffer_break: Option<core::num::NonZeroUsize>,
146 input_size: usize,
147) -> H10<AllocU32, H10Buckets<AllocU32>, H10DefaultParams> {
148 initialize_h10::<AllocU32, H10Buckets<AllocU32>>(
149 m32,
150 one_shot,
151 params,
152 input_size,
153 ringbuffer_break,
154 )
155}
156fn initialize_h10<
157 AllocU32: Allocator<u32>,
158 Buckets: SliceWrapperMut<u32> + SliceWrapper<u32> + Allocable<u32, AllocU32>,
159>(
160 m32: &mut AllocU32,
161 one_shot: bool,
162 params: &BrotliEncoderParams,
163 input_size: usize,
164 ringbuffer_break: Option<core::num::NonZeroUsize>,
165) -> H10<AllocU32, Buckets, H10DefaultParams>
166where
167 Buckets: PartialEq<Buckets>,
168{
169 let mut num_nodes = 1 << params.lgwin;
170 if one_shot && input_size < num_nodes {
171 num_nodes = input_size;
172 }
173 let window_mask = (1 << params.lgwin) - 1;
174 let invalid_pos = 0u32.wrapping_sub(window_mask);
175 let buckets = <Buckets as Allocable<u32, AllocU32>>::new(m32, invalid_pos);
176 H10::<AllocU32, Buckets, H10DefaultParams> {
177 common: Struct1 {
178 params: params.hasher,
179 is_prepared_: 1,
180 dict_num_lookups: 0,
181 dict_num_matches: 0,
182 },
183 _params: core::marker::PhantomData::<H10DefaultParams>,
184 window_mask_: window_mask as usize,
185 invalid_pos_: invalid_pos,
186 buckets_: buckets,
187 forest: m32.alloc_cell(num_nodes * 2),
188 ringbuffer_break,
189 }
190}
191
192impl<
193 AllocU32: Allocator<u32>,
194 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
195 Params: H10Params,
196 > H10<AllocU32, Buckets, Params>
197where
198 Buckets: PartialEq<Buckets>,
199{
200 pub fn free(&mut self, m32: &mut AllocU32) {
201 m32.free_cell(core::mem::take(&mut self.forest));
202 self.buckets_.free(m32);
203 }
204}
205impl<
206 Alloc: Allocator<u16> + Allocator<u32>,
207 Buckets: Allocable<u32, Alloc> + SliceWrapperMut<u32> + SliceWrapper<u32>,
208 Params: H10Params,
209 > CloneWithAlloc<Alloc> for H10<Alloc, Buckets, Params>
210where
211 Buckets: PartialEq<Buckets>,
212{
213 fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
214 let mut ret = H10::<Alloc, Buckets, Params> {
215 window_mask_: self.window_mask_,
216 common: self.common.clone(),
217 buckets_: Buckets::new_uninit(m),
218 invalid_pos_: self.invalid_pos_,
219 forest: allocate::<u32, _>(m, self.forest.len()),
220 _params: core::marker::PhantomData::<Params>,
221 ringbuffer_break: self.ringbuffer_break,
222 };
223 ret.buckets_
224 .slice_mut()
225 .clone_from_slice(self.buckets_.slice());
226 ret.forest.slice_mut().clone_from_slice(self.forest.slice());
227 ret
228 }
229}
230
231impl<
232 AllocU32: Allocator<u32>,
233 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
234 Params: H10Params,
235 > AnyHasher for H10<AllocU32, Buckets, Params>
236where
237 Buckets: PartialEq<Buckets>,
238{
239 #[inline(always)]
243 fn Opts(&self) -> H9Opts {
244 H9Opts {
245 literal_byte_score: 340,
246 }
247 }
248 #[inline(always)]
249 fn PrepareDistanceCache(&self, _distance_cache: &mut [i32]) {}
250 #[inline(always)]
251 fn HashTypeLength(&self) -> usize {
252 4
253 }
254 #[inline(always)]
255 fn StoreLookahead(&self) -> usize {
256 Params::max_tree_comp_length() as usize
257 }
258 fn StitchToPreviousBlock(
259 &mut self,
260 num_bytes: usize,
261 position: usize,
262 ringbuffer: &[u8],
263 ringbuffer_mask: usize,
264 ) {
265 super::hq::StitchToPreviousBlockH10(
266 self,
267 num_bytes,
268 position,
269 ringbuffer,
270 ringbuffer_mask,
271 self.ringbuffer_break,
272 )
273 }
274 #[inline(always)]
275 fn GetHasherCommon(&mut self) -> &mut Struct1 {
276 &mut self.common
277 }
278 #[inline(always)]
279 fn HashBytes(&self, data: &[u8]) -> usize {
280 let h = BROTLI_UNALIGNED_LOAD32(data).wrapping_mul(kHashMul32);
281 (h >> (32i32 - BUCKET_BITS as i32)) as usize
282 }
283 #[inline(always)]
284 fn Store(&mut self, data: &[u8], mask: usize, ix: usize) {
285 let max_backward: usize = self.window_mask_.wrapping_sub(16).wrapping_add(1);
286 StoreAndFindMatchesH10(
287 self,
288 data,
289 ix,
290 mask,
291 self.ringbuffer_break,
292 Params::max_tree_comp_length() as usize,
293 max_backward,
294 &mut 0,
295 &mut [],
296 );
297 }
298 fn StoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
299 let mut i: usize = ix_start;
300 let mut j: usize = ix_start;
301 if ix_start.wrapping_add(63) <= ix_end {
302 i = ix_end.wrapping_sub(63);
303 }
304 if ix_start.wrapping_add(512) <= i {
305 while j < i {
306 {
307 self.Store(data, mask, j);
308 }
309 j = j.wrapping_add(8);
310 }
311 }
312 while i < ix_end {
313 {
314 self.Store(data, mask, i);
315 }
316 i = i.wrapping_add(1);
317 }
318 }
319 fn BulkStoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
320 for i in ix_start..ix_end {
321 self.Store(data, mask, i);
322 }
323 }
324 fn Prepare(&mut self, _one_shot: bool, _input_size: usize, _data: &[u8]) -> HowPrepared {
325 if self.common.is_prepared_ != 0 {
326 return HowPrepared::ALREADY_PREPARED;
327 }
328 let invalid_pos = self.invalid_pos_;
329 for bucket in self.buckets_.slice_mut().iter_mut() {
330 *bucket = invalid_pos;
331 }
332 self.common.is_prepared_ = 1;
333 HowPrepared::NEWLY_PREPARED
334 }
335
336 fn FindLongestMatch(
337 &mut self,
338 _dictionary: Option<&BrotliDictionary>,
339 _dictionary_hash: &[u16],
340 _data: &[u8],
341 _ring_buffer_mask: usize,
342 _ring_buffer_break: Option<core::num::NonZeroUsize>,
343 _distance_cache: &[i32],
344 _cur_ix: usize,
345 _max_length: usize,
346 _max_backward: usize,
347 _gap: usize,
348 _max_distance: usize,
349 _out: &mut HasherSearchResult,
350 ) -> bool {
351 unimplemented!();
352 }
353}
354
355pub struct BackwardMatch(pub u64);
356
357impl BackwardMatch {
360 #[inline(always)]
361 pub fn distance(&self) -> u32 {
362 self.0 as u32
363 }
364 #[inline(always)]
365 pub fn length_and_code(&self) -> u32 {
366 (self.0 >> 32) as u32
367 }
368}
369pub struct BackwardMatchMut<'a>(pub &'a mut u64);
370
371impl<'a> BackwardMatchMut<'a> {
374 #[inline(always)]
375 pub fn distance(&self) -> u32 {
376 *self.0 as u32
377 }
378 #[inline(always)]
379 pub fn length_and_code(&self) -> u32 {
380 (*self.0 >> 32) as u32
381 }
382 #[inline(always)]
383 pub fn set_distance(&mut self, data: u32) {
384 *self.0 &= 0xffffffff00000000;
385 *self.0 |= u64::from(data)
386 }
387 #[inline(always)]
388 pub fn set_length_and_code(&mut self, data: u32) {
389 *self.0 = u64::from((*self.0) as u32) | (u64::from(data) << 32);
390 }
391 #[inline(always)]
392 pub fn init(&mut self, dist: usize, len: usize) {
393 self.set_distance(dist as u32);
394 self.set_length_and_code((len << 5) as u32);
395 }
396 #[inline(always)]
397 pub(crate) fn init_dictionary(&mut self, dist: usize, len: usize, len_code: usize) {
398 self.set_distance(dist as u32);
399 self.set_length_and_code((len << 5 | if len == len_code { 0 } else { len_code }) as u32);
400 }
401}
402
403macro_rules! LeftChildIndexH10 {
404 ($xself: expr, $pos: expr) => {
405 (2usize).wrapping_mul($pos & (*$xself).window_mask_)
406 };
407}
408macro_rules! RightChildIndexH10 {
409 ($xself: expr, $pos: expr) => {
410 (2usize)
411 .wrapping_mul($pos & (*$xself).window_mask_)
412 .wrapping_add(1)
413 };
414}
415pub fn StoreAndFindMatchesH10<
438 AllocU32: Allocator<u32>,
439 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
440 Params: H10Params,
441>(
442 xself: &mut H10<AllocU32, Buckets, Params>,
443 data: &[u8],
444 cur_ix: usize,
445 ring_buffer_mask: usize,
446 ringbuffer_break: Option<core::num::NonZeroUsize>,
447 max_length: usize,
448 max_backward: usize,
449 best_len: &mut usize,
450 matches: &mut [u64],
451) -> usize
452where
453 Buckets: PartialEq<Buckets>,
454{
455 let mut matches_offset = 0_usize;
456 let cur_ix_masked = cur_ix & ring_buffer_mask;
457 let max_comp_len = min(max_length, 128);
458 let should_reroot_tree = max_length >= 128;
459 let key = xself.HashBytes(&data[cur_ix_masked..]);
460 let forest = xself.forest.slice_mut();
461 let mut prev_ix = xself.buckets_.slice()[key] as usize;
462 let mut node_left = LeftChildIndexH10!(xself, cur_ix);
463 let mut node_right = RightChildIndexH10!(xself, cur_ix);
464 let mut best_len_left = 0_usize;
465 let mut best_len_right = 0_usize;
466 let mut depth_remaining = 64_usize;
467
468 if should_reroot_tree {
469 xself.buckets_.slice_mut()[key] = cur_ix as u32;
470 }
471
472 loop {
473 let backward = cur_ix.wrapping_sub(prev_ix);
474 let prev_ix_masked = prev_ix & ring_buffer_mask;
475 if backward == 0 || backward > max_backward || depth_remaining == 0 {
476 if should_reroot_tree {
477 forest[node_left] = xself.invalid_pos_;
478 forest[node_right] = xself.invalid_pos_;
479 }
480 break;
481 }
482
483 let cur_len = min(best_len_left, best_len_right);
484
485 let len = fix_unbroken_len(
486 cur_len.wrapping_add(FindMatchLengthWithLimit(
487 &data[cur_ix_masked.wrapping_add(cur_len)..],
488 &data[prev_ix_masked.wrapping_add(cur_len)..],
489 max_length.wrapping_sub(cur_len),
490 )),
491 prev_ix_masked,
492 cur_ix_masked,
493 ringbuffer_break,
494 );
495
496 if matches_offset != matches.len() && len > *best_len {
497 *best_len = len;
498 BackwardMatchMut(&mut matches[matches_offset]).init(backward, len);
499 matches_offset += 1;
500 }
501
502 if len >= max_comp_len {
503 if should_reroot_tree {
504 forest[node_left] = forest[LeftChildIndexH10!(xself, prev_ix)];
505 forest[node_right] = forest[RightChildIndexH10!(xself, prev_ix)];
506 }
507 break;
508 }
509
510 if data[cur_ix_masked.wrapping_add(len)] > data[prev_ix_masked.wrapping_add(len)] {
511 best_len_left = len;
512 if should_reroot_tree {
513 forest[node_left] = prev_ix as u32;
514 }
515 node_left = RightChildIndexH10!(xself, prev_ix);
516 prev_ix = forest[node_left] as usize;
517 } else {
518 best_len_right = len;
519 if should_reroot_tree {
520 forest[node_right] = prev_ix as u32;
521 }
522 node_right = LeftChildIndexH10!(xself, prev_ix);
523 prev_ix = forest[node_right] as usize;
524 }
525
526 depth_remaining = depth_remaining.wrapping_sub(1);
527 }
528
529 matches_offset
530}