Skip to main content

brotli/enc/backward_references/
hash_to_binary_tree.rs

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    //highest 7 bit is used to reconstruct the length code
27    pub length: u32,
28    // distance associated with the length
29    pub distance: u32,
30    // number of literal inserts before the copy; highest 5 bits contain distance short code + 1 (or zero if no short code)
31    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    /*  fn GetH10Tree(&mut self) -> Option<&mut H10<AllocU32, Buckets, H10Params>> {
240      Some(self)
241    }*/
242    #[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
357//    pub distance : u32,
358//    pub length_and_code : u32,
359impl 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
371//    pub distance : u32,
372//    pub length_and_code : u32,
373impl<'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}
415/*
416fn LeftChildIndexH10<AllocU32: Allocator<u32>,
417     Buckets: Allocable<u32, AllocU32>+SliceWrapperMut<u32>+SliceWrapper<u32>,
418     Params:H10Params>(
419    mut xself : &mut H10<AllocU32, Buckets, Params>, pos : usize
420) -> usize {
421    (2usize).wrapping_mul(pos & xself.window_mask_)
422}
423
424fn RightChildIndexH10<AllocU32: Allocator<u32>,
425     Buckets: Allocable<u32, AllocU32>+SliceWrapperMut<u32>+SliceWrapper<u32>,
426     Params:H10Params>(
427    mut xself : &mut H10<AllocU32, Buckets, Params>, pos : usize
428) -> usize {
429    (2usize).wrapping_mul(
430        pos & xself.window_mask_
431    ).wrapping_add(
432        1
433    )
434}
435*/
436
437pub 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}