Skip to main content

brotli/enc/backward_references/
mod.rs

1mod benchmark;
2pub mod hash_to_binary_tree;
3pub mod hq;
4mod test;
5
6use core::cmp::{max, min};
7
8use super::super::alloc::{Allocator, SliceWrapper, SliceWrapperMut};
9use super::command::{BrotliDistanceParams, Command, ComputeDistanceCode};
10use super::dictionary_hash::kStaticDictionaryHash;
11use super::hash_to_binary_tree::{H10Buckets, H10DefaultParams, ZopfliNode, H10};
12use super::static_dict::{
13    BrotliDictionary, FindMatchLengthWithLimit, FindMatchLengthWithLimitMin4,
14    BROTLI_UNALIGNED_LOAD32, BROTLI_UNALIGNED_LOAD64,
15};
16use super::util::{floatX, Log2FloorNonZero};
17use crate::enc::combined_alloc::allocate;
18
19pub static kInvalidMatch: u32 = 0x0fff_ffff;
20static kCutoffTransformsCount: u32 = 10;
21static kCutoffTransforms: u64 = 0x071b_520a_da2d_3200;
22pub static kHashMul32: u32 = 0x1e35_a7bd;
23pub static kHashMul64: u64 = 0x1e35_a7bd_1e35_a7bd;
24pub static kHashMul64Long: u64 = 0x1fe3_5a7b_d357_9bd3;
25
26#[derive(PartialEq, Eq, Copy, Clone, Debug)]
27#[repr(C)]
28pub enum BrotliEncoderMode {
29    BROTLI_MODE_GENERIC = 0,
30    BROTLI_MODE_TEXT = 1,
31    BROTLI_MODE_FONT = 2,
32    BROTLI_FORCE_LSB_PRIOR = 3,
33    BROTLI_FORCE_MSB_PRIOR = 4,
34    BROTLI_FORCE_UTF8_PRIOR = 5,
35    BROTLI_FORCE_SIGNED_PRIOR = 6,
36}
37
38/// This code takes a length and checks if there's an "end of dictionary" marker at the
39///  "ring_buffer_break"point. This marks where a backwards reference cannot pull data through.
40/// A match must stop at the end of the dictionary and cannot span the end of the dictionary
41/// and beginning of the file.  ring_buffer_break is only set true for custom LZ77 dictionary.
42fn fix_unbroken_len(
43    unbroken_len: usize,
44    prev_ix: usize,
45    _cur_ix_masked: usize,
46    ring_buffer_break: Option<core::num::NonZeroUsize>,
47) -> usize {
48    if let Some(br) = ring_buffer_break {
49        if prev_ix < usize::from(br) && prev_ix + unbroken_len > usize::from(br) {
50            return usize::from(br) - prev_ix;
51        }
52    }
53    return unbroken_len;
54}
55#[derive(Clone, Copy, Debug, PartialEq)]
56pub struct BrotliHasherParams {
57    /// type of hasher to use (default: type 6, but others have tradeoffs of speed/memory)
58    pub type_: i32,
59    /// number of the number of buckets to have in the hash table (defaults to quality - 1)
60    pub bucket_bits: i32,
61    /// number of potential matches to hold per bucket (hash collisions)
62    pub block_bits: i32,
63    /// number of bytes of a potential match to hash
64    pub hash_len: i32,
65    /// number of previous distance matches to check for future matches (defaults to 16)
66    pub num_last_distances_to_check: i32,
67    /// how much to weigh distance vs an extra byte of copy match when comparing possible copy srcs
68    pub literal_byte_score: i32,
69}
70
71#[derive(Clone, Debug)]
72pub struct BrotliEncoderParams {
73    pub dist: BrotliDistanceParams,
74    /// if this brotli file is generic, font or specifically text
75    pub mode: BrotliEncoderMode,
76    /// quality param between 0 and 11 (11 is smallest but takes longest to encode)
77    pub quality: i32,
78    pub q9_5: bool,
79    /// log of how big the ring buffer should be for copying prior data
80    pub lgwin: i32,
81    /// log of how often metablocks should be serialized
82    pub lgblock: i32,
83    /// how big the source file is (or 0 if no hint is provided)
84    pub size_hint: usize,
85    // FIXME: this should be bool
86    /// avoid serializing out priors for literal sections in the favor of decode speed
87    pub disable_literal_context_modeling: i32,
88    pub hasher: BrotliHasherParams,
89    /// produce an IR of the compression file
90    pub log_meta_block: bool,
91    /// attempt to detect how many bytes before the current byte generates the best prediction of it
92    /// * 0 = off (stride 1 always)
93    /// * 1 = on per 16th of a file
94    /// * 2 = on per block type switch
95    pub stride_detection_quality: u8,
96    /// if nonzero, will search for high entropy strings and log them differently to the IR
97    pub high_entropy_detection_quality: u8,
98    /// if nonzero it will search for the temporal locality and effectiveness of the priors
99    /// for literals. The best adaptation and forgetfulness will be logged per metablock to the IR
100    pub cdf_adaptation_detection: u8,
101    /// whether to search for whether the previous byte or the context_map are better predictors on a per-context-map basis
102    pub prior_bitmask_detection: u8,
103    /// for prior bitmask detection: stride_low, stride_speed, cm_low, cm_speed
104    pub literal_adaptation: [(u16, u16); 4],
105    pub large_window: bool,
106    /// avoid search for the best ndirect vs npostfix parameters for distance
107    pub avoid_distance_prefix_search: bool,
108    /// inserts an extra empty metadata block before the final empty metablock in
109    /// catable/appendable mode so concatination tools can just remove the last byte
110    pub byte_align: bool,
111    /// do not emit a empty last block at end of data - if not appendable, this
112    /// will also supress the stream header
113    pub bare_stream: bool,
114    /// construct brotli in such a way that it may be concatenated with another brotli file using appropriate bit ops
115    pub catable: bool,
116    /// can use the dictionary (default yes unless catable is set)
117    pub use_dictionary: bool,
118    /// construct brotli in such a way that another concatable brotli file may be appended
119    pub appendable: bool,
120    /// include a magic number and version number and size_hint at the beginning
121    pub magic_number: bool,
122    /// prefer to compute the map of previously seen strings
123    /// just once for all the threads at the beginning, since they overlap significantly
124    pub favor_cpu_efficiency: bool,
125}
126
127impl Default for BrotliEncoderParams {
128    fn default() -> BrotliEncoderParams {
129        super::encode::BrotliEncoderInitParams()
130    }
131}
132
133#[derive(Clone, Copy, Default, PartialEq)]
134pub struct H9Opts {
135    pub literal_byte_score: u32,
136}
137pub enum HowPrepared {
138    ALREADY_PREPARED,
139    NEWLY_PREPARED,
140}
141#[derive(Clone, PartialEq)]
142pub struct Struct1 {
143    pub params: BrotliHasherParams,
144    /// FIXME: this should be bool
145    pub is_prepared_: i32,
146    pub dict_num_lookups: usize,
147    pub dict_num_matches: usize,
148}
149
150fn LiteralSpreeLengthForSparseSearch(params: &BrotliEncoderParams) -> usize {
151    (if params.quality < 9 { 64i32 } else { 512i32 }) as usize
152}
153
154pub struct HasherSearchResult {
155    pub len: usize,
156    pub len_x_code: usize,
157    pub distance: usize,
158    pub score: u64,
159}
160
161pub trait CloneWithAlloc<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> {
162    fn clone_with_alloc(&self, m: &mut Alloc) -> Self;
163}
164
165pub trait AnyHasher {
166    fn Opts(&self) -> H9Opts;
167    fn GetHasherCommon(&mut self) -> &mut Struct1;
168    fn HashBytes(&self, data: &[u8]) -> usize;
169    fn HashTypeLength(&self) -> usize;
170    fn StoreLookahead(&self) -> usize;
171    fn PrepareDistanceCache(&self, distance_cache: &mut [i32]);
172    fn FindLongestMatch(
173        &mut self,
174        dictionary: Option<&BrotliDictionary>,
175        dictionary_hash: &[u16],
176        data: &[u8],
177        ring_buffer_mask: usize,
178        ring_buffer_break: Option<core::num::NonZeroUsize>,
179        distance_cache: &[i32],
180        cur_ix: usize,
181        max_length: usize,
182        max_backward: usize,
183        gap: usize,
184        max_distance: usize,
185        out: &mut HasherSearchResult,
186    ) -> bool;
187    fn Store(&mut self, data: &[u8], mask: usize, ix: usize);
188    fn Store4Vec4(&mut self, data: &[u8], mask: usize, ix: usize) {
189        for i in 0..4 {
190            self.Store(data, mask, ix + i * 4);
191        }
192    }
193    fn StoreEvenVec4(&mut self, data: &[u8], mask: usize, ix: usize) {
194        for i in 0..4 {
195            self.Store(data, mask, ix + i * 2);
196        }
197    }
198    fn StoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize);
199    fn BulkStoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize);
200    fn Prepare(&mut self, one_shot: bool, input_size: usize, data: &[u8]) -> HowPrepared;
201    fn StitchToPreviousBlock(
202        &mut self,
203        num_bytes: usize,
204        position: usize,
205        ringbuffer: &[u8],
206        ringbuffer_mask: usize,
207    );
208}
209
210pub fn StitchToPreviousBlockInternal<T: AnyHasher>(
211    handle: &mut T,
212    num_bytes: usize,
213    position: usize,
214    ringbuffer: &[u8],
215    ringbuffer_mask: usize,
216) {
217    if num_bytes >= handle.HashTypeLength().wrapping_sub(1) && (position >= 3) {
218        handle.Store(ringbuffer, ringbuffer_mask, position.wrapping_sub(3));
219        handle.Store(ringbuffer, ringbuffer_mask, position.wrapping_sub(2));
220        handle.Store(ringbuffer, ringbuffer_mask, position.wrapping_sub(1));
221    }
222}
223
224pub fn StoreLookaheadThenStore<T: AnyHasher>(hasher: &mut T, size: usize, dict: &[u8]) {
225    let overlap = hasher.StoreLookahead().wrapping_sub(1);
226    if size > overlap {
227        hasher.BulkStoreRange(dict, usize::MAX, 0, size - overlap);
228    }
229}
230
231pub trait BasicHashComputer {
232    fn HashBytes(&self, data: &[u8]) -> u32;
233    fn BUCKET_BITS(&self) -> i32;
234    fn USE_DICTIONARY(&self) -> i32;
235    fn BUCKET_SWEEP(&self) -> i32;
236}
237pub struct BasicHasher<Buckets: SliceWrapperMut<u32> + SliceWrapper<u32> + BasicHashComputer> {
238    pub GetHasherCommon: Struct1,
239    pub buckets_: Buckets,
240    pub h9_opts: H9Opts,
241}
242
243impl<A: SliceWrapperMut<u32> + SliceWrapper<u32> + BasicHashComputer> PartialEq<BasicHasher<A>>
244    for BasicHasher<A>
245{
246    fn eq(&self, other: &BasicHasher<A>) -> bool {
247        self.GetHasherCommon == other.GetHasherCommon
248            && self.h9_opts == other.h9_opts
249            && self.buckets_.slice() == other.buckets_.slice()
250    }
251}
252
253impl<T: SliceWrapperMut<u32> + SliceWrapper<u32> + BasicHashComputer> BasicHasher<T> {
254    fn StoreRangeOptBasic(
255        &mut self,
256        data: &[u8],
257        mask: usize,
258        ix_start: usize,
259        ix_end: usize,
260    ) -> usize {
261        let lookahead = 8;
262        if ix_end >= ix_start + lookahead * 2 {
263            let chunk_count = (ix_end - ix_start) / 4;
264            for chunk_id in 0..chunk_count {
265                let i = (ix_start + chunk_id * 4) & mask;
266                let word11 = data.split_at(i).1.split_at(11).0;
267                let mixed0 = self.HashBytes(word11);
268                let mixed1 = self.HashBytes(word11.split_at(1).1);
269                let mixed2 = self.HashBytes(word11.split_at(2).1);
270                let mixed3 = self.HashBytes(word11.split_at(3).1);
271                let off: u32 = (i >> 3).wrapping_rem(self.buckets_.BUCKET_SWEEP() as usize) as u32;
272                let offset0: usize = mixed0 + off as usize;
273                let offset1: usize = mixed1 + off as usize;
274                let offset2: usize = mixed2 + off as usize;
275                let offset3: usize = mixed3 + off as usize;
276                self.buckets_.slice_mut()[offset0] = i as u32;
277                self.buckets_.slice_mut()[offset1] = i as u32 + 1;
278                self.buckets_.slice_mut()[offset2] = i as u32 + 2;
279                self.buckets_.slice_mut()[offset3] = i as u32 + 3;
280            }
281            return ix_start + chunk_count * 4;
282        }
283        ix_start
284    }
285}
286pub struct H2Sub<AllocU32: alloc::Allocator<u32>> {
287    pub buckets_: AllocU32::AllocatedMemory, // 65537
288}
289impl<T: SliceWrapperMut<u32> + SliceWrapper<u32> + BasicHashComputer> AnyHasher for BasicHasher<T> {
290    #[inline(always)]
291    fn Opts(&self) -> H9Opts {
292        self.h9_opts
293    }
294    #[allow(unused_variables)]
295    fn PrepareDistanceCache(&self, distance_cache: &mut [i32]) {}
296    #[inline(always)]
297    fn HashTypeLength(&self) -> usize {
298        8
299    }
300    #[inline(always)]
301    fn StoreLookahead(&self) -> usize {
302        8
303    }
304    fn StitchToPreviousBlock(
305        &mut self,
306        num_bytes: usize,
307        position: usize,
308        ringbuffer: &[u8],
309        ringbuffer_mask: usize,
310    ) {
311        StitchToPreviousBlockInternal(self, num_bytes, position, ringbuffer, ringbuffer_mask);
312    }
313    #[inline(always)]
314    fn GetHasherCommon(&mut self) -> &mut Struct1 {
315        &mut self.GetHasherCommon
316    }
317    #[inline(always)]
318    fn HashBytes(&self, data: &[u8]) -> usize {
319        self.buckets_.HashBytes(data) as usize
320    }
321    fn Store(&mut self, data: &[u8], mask: usize, ix: usize) {
322        let (_, data_window) = data.split_at((ix & mask));
323        let key: u32 = self.HashBytes(data_window) as u32;
324        let off: u32 = (ix >> 3).wrapping_rem(self.buckets_.BUCKET_SWEEP() as usize) as u32;
325        self.buckets_.slice_mut()[key.wrapping_add(off) as usize] = ix as u32;
326    }
327    fn StoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
328        for i in self.StoreRangeOptBasic(data, mask, ix_start, ix_end)..ix_end {
329            self.Store(data, mask, i);
330        }
331    }
332    fn BulkStoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
333        self.StoreRange(data, mask, ix_start, ix_end);
334    }
335    fn Prepare(&mut self, one_shot: bool, input_size: usize, data: &[u8]) -> HowPrepared {
336        if self.GetHasherCommon.is_prepared_ != 0 {
337            return HowPrepared::ALREADY_PREPARED;
338        }
339        let partial_prepare_threshold = (4 << self.buckets_.BUCKET_BITS()) >> 7;
340        if one_shot && input_size <= partial_prepare_threshold {
341            for i in 0..input_size {
342                let key = self.HashBytes(&data[i..]);
343                let bs = self.buckets_.BUCKET_SWEEP() as usize;
344                for item in self.buckets_.slice_mut()[key..(key + bs)].iter_mut() {
345                    *item = 0;
346                }
347            }
348        } else {
349            for item in self.buckets_.slice_mut().iter_mut() {
350                *item = 0;
351            }
352        }
353        self.GetHasherCommon.is_prepared_ = 1;
354        HowPrepared::NEWLY_PREPARED
355    }
356
357    fn FindLongestMatch(
358        &mut self,
359        dictionary: Option<&BrotliDictionary>,
360        dictionary_hash: &[u16],
361        data: &[u8],
362        ring_buffer_mask: usize,
363        ring_buffer_break: Option<core::num::NonZeroUsize>,
364        distance_cache: &[i32],
365        cur_ix: usize,
366        max_length: usize,
367        max_backward: usize,
368        gap: usize,
369        max_distance: usize,
370        out: &mut HasherSearchResult,
371    ) -> bool {
372        let opts = self.Opts();
373        let best_len_in: usize = out.len;
374        let cur_ix_masked: usize = cur_ix & ring_buffer_mask;
375        let key: u32 = self.HashBytes(&data[cur_ix_masked..]) as u32;
376        let mut compare_char: i32 = data[cur_ix_masked.wrapping_add(best_len_in)] as i32;
377        let mut best_score: u64 = out.score;
378        let mut best_len: usize = best_len_in;
379        let cached_backward: usize = distance_cache[0] as usize;
380        let mut prev_ix: usize = cur_ix.wrapping_sub(cached_backward);
381        let mut is_match_found = false;
382        out.len_x_code = 0usize;
383        if prev_ix < cur_ix {
384            prev_ix &= ring_buffer_mask as u32 as usize;
385            if compare_char == data[prev_ix.wrapping_add(best_len)] as i32 {
386                let unbroken_len: usize = FindMatchLengthWithLimitMin4(
387                    &data[prev_ix..],
388                    &data[cur_ix_masked..],
389                    max_length,
390                );
391                if unbroken_len != 0 {
392                    let len =
393                        fix_unbroken_len(unbroken_len, prev_ix, cur_ix_masked, ring_buffer_break);
394                    best_score = BackwardReferenceScoreUsingLastDistance(len, opts);
395                    best_len = len;
396                    out.len = len;
397                    out.distance = cached_backward;
398                    out.score = best_score;
399                    compare_char = data[cur_ix_masked.wrapping_add(best_len)] as i32;
400                    if self.buckets_.BUCKET_SWEEP() == 1i32 {
401                        self.buckets_.slice_mut()[key as usize] = cur_ix as u32;
402                        return true;
403                    } else {
404                        is_match_found = true;
405                    }
406                }
407            }
408        }
409        let bucket_sweep = self.buckets_.BUCKET_SWEEP();
410        if bucket_sweep == 1i32 {
411            prev_ix = self.buckets_.slice()[key as usize] as usize;
412            self.buckets_.slice_mut()[key as usize] = cur_ix as u32;
413            let backward: usize = cur_ix.wrapping_sub(prev_ix);
414            prev_ix &= ring_buffer_mask as u32 as usize;
415            if compare_char != data[prev_ix.wrapping_add(best_len_in)] as i32 {
416                return false;
417            }
418            if backward == 0usize || backward > max_backward {
419                return false;
420            }
421            let unbroken_len: usize =
422                FindMatchLengthWithLimitMin4(&data[prev_ix..], &data[cur_ix_masked..], max_length);
423            if unbroken_len != 0 {
424                let len = fix_unbroken_len(unbroken_len, prev_ix, cur_ix_masked, ring_buffer_break);
425                out.len = len;
426                out.distance = backward;
427                out.score = BackwardReferenceScore(len, backward, opts);
428                return true;
429            }
430        } else {
431            for prev_ix_ref in
432                self.buckets_.slice().split_at(key as usize).1[..bucket_sweep as usize].iter()
433            {
434                let mut prev_ix = *prev_ix_ref as usize;
435                let backward: usize = cur_ix.wrapping_sub(prev_ix);
436                prev_ix &= ring_buffer_mask as u32 as usize;
437                if compare_char != data[prev_ix.wrapping_add(best_len)] as i32 {
438                    continue;
439                }
440                if backward == 0usize || backward > max_backward {
441                    continue;
442                }
443                let unbroken_len = FindMatchLengthWithLimitMin4(
444                    &data[prev_ix..],
445                    &data[cur_ix_masked..],
446                    max_length,
447                );
448
449                if unbroken_len != 0 {
450                    let len =
451                        fix_unbroken_len(unbroken_len, prev_ix, cur_ix_masked, ring_buffer_break);
452                    let score: u64 = BackwardReferenceScore(len, backward, opts);
453                    if best_score < score {
454                        best_score = score;
455                        best_len = len;
456                        out.len = best_len;
457                        out.distance = backward;
458                        out.score = score;
459                        compare_char = data[cur_ix_masked.wrapping_add(best_len)] as i32;
460                        is_match_found = true;
461                    }
462                }
463            }
464        }
465        if dictionary.is_some() && self.buckets_.USE_DICTIONARY() != 0 && !is_match_found {
466            is_match_found = SearchInStaticDictionary(
467                dictionary.unwrap(),
468                dictionary_hash,
469                self,
470                &data[cur_ix_masked..],
471                max_length,
472                max_backward.wrapping_add(gap),
473                max_distance,
474                out,
475                true,
476            );
477        }
478        self.buckets_.slice_mut()
479            [(key as usize).wrapping_add((cur_ix >> 3).wrapping_rem(bucket_sweep as usize))] =
480            cur_ix as u32;
481        is_match_found
482    }
483}
484impl<AllocU32: alloc::Allocator<u32>> BasicHashComputer for H2Sub<AllocU32> {
485    fn HashBytes(&self, data: &[u8]) -> u32 {
486        let h: u64 =
487            (BROTLI_UNALIGNED_LOAD64(data) << (64i32 - 8i32 * 5i32)).wrapping_mul(kHashMul64);
488        (h >> (64i32 - 16i32)) as u32
489    }
490    fn BUCKET_BITS(&self) -> i32 {
491        16
492    }
493    fn BUCKET_SWEEP(&self) -> i32 {
494        1
495    }
496    fn USE_DICTIONARY(&self) -> i32 {
497        1
498    }
499}
500impl<AllocU32: alloc::Allocator<u32>> SliceWrapperMut<u32> for H2Sub<AllocU32> {
501    fn slice_mut(&mut self) -> &mut [u32] {
502        return self.buckets_.slice_mut();
503    }
504}
505impl<AllocU32: alloc::Allocator<u32>> SliceWrapper<u32> for H2Sub<AllocU32> {
506    fn slice(&self) -> &[u32] {
507        return self.buckets_.slice();
508    }
509}
510pub struct H3Sub<AllocU32: alloc::Allocator<u32>> {
511    pub buckets_: AllocU32::AllocatedMemory, // 65538
512}
513impl<AllocU32: alloc::Allocator<u32>> SliceWrapperMut<u32> for H3Sub<AllocU32> {
514    fn slice_mut(&mut self) -> &mut [u32] {
515        return self.buckets_.slice_mut();
516    }
517}
518impl<AllocU32: alloc::Allocator<u32>> SliceWrapper<u32> for H3Sub<AllocU32> {
519    fn slice(&self) -> &[u32] {
520        return self.buckets_.slice();
521    }
522}
523impl<AllocU32: alloc::Allocator<u32>> BasicHashComputer for H3Sub<AllocU32> {
524    fn BUCKET_BITS(&self) -> i32 {
525        16
526    }
527    fn BUCKET_SWEEP(&self) -> i32 {
528        2
529    }
530    fn USE_DICTIONARY(&self) -> i32 {
531        0
532    }
533    fn HashBytes(&self, data: &[u8]) -> u32 {
534        let h: u64 =
535            (BROTLI_UNALIGNED_LOAD64(data) << (64i32 - 8i32 * 5i32)).wrapping_mul(kHashMul64);
536        (h >> (64i32 - 16i32)) as u32
537    }
538}
539pub struct H4Sub<AllocU32: alloc::Allocator<u32>> {
540    pub buckets_: AllocU32::AllocatedMemory, // 131076
541}
542impl<AllocU32: alloc::Allocator<u32>> BasicHashComputer for H4Sub<AllocU32> {
543    fn BUCKET_BITS(&self) -> i32 {
544        17
545    }
546    fn BUCKET_SWEEP(&self) -> i32 {
547        4
548    }
549    fn USE_DICTIONARY(&self) -> i32 {
550        1
551    }
552    fn HashBytes(&self, data: &[u8]) -> u32 {
553        let h: u64 =
554            (BROTLI_UNALIGNED_LOAD64(data) << (64i32 - 8i32 * 5i32)).wrapping_mul(kHashMul64);
555        (h >> (64i32 - 17i32)) as u32
556    }
557}
558impl<AllocU32: alloc::Allocator<u32>> SliceWrapperMut<u32> for H4Sub<AllocU32> {
559    fn slice_mut(&mut self) -> &mut [u32] {
560        return self.buckets_.slice_mut();
561    }
562}
563impl<AllocU32: alloc::Allocator<u32>> SliceWrapper<u32> for H4Sub<AllocU32> {
564    fn slice(&self) -> &[u32] {
565        return self.buckets_.slice();
566    }
567}
568pub struct H54Sub<AllocU32: alloc::Allocator<u32>> {
569    pub buckets_: AllocU32::AllocatedMemory,
570}
571impl<AllocU32: alloc::Allocator<u32>> BasicHashComputer for H54Sub<AllocU32> {
572    fn BUCKET_BITS(&self) -> i32 {
573        20
574    }
575    fn BUCKET_SWEEP(&self) -> i32 {
576        4
577    }
578    fn USE_DICTIONARY(&self) -> i32 {
579        0
580    }
581    fn HashBytes(&self, data: &[u8]) -> u32 {
582        let h: u64 =
583            (BROTLI_UNALIGNED_LOAD64(data) << (64i32 - 8i32 * 7i32)).wrapping_mul(kHashMul64);
584        (h >> (64i32 - 20i32)) as u32
585    }
586}
587
588impl<AllocU32: alloc::Allocator<u32>> SliceWrapperMut<u32> for H54Sub<AllocU32> {
589    fn slice_mut(&mut self) -> &mut [u32] {
590        return self.buckets_.slice_mut();
591    }
592}
593impl<AllocU32: alloc::Allocator<u32>> SliceWrapper<u32> for H54Sub<AllocU32> {
594    fn slice(&self) -> &[u32] {
595        return self.buckets_.slice();
596    }
597}
598pub const H9_BUCKET_BITS: usize = 15;
599pub const H9_BLOCK_BITS: usize = 8;
600pub const H9_NUM_LAST_DISTANCES_TO_CHECK: usize = 16;
601pub const H9_BLOCK_SIZE: usize = 1 << H9_BLOCK_BITS;
602const H9_BLOCK_MASK: usize = (1 << H9_BLOCK_BITS) - 1;
603
604impl H9Opts {
605    pub fn new(params: &BrotliHasherParams) -> H9Opts {
606        H9Opts {
607            literal_byte_score: if params.literal_byte_score != 0 {
608                params.literal_byte_score as u32
609            } else {
610                540
611            },
612        }
613    }
614}
615
616pub struct H9<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> {
617    pub num_: <Alloc as Allocator<u16>>::AllocatedMemory, //[u16;1 << H9_BUCKET_BITS],
618    pub buckets_: <Alloc as Allocator<u32>>::AllocatedMemory, //[u32; H9_BLOCK_SIZE << H9_BUCKET_BITS],
619    pub dict_search_stats_: Struct1,
620    pub h9_opts: H9Opts,
621}
622
623impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> PartialEq<H9<Alloc>> for H9<Alloc> {
624    fn eq(&self, other: &H9<Alloc>) -> bool {
625        self.dict_search_stats_ == other.dict_search_stats_
626            && self.num_.slice() == other.num_.slice()
627            && self.buckets_.slice() == other.buckets_.slice()
628            && self.h9_opts == other.h9_opts
629    }
630}
631
632fn adv_prepare_distance_cache(distance_cache: &mut [i32], num_distances: i32) {
633    if num_distances > 4i32 {
634        let last_distance: i32 = distance_cache[0];
635        distance_cache[4] = last_distance - 1i32;
636        distance_cache[5] = last_distance + 1i32;
637        distance_cache[6] = last_distance - 2i32;
638        distance_cache[7] = last_distance + 2i32;
639        distance_cache[8] = last_distance - 3i32;
640        distance_cache[9] = last_distance + 3i32;
641        if num_distances > 10i32 {
642            let next_last_distance: i32 = distance_cache[1];
643            distance_cache[10] = next_last_distance - 1i32;
644            distance_cache[11] = next_last_distance + 1i32;
645            distance_cache[12] = next_last_distance - 2i32;
646            distance_cache[13] = next_last_distance + 2i32;
647            distance_cache[14] = next_last_distance - 3i32;
648            distance_cache[15] = next_last_distance + 3i32;
649        }
650    }
651}
652
653pub const kDistanceCacheIndex: [u8; 16] = [0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1];
654
655pub const kDistanceCacheOffset: [i8; 16] = [0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3];
656
657//const BROTLI_LITERAL_BYTE_SCORE: u64 = 540;
658const BROTLI_DISTANCE_BIT_PENALTY: u32 = 120;
659
660// Score must be positive after applying maximal penalty.
661const BROTLI_SCORE_BASE: u32 = (BROTLI_DISTANCE_BIT_PENALTY * 8 * 8/* sizeof usize*/);
662const kDistanceShortCodeCost: [u32; 16] = [
663    /* Repeat last */
664    BROTLI_SCORE_BASE + 60,
665    /* 2nd, 3rd, 4th last */
666    BROTLI_SCORE_BASE - 95,
667    BROTLI_SCORE_BASE - 117,
668    BROTLI_SCORE_BASE - 127,
669    /* Last with offset */
670    BROTLI_SCORE_BASE - 93,
671    BROTLI_SCORE_BASE - 93,
672    BROTLI_SCORE_BASE - 96,
673    BROTLI_SCORE_BASE - 96,
674    BROTLI_SCORE_BASE - 99,
675    BROTLI_SCORE_BASE - 99,
676    /* 2nd last with offset */
677    BROTLI_SCORE_BASE - 105,
678    BROTLI_SCORE_BASE - 105,
679    BROTLI_SCORE_BASE - 115,
680    BROTLI_SCORE_BASE - 115,
681    BROTLI_SCORE_BASE - 125,
682    BROTLI_SCORE_BASE - 125,
683];
684
685fn BackwardReferenceScoreH9(
686    copy_length: usize,
687    backward_reference_offset: usize,
688    h9_opts: H9Opts,
689) -> u64 {
690    (u64::from(BROTLI_SCORE_BASE)
691        .wrapping_add((h9_opts.literal_byte_score as u64).wrapping_mul(copy_length as u64))
692        .wrapping_sub(
693            (BROTLI_DISTANCE_BIT_PENALTY as u64)
694                .wrapping_mul(Log2FloorNonZero(backward_reference_offset as u64) as u64),
695        ))
696        >> 2
697}
698
699fn BackwardReferenceScoreUsingLastDistanceH9(
700    copy_length: usize,
701    distance_short_code: usize,
702    h9_opts: H9Opts,
703) -> u64 {
704    ((h9_opts.literal_byte_score as u64)
705        .wrapping_mul(copy_length as u64)
706        .wrapping_add(u64::from(kDistanceShortCodeCost[distance_short_code])))
707        >> 2
708}
709
710impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> AnyHasher for H9<Alloc> {
711    #[inline(always)]
712    fn Opts(&self) -> H9Opts {
713        self.h9_opts
714    }
715    #[inline(always)]
716    fn GetHasherCommon(&mut self) -> &mut Struct1 {
717        &mut self.dict_search_stats_
718    }
719    #[inline(always)]
720    fn HashBytes(&self, data: &[u8]) -> usize {
721        let h: u32 = BROTLI_UNALIGNED_LOAD32(data).wrapping_mul(kHashMul32);
722        let thirty_two: usize = 32;
723        (h >> (thirty_two.wrapping_sub(H9_BUCKET_BITS))) as usize
724    }
725    #[inline(always)]
726    fn HashTypeLength(&self) -> usize {
727        4
728    }
729    #[inline(always)]
730    fn StoreLookahead(&self) -> usize {
731        4
732    }
733    fn PrepareDistanceCache(&self, distance_cache: &mut [i32]) {
734        let num_distances = H9_NUM_LAST_DISTANCES_TO_CHECK as i32;
735        adv_prepare_distance_cache(distance_cache, num_distances);
736    }
737    fn FindLongestMatch(
738        &mut self,
739        dictionary: Option<&BrotliDictionary>,
740        dictionary_hash: &[u16],
741        data: &[u8],
742        ring_buffer_mask: usize,
743        ring_buffer_break: Option<core::num::NonZeroUsize>,
744        distance_cache: &[i32],
745        cur_ix: usize,
746        max_length: usize,
747        max_backward: usize,
748        gap: usize,
749        max_distance: usize,
750        out: &mut HasherSearchResult,
751    ) -> bool {
752        let best_len_in: usize = out.len;
753        let cur_ix_masked: usize = cur_ix & ring_buffer_mask;
754        let mut best_score: u64 = out.score;
755        let mut best_len: usize = best_len_in;
756        let mut is_match_found = false;
757        out.len_x_code = 0usize;
758        for i in 0..H9_NUM_LAST_DISTANCES_TO_CHECK {
759            let idx = kDistanceCacheIndex[i] as usize;
760            let backward =
761                (distance_cache[idx] as usize).wrapping_add(kDistanceCacheOffset[i] as usize);
762            let mut prev_ix = cur_ix.wrapping_sub(backward);
763            if prev_ix >= cur_ix {
764                continue;
765            }
766            if backward > max_backward {
767                continue;
768            }
769            prev_ix &= ring_buffer_mask;
770            if cur_ix_masked.wrapping_add(best_len) > ring_buffer_mask
771                || prev_ix.wrapping_add(best_len) > ring_buffer_mask
772                || data[cur_ix_masked.wrapping_add(best_len)]
773                    != data[prev_ix.wrapping_add(best_len)]
774            {
775                continue;
776            }
777            {
778                let unbroken_len: usize =
779                    FindMatchLengthWithLimit(&data[prev_ix..], &data[cur_ix_masked..], max_length);
780                if unbroken_len >= 3 || (unbroken_len == 2 && i < 2) {
781                    let len =
782                        fix_unbroken_len(unbroken_len, prev_ix, cur_ix_masked, ring_buffer_break);
783                    let score = BackwardReferenceScoreUsingLastDistanceH9(len, i, self.h9_opts);
784                    if best_score < score {
785                        best_score = score;
786                        best_len = len;
787                        out.len = best_len;
788                        out.distance = backward;
789                        out.score = best_score;
790                        is_match_found = true;
791                    }
792                }
793            }
794        }
795        if max_length >= 4 && cur_ix_masked.wrapping_add(best_len) <= ring_buffer_mask {
796            let key = self.HashBytes(data.split_at(cur_ix_masked).1);
797            let bucket = &mut self
798                .buckets_
799                .slice_mut()
800                .split_at_mut(key << H9_BLOCK_BITS)
801                .1
802                .split_at_mut(H9_BLOCK_SIZE)
803                .0;
804            assert!(bucket.len() > H9_BLOCK_MASK);
805            assert_eq!(bucket.len(), H9_BLOCK_MASK + 1);
806            let self_num_key = &mut self.num_.slice_mut()[key];
807            let down = if *self_num_key > H9_BLOCK_SIZE as u16 {
808                (*self_num_key as usize) - H9_BLOCK_SIZE
809            } else {
810                0usize
811            };
812            let mut i: usize = *self_num_key as usize;
813            let mut prev_best_val = data[cur_ix_masked.wrapping_add(best_len)];
814            while i > down {
815                i -= 1;
816                let mut prev_ix = bucket[i & H9_BLOCK_MASK] as usize;
817                let backward = cur_ix.wrapping_sub(prev_ix);
818                if (backward > max_backward) {
819                    break;
820                }
821                prev_ix &= ring_buffer_mask;
822                if (prev_ix.wrapping_add(best_len) > ring_buffer_mask
823                    || prev_best_val != data[prev_ix.wrapping_add(best_len)])
824                {
825                    continue;
826                }
827                {
828                    let unbroken_len = FindMatchLengthWithLimit(
829                        data.split_at(prev_ix).1,
830                        data.split_at(cur_ix_masked).1,
831                        max_length,
832                    );
833                    if (unbroken_len >= 4) {
834                        let len = fix_unbroken_len(
835                            unbroken_len,
836                            prev_ix,
837                            cur_ix_masked,
838                            ring_buffer_break,
839                        );
840                        /* Comparing for >= 3 does not change the semantics, but just saves
841                        for a few unnecessary binary logarithms in backward reference
842                        score, since we are not interested in such short matches. */
843                        let score = BackwardReferenceScoreH9(len, backward, self.h9_opts);
844                        if (best_score < score) {
845                            best_score = score;
846                            best_len = len;
847                            out.len = best_len;
848                            out.distance = backward;
849                            out.score = best_score;
850                            is_match_found = true;
851                            if cur_ix_masked.wrapping_add(best_len) > ring_buffer_mask {
852                                break;
853                            }
854                            prev_best_val = data[cur_ix_masked.wrapping_add(best_len)];
855                        }
856                    }
857                }
858            }
859            bucket[*self_num_key as usize & H9_BLOCK_MASK] = cur_ix as u32;
860            *self_num_key = self_num_key.wrapping_add(1);
861        }
862        if !is_match_found && dictionary.is_some() {
863            let (_, cur_data) = data.split_at(cur_ix_masked);
864            is_match_found = SearchInStaticDictionary(
865                dictionary.unwrap(),
866                dictionary_hash,
867                self,
868                cur_data,
869                max_length,
870                max_backward.wrapping_add(gap),
871                max_distance,
872                out,
873                false,
874            );
875        }
876        is_match_found
877    }
878
879    fn Store(&mut self, data: &[u8], mask: usize, ix: usize) {
880        let (_, data_window) = data.split_at((ix & mask));
881        let key: u32 = self.HashBytes(data_window) as u32;
882        let self_num_key = &mut self.num_.slice_mut()[key as usize];
883        let minor_ix: usize = (*self_num_key as usize & H9_BLOCK_MASK);
884        self.buckets_.slice_mut()[minor_ix.wrapping_add((key as usize) << H9_BLOCK_BITS)] =
885            ix as u32;
886        *self_num_key = self_num_key.wrapping_add(1);
887    }
888    fn StoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
889        for i in ix_start..ix_end {
890            self.Store(data, mask, i);
891        }
892    }
893    fn BulkStoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
894        for i in ix_start..ix_end {
895            self.Store(data, mask, i);
896        }
897    }
898    fn Prepare(&mut self, _one_shot: bool, _input_size: usize, _data: &[u8]) -> HowPrepared {
899        if self.GetHasherCommon().is_prepared_ != 0 {
900            return HowPrepared::ALREADY_PREPARED;
901        }
902        for item in self.num_.slice_mut().iter_mut() {
903            *item = 0;
904        }
905        self.GetHasherCommon().is_prepared_ = 1;
906        HowPrepared::NEWLY_PREPARED
907    }
908    fn StitchToPreviousBlock(
909        &mut self,
910        num_bytes: usize,
911        position: usize,
912        ringbuffer: &[u8],
913        ringbuffer_mask: usize,
914    ) {
915        StitchToPreviousBlockInternal(self, num_bytes, position, ringbuffer, ringbuffer_mask)
916    }
917}
918
919pub trait AdvHashSpecialization: PartialEq<Self> {
920    fn get_hash_mask(&self) -> u64;
921    fn set_hash_mask(&mut self, params_hash_len: i32);
922    fn get_k_hash_mul(&self) -> u64;
923    fn HashTypeLength(&self) -> usize;
924    fn StoreLookahead(&self) -> usize;
925    fn load_and_mix_word(&self, data: &[u8]) -> u64;
926    fn hash_shift(&self) -> i32;
927    fn bucket_size(&self) -> u32;
928    fn block_mask(&self) -> u32;
929    fn block_size(&self) -> u32;
930    fn block_bits(&self) -> i32;
931}
932pub struct AdvHasher<
933    Specialization: AdvHashSpecialization + Sized + Clone,
934    Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>,
935> {
936    pub GetHasherCommon: Struct1,
937    pub specialization: Specialization, // contains hash_mask_
938    pub num: <Alloc as Allocator<u16>>::AllocatedMemory,
939    pub buckets: <Alloc as Allocator<u32>>::AllocatedMemory,
940    pub h9_opts: H9Opts,
941}
942
943impl<
944        Specialization: AdvHashSpecialization + Sized + Clone,
945        Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>,
946    > PartialEq<AdvHasher<Specialization, Alloc>> for AdvHasher<Specialization, Alloc>
947{
948    fn eq(&self, other: &Self) -> bool {
949        self.GetHasherCommon == other.GetHasherCommon
950            && self.specialization == other.specialization
951            && self.num.slice() == other.num.slice()
952            && self.buckets.slice() == other.buckets.slice()
953            && self.h9_opts == other.h9_opts
954    }
955}
956
957#[derive(Clone, PartialEq)]
958pub struct HQ5Sub {}
959impl AdvHashSpecialization for HQ5Sub {
960    #[inline(always)]
961    fn hash_shift(&self) -> i32 {
962        32i32 - 14 // 32 - bucket_bits
963    }
964    #[inline(always)]
965    fn bucket_size(&self) -> u32 {
966        1 << 14
967    }
968    #[inline(always)]
969    fn block_bits(&self) -> i32 {
970        4
971    }
972    #[inline(always)]
973    fn block_size(&self) -> u32 {
974        1 << 4
975    }
976    #[inline(always)]
977    fn block_mask(&self) -> u32 {
978        (1 << 4) - 1
979    }
980    #[inline(always)]
981    fn get_hash_mask(&self) -> u64 {
982        //return 0xffff_ffff_ffff_ffff;
983        0xffff_ffff // make it 32 bit
984    }
985    #[inline(always)]
986    fn get_k_hash_mul(&self) -> u64 {
987        kHashMul32 as u64
988    }
989    #[inline(always)]
990    fn load_and_mix_word(&self, data: &[u8]) -> u64 {
991        (BROTLI_UNALIGNED_LOAD32(data) as u64 * self.get_k_hash_mul()) & self.get_hash_mask()
992    }
993    #[inline(always)]
994    fn set_hash_mask(&mut self, _params_hash_len: i32) {}
995    fn HashTypeLength(&self) -> usize {
996        4
997    }
998    #[inline(always)]
999    fn StoreLookahead(&self) -> usize {
1000        4
1001    }
1002}
1003
1004#[derive(Clone, PartialEq)]
1005pub struct HQ7Sub {}
1006impl AdvHashSpecialization for HQ7Sub {
1007    #[inline(always)]
1008    fn hash_shift(&self) -> i32 {
1009        32i32 - 15 // 32 - bucket_bits
1010    }
1011    #[inline(always)]
1012    fn bucket_size(&self) -> u32 {
1013        1 << 15
1014    }
1015    #[inline(always)]
1016    fn block_bits(&self) -> i32 {
1017        6
1018    }
1019    #[inline(always)]
1020    fn block_size(&self) -> u32 {
1021        1 << 6
1022    }
1023    #[inline(always)]
1024    fn block_mask(&self) -> u32 {
1025        (1 << 6) - 1
1026    }
1027    #[inline(always)]
1028    fn get_hash_mask(&self) -> u64 {
1029        //return 0xffff_ffff_ffff_ffff;
1030        0xffff_ffff // make it 32 bit
1031    }
1032    #[inline(always)]
1033    fn get_k_hash_mul(&self) -> u64 {
1034        kHashMul32 as u64
1035    }
1036    #[inline(always)]
1037    fn load_and_mix_word(&self, data: &[u8]) -> u64 {
1038        (BROTLI_UNALIGNED_LOAD32(data) as u64 * self.get_k_hash_mul()) & self.get_hash_mask()
1039    }
1040    #[inline(always)]
1041    fn set_hash_mask(&mut self, _params_hash_len: i32) {}
1042    fn HashTypeLength(&self) -> usize {
1043        4
1044    }
1045    #[inline(always)]
1046    fn StoreLookahead(&self) -> usize {
1047        4
1048    }
1049}
1050
1051#[derive(Clone, PartialEq)]
1052pub struct H5Sub {
1053    pub hash_shift_: i32,
1054    pub bucket_size_: u32,
1055    pub block_mask_: u32,
1056    pub block_bits_: i32,
1057}
1058
1059impl AdvHashSpecialization for H5Sub {
1060    #[inline(always)]
1061    fn hash_shift(&self) -> i32 {
1062        self.hash_shift_
1063    }
1064    fn bucket_size(&self) -> u32 {
1065        self.bucket_size_
1066    }
1067    fn block_bits(&self) -> i32 {
1068        self.block_bits_
1069    }
1070    fn block_size(&self) -> u32 {
1071        1 << self.block_bits_
1072    }
1073    fn block_mask(&self) -> u32 {
1074        self.block_mask_
1075    }
1076    fn get_hash_mask(&self) -> u64 {
1077        //return 0xffff_ffff_ffff_ffff;
1078        0xffff_ffff // make it 32 bit
1079    }
1080    fn get_k_hash_mul(&self) -> u64 {
1081        kHashMul32 as u64
1082    }
1083    fn load_and_mix_word(&self, data: &[u8]) -> u64 {
1084        (BROTLI_UNALIGNED_LOAD32(data) as u64 * self.get_k_hash_mul()) & self.get_hash_mask()
1085    }
1086    #[allow(unused_variables)]
1087    fn set_hash_mask(&mut self, params_hash_len: i32) {}
1088    fn HashTypeLength(&self) -> usize {
1089        4
1090    }
1091    fn StoreLookahead(&self) -> usize {
1092        4
1093    }
1094}
1095
1096#[derive(Clone, PartialEq)]
1097pub struct H6Sub {
1098    pub hash_mask: u64,
1099    pub hash_shift_: i32,
1100    pub bucket_size_: u32,
1101    pub block_mask_: u32,
1102    pub block_bits_: i32,
1103}
1104
1105impl AdvHashSpecialization for H6Sub {
1106    #[inline(always)]
1107    fn hash_shift(&self) -> i32 {
1108        self.hash_shift_
1109    }
1110    #[inline(always)]
1111    fn bucket_size(&self) -> u32 {
1112        self.bucket_size_
1113    }
1114    fn block_bits(&self) -> i32 {
1115        self.block_bits_
1116    }
1117    fn block_size(&self) -> u32 {
1118        1 << self.block_bits_
1119    }
1120    #[inline(always)]
1121    fn block_mask(&self) -> u32 {
1122        self.block_mask_
1123    }
1124    #[inline(always)]
1125    fn get_hash_mask(&self) -> u64 {
1126        self.hash_mask
1127    }
1128    #[inline(always)]
1129    fn set_hash_mask(&mut self, params_hash_len: i32) {
1130        // FIXME: this assumes params_hash_len is fairly small, or else it may result in a negative shift value
1131        self.hash_mask = u64::MAX >> (64i32 - 8i32 * params_hash_len);
1132    }
1133    #[inline(always)]
1134    fn get_k_hash_mul(&self) -> u64 {
1135        kHashMul64Long
1136    }
1137    #[inline(always)]
1138    fn load_and_mix_word(&self, data: &[u8]) -> u64 {
1139        (BROTLI_UNALIGNED_LOAD64(data) & self.get_hash_mask()).wrapping_mul(self.get_k_hash_mul())
1140    }
1141    #[inline(always)]
1142    fn HashTypeLength(&self) -> usize {
1143        8
1144    }
1145    #[inline(always)]
1146    fn StoreLookahead(&self) -> usize {
1147        8
1148    }
1149}
1150
1151fn BackwardReferencePenaltyUsingLastDistance(distance_short_code: usize) -> u64 {
1152    // FIXME?: double bitwise AND with the same value?
1153    (39u64).wrapping_add((0x0001_ca10_u64 >> (distance_short_code & 0x0e) & 0x0e))
1154}
1155
1156impl<
1157        Specialization: AdvHashSpecialization + Clone,
1158        Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>,
1159    > AdvHasher<Specialization, Alloc>
1160{
1161    // 7 opt
1162    // returns a new ix_start
1163    fn StoreRangeOptBatch(
1164        &mut self,
1165        data: &[u8],
1166        mask: usize,
1167        ix_start: usize,
1168        ix_end: usize,
1169    ) -> usize {
1170        let lookahead = self.specialization.StoreLookahead();
1171        if ix_end >= ix_start + lookahead * 2 && lookahead == 4 {
1172            let num = self.num.slice_mut();
1173            let buckets = self.buckets.slice_mut();
1174            assert_eq!(num.len(), self.specialization.bucket_size() as usize);
1175            assert_eq!(
1176                buckets.len(),
1177                self.specialization.bucket_size() as usize
1178                    * self.specialization.block_size() as usize
1179            );
1180            let shift = self.specialization.hash_shift();
1181            let chunk_count = (ix_end - ix_start) / 4;
1182            for chunk_id in 0..chunk_count {
1183                let i = (ix_start + chunk_id * 4) & mask;
1184                let ffffffff = 0xffff_ffff;
1185                let word = u64::from(data[i])
1186                    | (u64::from(data[i + 1]) << 8)
1187                    | (u64::from(data[i + 2]) << 16)
1188                    | (u64::from(data[i + 3]) << 24)
1189                    | (u64::from(data[i + 4]) << 32)
1190                    | (u64::from(data[i + 5]) << 40)
1191                    | (u64::from(data[i + 6]) << 48);
1192                let mixed0 = ((((word & ffffffff) * self.specialization.get_k_hash_mul())
1193                    & self.specialization.get_hash_mask())
1194                    >> shift) as usize;
1195                let mixed1 = (((((word >> 8) & ffffffff) * self.specialization.get_k_hash_mul())
1196                    & self.specialization.get_hash_mask())
1197                    >> shift) as usize;
1198                let mixed2 = (((((word >> 16) & ffffffff) * self.specialization.get_k_hash_mul())
1199                    & self.specialization.get_hash_mask())
1200                    >> shift) as usize;
1201                let mixed3 = (((((word >> 24) & ffffffff) * self.specialization.get_k_hash_mul())
1202                    & self.specialization.get_hash_mask())
1203                    >> shift) as usize;
1204                let mut num_ref0 = u32::from(num[mixed0]);
1205                num[mixed0] = num_ref0.wrapping_add(1) as u16;
1206                num_ref0 &= self.specialization.block_mask();
1207                let mut num_ref1 = u32::from(num[mixed1]);
1208                num[mixed1] = num_ref1.wrapping_add(1) as u16;
1209                num_ref1 &= self.specialization.block_mask();
1210                let mut num_ref2 = u32::from(num[mixed2]);
1211                num[mixed2] = num_ref2.wrapping_add(1) as u16;
1212                num_ref2 &= self.specialization.block_mask();
1213                let mut num_ref3 = u32::from(num[mixed3]);
1214                num[mixed3] = num_ref3.wrapping_add(1) as u16;
1215                num_ref3 &= self.specialization.block_mask();
1216                let offset0: usize =
1217                    (mixed0 << self.specialization.block_bits()) + num_ref0 as usize;
1218                let offset1: usize =
1219                    (mixed1 << self.specialization.block_bits()) + num_ref1 as usize;
1220                let offset2: usize =
1221                    (mixed2 << self.specialization.block_bits()) + num_ref2 as usize;
1222                let offset3: usize =
1223                    (mixed3 << self.specialization.block_bits()) + num_ref3 as usize;
1224                buckets[offset0] = (i) as u32;
1225                buckets[offset1] = (i + 1) as u32;
1226                buckets[offset2] = (i + 2) as u32;
1227                buckets[offset3] = (i + 3) as u32;
1228            }
1229            return ix_start + chunk_count * 4;
1230        }
1231        ix_start
1232    }
1233
1234    fn BulkStoreRangeOptMemFetch(
1235        &mut self,
1236        data: &[u8],
1237        mask: usize,
1238        ix_start: usize,
1239        ix_end: usize,
1240    ) -> usize {
1241        const REG_SIZE: usize = 32usize;
1242        let lookahead = self.specialization.StoreLookahead();
1243        if mask == usize::MAX && ix_end > ix_start + REG_SIZE && lookahead == 4 {
1244            const lookahead4: usize = 4;
1245            assert_eq!(lookahead4, lookahead);
1246            let mut data64 = [0u8; REG_SIZE + lookahead4 - 1];
1247            let del = (ix_end - ix_start) / REG_SIZE;
1248            let num = self.num.slice_mut();
1249            let buckets = self.buckets.slice_mut();
1250            assert_eq!(num.len(), self.specialization.bucket_size() as usize);
1251            assert_eq!(
1252                buckets.len(),
1253                self.specialization.bucket_size() as usize
1254                    * self.specialization.block_size() as usize
1255            );
1256            let shift = self.specialization.hash_shift();
1257            for chunk_id in 0..del {
1258                let ix_offset = ix_start + chunk_id * REG_SIZE;
1259                data64[..REG_SIZE + lookahead4 - 1].clone_from_slice(
1260                    data.split_at(ix_offset)
1261                        .1
1262                        .split_at(REG_SIZE + lookahead4 - 1)
1263                        .0,
1264                );
1265                for quad_index in 0..(REG_SIZE >> 2) {
1266                    let i = quad_index << 2;
1267                    let ffffffff = 0xffff_ffff;
1268                    let word = u64::from(data64[i])
1269                        | (u64::from(data64[i + 1]) << 8)
1270                        | (u64::from(data64[i + 2]) << 16)
1271                        | (u64::from(data64[i + 3]) << 24)
1272                        | (u64::from(data64[i + 4]) << 32)
1273                        | (u64::from(data64[i + 5]) << 40)
1274                        | (u64::from(data64[i + 6]) << 48);
1275                    let mixed0 = ((((word & ffffffff) * self.specialization.get_k_hash_mul())
1276                        & self.specialization.get_hash_mask())
1277                        >> shift) as usize;
1278                    let mixed1 = (((((word >> 8) & ffffffff)
1279                        * self.specialization.get_k_hash_mul())
1280                        & self.specialization.get_hash_mask())
1281                        >> shift) as usize;
1282                    let mixed2 = (((((word >> 16) & ffffffff)
1283                        * self.specialization.get_k_hash_mul())
1284                        & self.specialization.get_hash_mask())
1285                        >> shift) as usize;
1286                    let mixed3 = (((((word >> 24) & ffffffff)
1287                        * self.specialization.get_k_hash_mul())
1288                        & self.specialization.get_hash_mask())
1289                        >> shift) as usize;
1290                    let mut num_ref0 = u32::from(num[mixed0]);
1291                    num[mixed0] = num_ref0.wrapping_add(1) as u16;
1292                    num_ref0 &= self.specialization.block_mask();
1293                    let mut num_ref1 = u32::from(num[mixed1]);
1294                    num[mixed1] = num_ref1.wrapping_add(1) as u16;
1295                    num_ref1 &= self.specialization.block_mask();
1296                    let mut num_ref2 = u32::from(num[mixed2]);
1297                    num[mixed2] = num_ref2.wrapping_add(1) as u16;
1298                    num_ref2 &= self.specialization.block_mask();
1299                    let mut num_ref3 = u32::from(num[mixed3]);
1300                    num[mixed3] = num_ref3.wrapping_add(1) as u16;
1301                    num_ref3 &= self.specialization.block_mask();
1302                    let offset0: usize =
1303                        (mixed0 << self.specialization.block_bits()) + num_ref0 as usize;
1304                    let offset1: usize =
1305                        (mixed1 << self.specialization.block_bits()) + num_ref1 as usize;
1306                    let offset2: usize =
1307                        (mixed2 << self.specialization.block_bits()) + num_ref2 as usize;
1308                    let offset3: usize =
1309                        (mixed3 << self.specialization.block_bits()) + num_ref3 as usize;
1310                    buckets[offset0] = (ix_offset + i) as u32;
1311                    buckets[offset1] = (ix_offset + i + 1) as u32;
1312                    buckets[offset2] = (ix_offset + i + 2) as u32;
1313                    buckets[offset3] = (ix_offset + i + 3) as u32;
1314                }
1315            }
1316            return ix_start + del * REG_SIZE;
1317        }
1318        ix_start
1319    }
1320
1321    #[cfg(feature = "benchmark")]
1322    fn BulkStoreRangeOptMemFetchLazyDupeUpdate(
1323        &mut self,
1324        data: &[u8],
1325        mask: usize,
1326        ix_start: usize,
1327        ix_end: usize,
1328    ) -> usize {
1329        const REG_SIZE: usize = 32usize;
1330        let lookahead = self.specialization.StoreLookahead();
1331        if mask == usize::MAX && ix_end > ix_start + REG_SIZE && lookahead == 4 {
1332            const lookahead4: usize = 4;
1333            assert_eq!(lookahead4, lookahead);
1334            let mut data64 = [0u8; REG_SIZE + lookahead4];
1335            let del = (ix_end - ix_start) / REG_SIZE;
1336            let num = self.num.slice_mut();
1337            let buckets = self.buckets.slice_mut();
1338            assert_eq!(num.len(), self.specialization.bucket_size() as usize);
1339            assert_eq!(
1340                buckets.len(),
1341                self.specialization.bucket_size() as usize
1342                    * self.specialization.block_size() as usize
1343            );
1344            let shift = self.specialization.hash_shift();
1345            for chunk_id in 0..del {
1346                let ix_offset = ix_start + chunk_id * REG_SIZE;
1347                data64[..REG_SIZE + lookahead4]
1348                    .clone_from_slice(data.split_at(ix_offset).1.split_at(REG_SIZE + lookahead4).0);
1349                for quad_index in 0..(REG_SIZE >> 2) {
1350                    let i = quad_index << 2;
1351                    let ffffffff = 0xffff_ffff;
1352                    let word = u64::from(data64[i])
1353                        | (u64::from(data64[i + 1]) << 8)
1354                        | (u64::from(data64[i + 2]) << 16)
1355                        | (u64::from(data64[i + 3]) << 24)
1356                        | (u64::from(data64[i + 4]) << 32)
1357                        | (u64::from(data64[i + 5]) << 40)
1358                        | (u64::from(data64[i + 6]) << 48);
1359                    let mixed0 = ((((word & ffffffff) * self.specialization.get_k_hash_mul())
1360                        & self.specialization.get_hash_mask())
1361                        >> shift) as usize;
1362                    let mixed1 = (((((word >> 8) & ffffffff)
1363                        * self.specialization.get_k_hash_mul())
1364                        & self.specialization.get_hash_mask())
1365                        >> shift) as usize;
1366                    let mixed2 = (((((word >> 16) & ffffffff)
1367                        * self.specialization.get_k_hash_mul())
1368                        & self.specialization.get_hash_mask())
1369                        >> shift) as usize;
1370                    let mixed3 = (((((word >> 24) & ffffffff)
1371                        * self.specialization.get_k_hash_mul())
1372                        & self.specialization.get_hash_mask())
1373                        >> shift) as usize;
1374                    let mut num_ref0 = u32::from(num[mixed0]);
1375                    let mut num_ref1 = u32::from(num[mixed1]);
1376                    let mut num_ref2 = u32::from(num[mixed2]);
1377                    let mut num_ref3 = u32::from(num[mixed3]);
1378                    num[mixed0] = num_ref0.wrapping_add(1) as u16;
1379                    num[mixed1] = num_ref1.wrapping_add(1) as u16;
1380                    num[mixed2] = num_ref2.wrapping_add(1) as u16;
1381                    num[mixed3] = num_ref3.wrapping_add(1) as u16;
1382                    num_ref0 &= self.specialization.block_mask();
1383                    num_ref1 &= self.specialization.block_mask();
1384                    num_ref2 &= self.specialization.block_mask();
1385                    num_ref3 &= self.specialization.block_mask();
1386                    let offset0: usize =
1387                        (mixed0 << self.specialization.block_bits()) + num_ref0 as usize;
1388                    let offset1: usize =
1389                        (mixed1 << self.specialization.block_bits()) + num_ref1 as usize;
1390                    let offset2: usize =
1391                        (mixed2 << self.specialization.block_bits()) + num_ref2 as usize;
1392                    let offset3: usize =
1393                        (mixed3 << self.specialization.block_bits()) + num_ref3 as usize;
1394                    buckets[offset0] = (ix_offset + i) as u32;
1395                    buckets[offset1] = (ix_offset + i + 1) as u32;
1396                    buckets[offset2] = (ix_offset + i + 2) as u32;
1397                    buckets[offset3] = (ix_offset + i + 3) as u32;
1398                }
1399            }
1400            return ix_start + del * REG_SIZE;
1401        }
1402        ix_start
1403    }
1404
1405    #[cfg(feature = "benchmark")]
1406    fn BulkStoreRangeOptRandomDupeUpdate(
1407        &mut self,
1408        data: &[u8],
1409        mask: usize,
1410        ix_start: usize,
1411        ix_end: usize,
1412    ) -> usize {
1413        const REG_SIZE: usize = 32usize;
1414        let lookahead = self.specialization.StoreLookahead();
1415        if mask == usize::MAX && ix_end > ix_start + REG_SIZE && lookahead == 4 {
1416            const lookahead4: usize = 4;
1417            assert_eq!(lookahead4, lookahead);
1418            let mut data64 = [0u8; REG_SIZE + lookahead4];
1419            let del = (ix_end - ix_start) / REG_SIZE;
1420            let num = self.num.slice_mut();
1421            let buckets = self.buckets.slice_mut();
1422            assert_eq!(num.len(), self.specialization.bucket_size() as usize);
1423            assert_eq!(
1424                buckets.len(),
1425                self.specialization.bucket_size() as usize
1426                    * self.specialization.block_size() as usize
1427            );
1428            let shift = self.specialization.hash_shift();
1429            for chunk_id in 0..del {
1430                let ix_offset = ix_start + chunk_id * REG_SIZE;
1431                data64[..REG_SIZE + lookahead4]
1432                    .clone_from_slice(data.split_at(ix_offset).1.split_at(REG_SIZE + lookahead4).0);
1433                for i in 0..REG_SIZE {
1434                    let mixed_word = ((u32::from(data64[i])
1435                        | (u32::from(data64[i + 1]) << 8)
1436                        | (u32::from(data64[i + 2]) << 16)
1437                        | (u32::from(data64[i + 3]) << 24))
1438                        as u64
1439                        * self.specialization.get_k_hash_mul())
1440                        & self.specialization.get_hash_mask();
1441                    let key = mixed_word >> shift;
1442                    let minor_ix: usize = chunk_id & self.specialization.block_mask() as usize; //   *num_ref as usize & self.specialization.block_mask() as usize; //GIGANTIC HAX: overwrite firsst option
1443                    let offset: usize =
1444                        minor_ix + (key << self.specialization.block_bits()) as usize;
1445                    buckets[offset] = (ix_offset + i) as u32;
1446                }
1447            }
1448            for (bucket_index, num_ref) in num.iter_mut().enumerate() {
1449                let region = buckets
1450                    .split_at_mut(bucket_index << self.specialization.block_bits())
1451                    .1
1452                    .split_at_mut(self.specialization.block_size() as usize)
1453                    .0;
1454                let mut lnum = 0usize;
1455                for block_index in 0..self.specialization.block_size() as usize {
1456                    if region[block_index] != 0 {
1457                        let byte_addr = region[block_index];
1458                        region[lnum] = byte_addr;
1459                        lnum += 1;
1460                    }
1461                }
1462                *num_ref = lnum as u16;
1463            }
1464            return ix_start + del * REG_SIZE;
1465        }
1466        ix_start
1467    }
1468}
1469
1470impl<
1471        Specialization: AdvHashSpecialization + Clone,
1472        Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>,
1473    > AnyHasher for AdvHasher<Specialization, Alloc>
1474{
1475    fn Opts(&self) -> H9Opts {
1476        self.h9_opts
1477    }
1478    fn PrepareDistanceCache(&self, distance_cache: &mut [i32]) {
1479        let num_distances = self.GetHasherCommon.params.num_last_distances_to_check;
1480        adv_prepare_distance_cache(distance_cache, num_distances);
1481    }
1482    fn StitchToPreviousBlock(
1483        &mut self,
1484        num_bytes: usize,
1485        position: usize,
1486        ringbuffer: &[u8],
1487        ringbuffer_mask: usize,
1488    ) {
1489        StitchToPreviousBlockInternal(self, num_bytes, position, ringbuffer, ringbuffer_mask);
1490    }
1491    fn Prepare(&mut self, one_shot: bool, input_size: usize, data: &[u8]) -> HowPrepared {
1492        if self.GetHasherCommon.is_prepared_ != 0 {
1493            return HowPrepared::ALREADY_PREPARED;
1494        }
1495        let partial_prepare_threshold = self.specialization.bucket_size() as usize >> 6;
1496        if one_shot && input_size <= partial_prepare_threshold {
1497            for i in 0..input_size {
1498                let key = self.HashBytes(&data[i..]);
1499                self.num.slice_mut()[key] = 0;
1500            }
1501        } else {
1502            for item in
1503                self.num.slice_mut()[..(self.specialization.bucket_size() as usize)].iter_mut()
1504            {
1505                *item = 0;
1506            }
1507        }
1508        self.GetHasherCommon.is_prepared_ = 1;
1509        HowPrepared::NEWLY_PREPARED
1510    }
1511
1512    fn GetHasherCommon(&mut self) -> &mut Struct1 {
1513        &mut self.GetHasherCommon
1514    }
1515    fn HashTypeLength(&self) -> usize {
1516        self.specialization.HashTypeLength()
1517    }
1518    fn StoreLookahead(&self) -> usize {
1519        self.specialization.StoreLookahead()
1520    }
1521    fn HashBytes(&self, data: &[u8]) -> usize {
1522        let shift = self.specialization.hash_shift();
1523        let h: u64 = self.specialization.load_and_mix_word(data);
1524        (h >> shift) as u32 as usize
1525    }
1526    fn StoreEvenVec4(&mut self, data: &[u8], mask: usize, ix: usize) {
1527        if self.specialization.StoreLookahead() != 4 {
1528            for i in 0..4 {
1529                self.Store(data, mask, ix + i * 2);
1530            }
1531            return;
1532        }
1533        let shift = self.specialization.hash_shift();
1534        let num = self.num.slice_mut();
1535        let buckets = self.buckets.slice_mut();
1536        let li = ix & mask;
1537        let lword = u64::from(data[li])
1538            | (u64::from(data[li + 1]) << 8)
1539            | (u64::from(data[li + 2]) << 16)
1540            | (u64::from(data[li + 3]) << 24)
1541            | (u64::from(data[li + 4]) << 32)
1542            | (u64::from(data[li + 5]) << 40)
1543            | (u64::from(data[li + 6]) << 48)
1544            | (u64::from(data[li + 7]) << 56);
1545        let hi = (ix + 8) & mask;
1546        let hword = u64::from(data[hi]) | (u64::from(data[hi + 1]) << 8);
1547        let mixed0 = ((((lword & 0xffff_ffff) * self.specialization.get_k_hash_mul())
1548            & self.specialization.get_hash_mask())
1549            >> shift) as usize;
1550        let mixed1 = (((((lword >> 16) & 0xffff_ffff) * self.specialization.get_k_hash_mul())
1551            & self.specialization.get_hash_mask())
1552            >> shift) as usize;
1553        let mixed2 = (((((lword >> 32) & 0xffff_ffff) * self.specialization.get_k_hash_mul())
1554            & self.specialization.get_hash_mask())
1555            >> shift) as usize;
1556        let mixed3 = ((((((hword & 0xffff) << 16) | ((lword >> 48) & 0xffff))
1557            * self.specialization.get_k_hash_mul())
1558            & self.specialization.get_hash_mask())
1559            >> shift) as usize;
1560        let mut num_ref0 = u32::from(num[mixed0]);
1561        num[mixed0] = num_ref0.wrapping_add(1) as u16;
1562        num_ref0 &= self.specialization.block_mask();
1563        let mut num_ref1 = u32::from(num[mixed1]);
1564        num[mixed1] = num_ref1.wrapping_add(1) as u16;
1565        num_ref1 &= self.specialization.block_mask();
1566        let mut num_ref2 = u32::from(num[mixed2]);
1567        num[mixed2] = num_ref2.wrapping_add(1) as u16;
1568        num_ref2 &= self.specialization.block_mask();
1569        let mut num_ref3 = u32::from(num[mixed3]);
1570        num[mixed3] = num_ref3.wrapping_add(1) as u16;
1571        num_ref3 &= self.specialization.block_mask();
1572        let offset0: usize = (mixed0 << self.specialization.block_bits()) + num_ref0 as usize;
1573        let offset1: usize = (mixed1 << self.specialization.block_bits()) + num_ref1 as usize;
1574        let offset2: usize = (mixed2 << self.specialization.block_bits()) + num_ref2 as usize;
1575        let offset3: usize = (mixed3 << self.specialization.block_bits()) + num_ref3 as usize;
1576        buckets[offset0] = ix as u32;
1577        buckets[offset1] = (ix + 2) as u32;
1578        buckets[offset2] = (ix + 4) as u32;
1579        buckets[offset3] = (ix + 6) as u32;
1580    }
1581    fn Store4Vec4(&mut self, data: &[u8], mask: usize, ix: usize) {
1582        if self.specialization.StoreLookahead() != 4 {
1583            for i in 0..4 {
1584                self.Store(data, mask, ix + i * 4);
1585            }
1586            return;
1587        }
1588        let shift = self.specialization.hash_shift();
1589        let num = self.num.slice_mut();
1590        let buckets = self.buckets.slice_mut();
1591        let li = ix & mask;
1592        let llword = u32::from(data[li])
1593            | (u32::from(data[li + 1]) << 8)
1594            | (u32::from(data[li + 2]) << 16)
1595            | (u32::from(data[li + 3]) << 24);
1596        let luword = u32::from(data[li + 4])
1597            | (u32::from(data[li + 5]) << 8)
1598            | (u32::from(data[li + 6]) << 16)
1599            | (u32::from(data[li + 7]) << 24);
1600        let ui = (ix + 8) & mask;
1601        let ulword = u32::from(data[ui])
1602            | (u32::from(data[ui + 1]) << 8)
1603            | (u32::from(data[ui + 2]) << 16)
1604            | (u32::from(data[ui + 3]) << 24);
1605
1606        let uuword = u32::from(data[ui + 4])
1607            | (u32::from(data[ui + 5]) << 8)
1608            | (u32::from(data[ui + 6]) << 16)
1609            | (u32::from(data[ui + 7]) << 24);
1610
1611        let mixed0 = (((u64::from(llword) * self.specialization.get_k_hash_mul())
1612            & self.specialization.get_hash_mask())
1613            >> shift) as usize;
1614        let mixed1 = (((u64::from(luword) * self.specialization.get_k_hash_mul())
1615            & self.specialization.get_hash_mask())
1616            >> shift) as usize;
1617        let mixed2 = (((u64::from(ulword) * self.specialization.get_k_hash_mul())
1618            & self.specialization.get_hash_mask())
1619            >> shift) as usize;
1620        let mixed3 = (((u64::from(uuword) * self.specialization.get_k_hash_mul())
1621            & self.specialization.get_hash_mask())
1622            >> shift) as usize;
1623        let mut num_ref0 = u32::from(num[mixed0]);
1624        num[mixed0] = num_ref0.wrapping_add(1) as u16;
1625        num_ref0 &= self.specialization.block_mask();
1626        let mut num_ref1 = u32::from(num[mixed1]);
1627        num[mixed1] = num_ref1.wrapping_add(1) as u16;
1628        num_ref1 &= self.specialization.block_mask();
1629        let mut num_ref2 = u32::from(num[mixed2]);
1630        num[mixed2] = num_ref2.wrapping_add(1) as u16;
1631        num_ref2 &= self.specialization.block_mask();
1632        let mut num_ref3 = u32::from(num[mixed3]);
1633        num[mixed3] = num_ref3.wrapping_add(1) as u16;
1634        num_ref3 &= self.specialization.block_mask();
1635        let offset0: usize = (mixed0 << self.specialization.block_bits()) + num_ref0 as usize;
1636        let offset1: usize = (mixed1 << self.specialization.block_bits()) + num_ref1 as usize;
1637        let offset2: usize = (mixed2 << self.specialization.block_bits()) + num_ref2 as usize;
1638        let offset3: usize = (mixed3 << self.specialization.block_bits()) + num_ref3 as usize;
1639        buckets[offset0] = ix as u32;
1640        buckets[offset1] = (ix + 4) as u32;
1641        buckets[offset2] = (ix + 8) as u32;
1642        buckets[offset3] = (ix + 12) as u32;
1643    }
1644    fn Store(&mut self, data: &[u8], mask: usize, ix: usize) {
1645        let (_, data_window) = data.split_at((ix & mask));
1646        let key: u32 = self.HashBytes(data_window) as u32;
1647        let minor_ix: usize =
1648            (self.num.slice()[(key as usize)] as u32 & self.specialization.block_mask()) as usize;
1649        let offset: usize =
1650            minor_ix.wrapping_add((key << self.specialization.block_bits()) as usize);
1651        self.buckets.slice_mut()[offset] = ix as u32;
1652        {
1653            let _lhs = &mut self.num.slice_mut()[(key as usize)];
1654            *_lhs = (*_lhs as i32 + 1) as u16;
1655        }
1656    }
1657    fn StoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
1658        for i in self.StoreRangeOptBatch(data, mask, ix_start, ix_end)..ix_end {
1659            self.Store(data, mask, i);
1660        }
1661    }
1662    fn BulkStoreRange(&mut self, data: &[u8], mask: usize, mut ix_start: usize, ix_end: usize) {
1663        /*
1664        if ix_start + 4096 < ix_end {
1665          for vec_offset in 0..(ix_end - ix_start - 4096) / 16 {
1666            self.Store4Vec4(data, mask, ix_start + vec_offset * 16);
1667          }
1668          ix_start += 16 * ((ix_end - ix_start - 4096) / 16);
1669        }
1670        if ix_start + 512 < ix_end {
1671          for vec_offset in 0..(ix_end - ix_start - 512) / 8 {
1672            self.StoreEvenVec4(data, mask, ix_start + vec_offset * 8);
1673            //self.StoreRange(data, mask, ix_start + vec_offset * 8, ix_start + (1+ vec_offset) * 8);
1674          }
1675          ix_start += 8 * ((ix_end - ix_start - 512) / 8);
1676        }
1677         */
1678        ix_start = self.BulkStoreRangeOptMemFetch(data, mask, ix_start, ix_end);
1679        for i in ix_start..ix_end {
1680            self.Store(data, mask, i);
1681        }
1682    }
1683
1684    fn FindLongestMatch(
1685        &mut self,
1686        dictionary: Option<&BrotliDictionary>,
1687        dictionary_hash: &[u16],
1688        data: &[u8],
1689        ring_buffer_mask: usize,
1690        ring_buffer_break: Option<core::num::NonZeroUsize>,
1691        distance_cache: &[i32],
1692        cur_ix: usize,
1693        max_length: usize,
1694        max_backward: usize,
1695        gap: usize,
1696        max_distance: usize,
1697        out: &mut HasherSearchResult,
1698    ) -> bool {
1699        let opts = self.Opts();
1700        let cur_ix_masked: usize = cur_ix & ring_buffer_mask;
1701        let mut is_match_found = false;
1702        let mut best_score: u64 = out.score;
1703        let mut best_len: usize = out.len;
1704        out.len = 0usize;
1705        out.len_x_code = 0usize;
1706        let cur_data = data.split_at(cur_ix_masked).1;
1707        for i in 0..self.GetHasherCommon.params.num_last_distances_to_check as usize {
1708            let backward: usize = distance_cache[i] as usize;
1709            let mut prev_ix: usize = cur_ix.wrapping_sub(backward);
1710            if prev_ix >= cur_ix || backward > max_backward {
1711                continue;
1712            }
1713            prev_ix &= ring_buffer_mask;
1714            if (cur_ix_masked.wrapping_add(best_len) > ring_buffer_mask
1715                || prev_ix.wrapping_add(best_len) > ring_buffer_mask
1716                || cur_data[best_len] != data[prev_ix.wrapping_add(best_len)])
1717            {
1718                continue;
1719            }
1720            let prev_data = data.split_at(prev_ix).1;
1721
1722            let unbroken_len = FindMatchLengthWithLimit(prev_data, cur_data, max_length);
1723            if unbroken_len >= 3 || (unbroken_len == 2 && i < 2) {
1724                let len = fix_unbroken_len(unbroken_len, prev_ix, cur_ix_masked, ring_buffer_break);
1725                let mut score: u64 = BackwardReferenceScoreUsingLastDistance(len, opts);
1726                if best_score < score {
1727                    if i != 0 {
1728                        score = score.wrapping_sub(BackwardReferencePenaltyUsingLastDistance(i));
1729                    }
1730                    if best_score < score {
1731                        best_score = score;
1732                        best_len = len;
1733                        out.len = best_len;
1734                        out.distance = backward;
1735                        out.score = best_score;
1736                        is_match_found = true;
1737                    }
1738                }
1739            }
1740        }
1741
1742        let key: u32 = self.HashBytes(cur_data) as u32;
1743        let common_block_bits = self.specialization.block_bits();
1744        let num_ref_mut = &mut self.num.slice_mut()[key as usize];
1745        let num_copy = *num_ref_mut;
1746        let bucket: &mut [u32] = self
1747            .buckets
1748            .slice_mut()
1749            .split_at_mut((key << common_block_bits) as usize)
1750            .1
1751            .split_at_mut(self.specialization.block_size() as usize)
1752            .0;
1753        assert!(bucket.len() > self.specialization.block_mask() as usize);
1754        if num_copy != 0 {
1755            let down: usize = max(
1756                i32::from(num_copy) - self.specialization.block_size() as i32,
1757                0,
1758            ) as usize;
1759            let mut i = num_copy as usize;
1760            while i > down {
1761                i -= 1;
1762                let mut prev_ix = bucket[i & self.specialization.block_mask() as usize] as usize;
1763                let backward = cur_ix.wrapping_sub(prev_ix);
1764                prev_ix &= ring_buffer_mask;
1765                if (cur_ix_masked.wrapping_add(best_len) > ring_buffer_mask
1766                    || prev_ix.wrapping_add(best_len) > ring_buffer_mask
1767                    || cur_data[best_len] != data[prev_ix.wrapping_add(best_len)])
1768                {
1769                    if backward > max_backward {
1770                        break;
1771                    }
1772                    continue;
1773                }
1774                if backward > max_backward {
1775                    break;
1776                }
1777                let prev_data = data.split_at(prev_ix).1;
1778                let unbroken_len = FindMatchLengthWithLimitMin4(prev_data, cur_data, max_length);
1779                if unbroken_len != 0 {
1780                    let len =
1781                        fix_unbroken_len(unbroken_len, prev_ix, cur_ix_masked, ring_buffer_break);
1782                    let score: u64 = BackwardReferenceScore(len, backward, opts);
1783                    if best_score < score {
1784                        best_score = score;
1785                        best_len = len;
1786                        out.len = best_len;
1787                        out.distance = backward;
1788                        out.score = best_score;
1789                        is_match_found = true;
1790                    }
1791                }
1792            }
1793        }
1794        bucket[(num_copy as u32 & self.specialization.block_mask()) as usize] = cur_ix as u32;
1795        *num_ref_mut = num_ref_mut.wrapping_add(1);
1796
1797        if !is_match_found && dictionary.is_some() {
1798            let (_, cur_data) = data.split_at(cur_ix_masked);
1799            is_match_found = SearchInStaticDictionary(
1800                dictionary.unwrap(),
1801                dictionary_hash,
1802                self,
1803                cur_data,
1804                max_length,
1805                max_backward.wrapping_add(gap),
1806                max_distance,
1807                out,
1808                false,
1809            );
1810        }
1811        is_match_found
1812    }
1813}
1814
1815pub struct BankH40 {
1816    pub slots: [SlotH40; 65536],
1817}
1818
1819pub struct BankH41 {
1820    pub slots: [SlotH41; 65536],
1821}
1822
1823pub struct BankH42 {
1824    pub slots: [SlotH42; 512],
1825}
1826
1827pub struct SlotH40 {
1828    pub delta: u16,
1829    pub next: u16,
1830}
1831pub struct SlotH41 {
1832    pub delta: u16,
1833    pub next: u16,
1834}
1835
1836pub struct SlotH42 {
1837    pub delta: u16,
1838    pub next: u16,
1839}
1840
1841// UNSUPPORTED, for now.
1842pub struct H40 {
1843    pub common: Struct1,
1844    pub addr: [u32; 32768],
1845    pub head: [u16; 32768],
1846    pub tiny_hash: [u8; 65536],
1847    pub banks: [BankH40; 1],
1848    pub free_slot_idx: [u16; 1],
1849    pub max_hops: usize,
1850}
1851
1852pub struct H41 {
1853    pub common: Struct1,
1854    pub addr: [u32; 32768],
1855    pub head: [u16; 32768],
1856    pub tiny_hash: [u8; 65536],
1857    pub banks: [BankH41; 1],
1858    pub free_slot_idx: [u16; 1],
1859    pub max_hops: usize,
1860}
1861
1862pub struct H42 {
1863    pub common: Struct1,
1864    pub addr: [u32; 32768],
1865    pub head: [u16; 32768],
1866    pub tiny_hash: [u8; 65536],
1867    pub banks: [BankH42; 512],
1868    pub max_hops: usize,
1869}
1870
1871fn BackwardReferenceScoreUsingLastDistance(copy_length: usize, h9_opts: H9Opts) -> u64 {
1872    ((h9_opts.literal_byte_score as u64) >> 2)
1873        .wrapping_mul(copy_length as u64)
1874        .wrapping_add((30u64 * 8u64).wrapping_mul(::core::mem::size_of::<u64>() as u64))
1875        .wrapping_add(15)
1876}
1877
1878fn BackwardReferenceScore(
1879    copy_length: usize,
1880    backward_reference_offset: usize,
1881    h9_opts: H9Opts,
1882) -> u64 {
1883    (30u64 * 8u64)
1884        .wrapping_mul(::core::mem::size_of::<u64>() as u64)
1885        .wrapping_add(((h9_opts.literal_byte_score as usize) >> 2).wrapping_mul(copy_length) as u64)
1886        .wrapping_sub(
1887            (30u64).wrapping_mul(Log2FloorNonZero(backward_reference_offset as u64) as u64),
1888        )
1889}
1890
1891fn Hash14(data: &[u8]) -> u32 {
1892    let h: u32 = BROTLI_UNALIGNED_LOAD32(data).wrapping_mul(kHashMul32);
1893    h >> (32i32 - 14i32)
1894}
1895
1896fn TestStaticDictionaryItem(
1897    dictionary: &BrotliDictionary,
1898    item: usize,
1899    data: &[u8],
1900    max_length: usize,
1901    max_backward: usize,
1902    max_distance: usize,
1903    h9_opts: H9Opts,
1904    out: &mut HasherSearchResult,
1905) -> i32 {
1906    let backward: usize;
1907
1908    let len: usize = item & 0x1fusize;
1909    let dist: usize = item >> 5;
1910    let offset: usize =
1911        (dictionary.offsets_by_length[len] as usize).wrapping_add(len.wrapping_mul(dist));
1912    if len > max_length {
1913        return 0i32;
1914    }
1915    let matchlen: usize = FindMatchLengthWithLimit(data, &dictionary.data[offset..], len);
1916    if matchlen.wrapping_add(kCutoffTransformsCount as usize) <= len || matchlen == 0usize {
1917        return 0i32;
1918    }
1919    {
1920        let cut: u64 = len.wrapping_sub(matchlen) as u64;
1921        let transform_id: usize =
1922            (cut << 2).wrapping_add(kCutoffTransforms >> cut.wrapping_mul(6) & 0x3f) as usize;
1923        backward = max_backward
1924            .wrapping_add(dist)
1925            .wrapping_add(1)
1926            .wrapping_add(transform_id << dictionary.size_bits_by_length[len] as i32);
1927    }
1928    if backward > max_distance {
1929        return 0i32;
1930    }
1931    let score: u64 = BackwardReferenceScore(matchlen, backward, h9_opts);
1932    if score < out.score {
1933        return 0i32;
1934    }
1935    out.len = matchlen;
1936    out.len_x_code = len ^ matchlen;
1937    out.distance = backward;
1938    out.score = score;
1939    1i32
1940}
1941
1942fn SearchInStaticDictionary<HasherType: AnyHasher>(
1943    dictionary: &BrotliDictionary,
1944    dictionary_hash: &[u16],
1945    handle: &mut HasherType,
1946    data: &[u8],
1947    max_length: usize,
1948    max_backward: usize,
1949    max_distance: usize,
1950    out: &mut HasherSearchResult,
1951    shallow: bool,
1952) -> bool {
1953    let mut key: usize;
1954    let mut i: usize;
1955    let mut is_match_found = false;
1956    let opts = handle.Opts();
1957    let xself: &mut Struct1 = handle.GetHasherCommon();
1958    if xself.dict_num_matches < xself.dict_num_lookups >> 7 {
1959        return false;
1960    }
1961    key = (Hash14(data) << 1) as usize; //FIXME: works for any kind of hasher??
1962    i = 0usize;
1963    while i < if shallow { 1 } else { 2 } {
1964        {
1965            let item: usize = dictionary_hash[key] as usize;
1966            xself.dict_num_lookups = xself.dict_num_lookups.wrapping_add(1);
1967            if item != 0usize {
1968                let item_matches: i32 = TestStaticDictionaryItem(
1969                    dictionary,
1970                    item,
1971                    data,
1972                    max_length,
1973                    max_backward,
1974                    max_distance,
1975                    opts,
1976                    out,
1977                );
1978                if item_matches != 0 {
1979                    xself.dict_num_matches = xself.dict_num_matches.wrapping_add(1);
1980                    is_match_found = true;
1981                }
1982            }
1983        }
1984        i = i.wrapping_add(1);
1985        key = key.wrapping_add(1);
1986    }
1987    is_match_found
1988}
1989
1990impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> CloneWithAlloc<Alloc>
1991    for BasicHasher<H2Sub<Alloc>>
1992{
1993    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
1994        let mut ret = BasicHasher::<H2Sub<Alloc>> {
1995            GetHasherCommon: self.GetHasherCommon.clone(),
1996            buckets_: H2Sub {
1997                buckets_: allocate::<u32, _>(m, self.buckets_.buckets_.len()),
1998            },
1999            h9_opts: self.h9_opts,
2000        };
2001        ret.buckets_
2002            .buckets_
2003            .slice_mut()
2004            .clone_from_slice(self.buckets_.buckets_.slice());
2005        ret
2006    }
2007}
2008impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> CloneWithAlloc<Alloc>
2009    for BasicHasher<H3Sub<Alloc>>
2010{
2011    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
2012        let mut ret = BasicHasher::<H3Sub<Alloc>> {
2013            GetHasherCommon: self.GetHasherCommon.clone(),
2014            buckets_: H3Sub::<Alloc> {
2015                buckets_: allocate::<u32, _>(m, self.buckets_.buckets_.len()),
2016            },
2017            h9_opts: self.h9_opts,
2018        };
2019        ret.buckets_
2020            .buckets_
2021            .slice_mut()
2022            .clone_from_slice(self.buckets_.buckets_.slice());
2023        ret
2024    }
2025}
2026impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> CloneWithAlloc<Alloc>
2027    for BasicHasher<H4Sub<Alloc>>
2028{
2029    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
2030        let mut ret = BasicHasher::<H4Sub<Alloc>> {
2031            GetHasherCommon: self.GetHasherCommon.clone(),
2032            buckets_: H4Sub::<Alloc> {
2033                buckets_: allocate::<u32, _>(m, self.buckets_.buckets_.len()),
2034            },
2035            h9_opts: self.h9_opts,
2036        };
2037        ret.buckets_
2038            .buckets_
2039            .slice_mut()
2040            .clone_from_slice(self.buckets_.buckets_.slice());
2041        ret
2042    }
2043}
2044impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> CloneWithAlloc<Alloc>
2045    for BasicHasher<H54Sub<Alloc>>
2046{
2047    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
2048        let mut ret = BasicHasher::<H54Sub<Alloc>> {
2049            GetHasherCommon: self.GetHasherCommon.clone(),
2050            buckets_: H54Sub::<Alloc> {
2051                buckets_: allocate::<u32, _>(m, self.buckets_.len()),
2052            },
2053            h9_opts: self.h9_opts,
2054        };
2055        ret.buckets_
2056            .buckets_
2057            .slice_mut()
2058            .clone_from_slice(self.buckets_.buckets_.slice());
2059        ret
2060    }
2061}
2062impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> CloneWithAlloc<Alloc> for H9<Alloc> {
2063    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
2064        let mut num = allocate::<u16, _>(m, self.num_.len());
2065        num.slice_mut().clone_from_slice(self.num_.slice());
2066        let mut buckets = allocate::<u32, _>(m, self.buckets_.len());
2067        buckets.slice_mut().clone_from_slice(self.buckets_.slice());
2068        H9::<Alloc> {
2069            num_: num,
2070            buckets_: buckets,
2071            dict_search_stats_: self.dict_search_stats_.clone(),
2072            h9_opts: self.h9_opts,
2073        }
2074    }
2075}
2076impl<
2077        Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>,
2078        Special: AdvHashSpecialization + Sized + Clone,
2079    > CloneWithAlloc<Alloc> for AdvHasher<Special, Alloc>
2080{
2081    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
2082        let mut num = allocate::<u16, _>(m, self.num.len());
2083        num.slice_mut().clone_from_slice(self.num.slice());
2084        let mut buckets = allocate::<u32, _>(m, self.buckets.len());
2085        buckets.slice_mut().clone_from_slice(self.buckets.slice());
2086        AdvHasher::<Special, Alloc> {
2087            GetHasherCommon: self.GetHasherCommon.clone(),
2088            specialization: self.specialization.clone(),
2089            num,
2090            buckets,
2091            h9_opts: self.h9_opts,
2092        }
2093    }
2094}
2095
2096pub enum UnionHasher<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> {
2097    Uninit,
2098    H2(BasicHasher<H2Sub<Alloc>>),
2099    H3(BasicHasher<H3Sub<Alloc>>),
2100    H4(BasicHasher<H4Sub<Alloc>>),
2101    H54(BasicHasher<H54Sub<Alloc>>),
2102    H5(AdvHasher<H5Sub, Alloc>),
2103    H5q7(AdvHasher<HQ7Sub, Alloc>),
2104    H5q5(AdvHasher<HQ5Sub, Alloc>),
2105    H6(AdvHasher<H6Sub, Alloc>),
2106    H9(H9<Alloc>),
2107    H10(H10<Alloc, H10Buckets<Alloc>, H10DefaultParams>),
2108}
2109impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> PartialEq<UnionHasher<Alloc>>
2110    for UnionHasher<Alloc>
2111{
2112    fn eq(&self, other: &UnionHasher<Alloc>) -> bool {
2113        match *self {
2114            UnionHasher::H2(ref hasher) => match *other {
2115                UnionHasher::H2(ref otherh) => *hasher == *otherh,
2116                _ => false,
2117            },
2118            UnionHasher::H3(ref hasher) => match *other {
2119                UnionHasher::H3(ref otherh) => *hasher == *otherh,
2120                _ => false,
2121            },
2122            UnionHasher::H4(ref hasher) => match *other {
2123                UnionHasher::H4(ref otherh) => *hasher == *otherh,
2124                _ => false,
2125            },
2126            UnionHasher::H54(ref hasher) => match *other {
2127                UnionHasher::H54(ref otherh) => *hasher == *otherh,
2128                _ => false,
2129            },
2130            UnionHasher::H5(ref hasher) => match *other {
2131                UnionHasher::H5(ref otherh) => *hasher == *otherh,
2132                _ => false,
2133            },
2134            UnionHasher::H5q7(ref hasher) => match *other {
2135                UnionHasher::H5q7(ref otherh) => *hasher == *otherh,
2136                _ => false,
2137            },
2138            UnionHasher::H5q5(ref hasher) => match *other {
2139                UnionHasher::H5q5(ref otherh) => *hasher == *otherh,
2140                _ => false,
2141            },
2142            UnionHasher::H6(ref hasher) => match *other {
2143                UnionHasher::H6(ref otherh) => *hasher == *otherh,
2144                _ => false,
2145            },
2146            UnionHasher::H9(ref hasher) => match *other {
2147                UnionHasher::H9(ref otherh) => *hasher == *otherh,
2148                _ => false,
2149            },
2150            UnionHasher::H10(ref hasher) => match *other {
2151                UnionHasher::H10(ref otherh) => *hasher == *otherh,
2152                _ => false,
2153            },
2154            UnionHasher::Uninit => match *other {
2155                UnionHasher::Uninit => true,
2156                _ => false,
2157            },
2158        }
2159    }
2160}
2161impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> CloneWithAlloc<Alloc>
2162    for UnionHasher<Alloc>
2163{
2164    fn clone_with_alloc(&self, m: &mut Alloc) -> Self {
2165        match *self {
2166            UnionHasher::H2(ref hasher) => UnionHasher::H2(hasher.clone_with_alloc(m)),
2167            UnionHasher::H3(ref hasher) => UnionHasher::H3(hasher.clone_with_alloc(m)),
2168            UnionHasher::H4(ref hasher) => UnionHasher::H4(hasher.clone_with_alloc(m)),
2169            UnionHasher::H5(ref hasher) => UnionHasher::H5(hasher.clone_with_alloc(m)),
2170            UnionHasher::H5q7(ref hasher) => UnionHasher::H5q7(hasher.clone_with_alloc(m)),
2171            UnionHasher::H5q5(ref hasher) => UnionHasher::H5q5(hasher.clone_with_alloc(m)),
2172            UnionHasher::H6(ref hasher) => UnionHasher::H6(hasher.clone_with_alloc(m)),
2173            UnionHasher::H54(ref hasher) => UnionHasher::H54(hasher.clone_with_alloc(m)),
2174            UnionHasher::H9(ref hasher) => UnionHasher::H9(hasher.clone_with_alloc(m)),
2175            UnionHasher::H10(ref hasher) => UnionHasher::H10(hasher.clone_with_alloc(m)),
2176            UnionHasher::Uninit => UnionHasher::Uninit,
2177        }
2178    }
2179}
2180macro_rules! match_all_hashers_mut {
2181    ($xself : expr, $func_call : ident, $( $args:expr),*) => {
2182        match $xself {
2183     &mut UnionHasher::H2(ref mut hasher) => hasher.$func_call($($args),*),
2184     &mut UnionHasher::H3(ref mut hasher) => hasher.$func_call($($args),*),
2185     &mut UnionHasher::H4(ref mut hasher) => hasher.$func_call($($args),*),
2186     &mut UnionHasher::H5(ref mut hasher) => hasher.$func_call($($args),*),
2187     &mut UnionHasher::H5q7(ref mut hasher) => hasher.$func_call($($args),*),
2188     &mut UnionHasher::H5q5(ref mut hasher) => hasher.$func_call($($args),*),
2189     &mut UnionHasher::H6(ref mut hasher) => hasher.$func_call($($args),*),
2190     &mut UnionHasher::H54(ref mut hasher) => hasher.$func_call($($args),*),
2191     &mut UnionHasher::H9(ref mut hasher) => hasher.$func_call($($args),*),
2192     &mut UnionHasher::H10(ref mut hasher) => hasher.$func_call($($args),*),
2193     &mut UnionHasher::Uninit => panic!("UNINTIALIZED"),
2194        }
2195    };
2196}
2197macro_rules! match_all_hashers {
2198    ($xself : expr, $func_call : ident, $( $args:expr),*) => {
2199        match $xself {
2200     &UnionHasher::H2(ref hasher) => hasher.$func_call($($args),*),
2201     &UnionHasher::H3(ref hasher) => hasher.$func_call($($args),*),
2202     &UnionHasher::H4(ref hasher) => hasher.$func_call($($args),*),
2203     &UnionHasher::H5(ref hasher) => hasher.$func_call($($args),*),
2204     &UnionHasher::H5q7(ref hasher) => hasher.$func_call($($args),*),
2205     &UnionHasher::H5q5(ref hasher) => hasher.$func_call($($args),*),
2206     &UnionHasher::H6(ref hasher) => hasher.$func_call($($args),*),
2207     &UnionHasher::H54(ref hasher) => hasher.$func_call($($args),*),
2208     &UnionHasher::H9(ref hasher) => hasher.$func_call($($args),*),
2209     &UnionHasher::H10(ref hasher) => hasher.$func_call($($args),*),
2210     &UnionHasher::Uninit => panic!("UNINTIALIZED"),
2211        }
2212    };
2213}
2214impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> AnyHasher for UnionHasher<Alloc> {
2215    fn Opts(&self) -> H9Opts {
2216        match_all_hashers!(self, Opts,)
2217    }
2218    fn GetHasherCommon(&mut self) -> &mut Struct1 {
2219        match_all_hashers_mut!(self, GetHasherCommon,)
2220    } /*
2221      fn GetH10Tree(&mut self) -> Option<&mut H10<AllocU32, H10Buckets, H10DefaultParams>> {
2222        return match_all_hashers_mut!(self, GetH10Tree,);
2223      }*/
2224    fn Prepare(&mut self, one_shot: bool, input_size: usize, data: &[u8]) -> HowPrepared {
2225        match_all_hashers_mut!(self, Prepare, one_shot, input_size, data)
2226    }
2227    fn HashBytes(&self, data: &[u8]) -> usize {
2228        match_all_hashers!(self, HashBytes, data)
2229    }
2230    fn HashTypeLength(&self) -> usize {
2231        match_all_hashers!(self, HashTypeLength,)
2232    }
2233    fn StoreLookahead(&self) -> usize {
2234        match_all_hashers!(self, StoreLookahead,)
2235    }
2236    fn PrepareDistanceCache(&self, distance_cache: &mut [i32]) {
2237        match_all_hashers!(self, PrepareDistanceCache, distance_cache)
2238    }
2239    fn StitchToPreviousBlock(
2240        &mut self,
2241        num_bytes: usize,
2242        position: usize,
2243        ringbuffer: &[u8],
2244        ringbuffer_mask: usize,
2245    ) {
2246        match_all_hashers_mut!(
2247            self,
2248            StitchToPreviousBlock,
2249            num_bytes,
2250            position,
2251            ringbuffer,
2252            ringbuffer_mask
2253        )
2254    }
2255    fn FindLongestMatch(
2256        &mut self,
2257        dictionary: Option<&BrotliDictionary>,
2258        dictionary_hash: &[u16],
2259        data: &[u8],
2260        ring_buffer_mask: usize,
2261        ring_buffer_break: Option<core::num::NonZeroUsize>,
2262        distance_cache: &[i32],
2263        cur_ix: usize,
2264        max_length: usize,
2265        max_backward: usize,
2266        gap: usize,
2267        max_distance: usize,
2268        out: &mut HasherSearchResult,
2269    ) -> bool {
2270        match_all_hashers_mut!(
2271            self,
2272            FindLongestMatch,
2273            dictionary,
2274            dictionary_hash,
2275            data,
2276            ring_buffer_mask,
2277            ring_buffer_break,
2278            distance_cache,
2279            cur_ix,
2280            max_length,
2281            max_backward,
2282            gap,
2283            max_distance,
2284            out
2285        )
2286    }
2287    fn Store(&mut self, data: &[u8], mask: usize, ix: usize) {
2288        match_all_hashers_mut!(self, Store, data, mask, ix)
2289    }
2290    fn StoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
2291        match_all_hashers_mut!(self, StoreRange, data, mask, ix_start, ix_end)
2292    }
2293    fn BulkStoreRange(&mut self, data: &[u8], mask: usize, ix_start: usize, ix_end: usize) {
2294        match_all_hashers_mut!(self, BulkStoreRange, data, mask, ix_start, ix_end)
2295    }
2296}
2297
2298impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> UnionHasher<Alloc> {
2299    pub fn free(&mut self, alloc: &mut Alloc) {
2300        match self {
2301            &mut UnionHasher::H2(ref mut hasher) => {
2302                <Alloc as Allocator<u32>>::free_cell(
2303                    alloc,
2304                    core::mem::take(&mut hasher.buckets_.buckets_),
2305                );
2306            }
2307            &mut UnionHasher::H3(ref mut hasher) => {
2308                <Alloc as Allocator<u32>>::free_cell(
2309                    alloc,
2310                    core::mem::take(&mut hasher.buckets_.buckets_),
2311                );
2312            }
2313            &mut UnionHasher::H4(ref mut hasher) => {
2314                <Alloc as Allocator<u32>>::free_cell(
2315                    alloc,
2316                    core::mem::take(&mut hasher.buckets_.buckets_),
2317                );
2318            }
2319            &mut UnionHasher::H54(ref mut hasher) => {
2320                <Alloc as Allocator<u32>>::free_cell(
2321                    alloc,
2322                    core::mem::take(&mut hasher.buckets_.buckets_),
2323                );
2324            }
2325            &mut UnionHasher::H5q7(ref mut hasher) => {
2326                <Alloc as Allocator<u16>>::free_cell(alloc, core::mem::take(&mut hasher.num));
2327                <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut hasher.buckets));
2328            }
2329            &mut UnionHasher::H5q5(ref mut hasher) => {
2330                <Alloc as Allocator<u16>>::free_cell(alloc, core::mem::take(&mut hasher.num));
2331                <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut hasher.buckets));
2332            }
2333            &mut UnionHasher::H5(ref mut hasher) => {
2334                <Alloc as Allocator<u16>>::free_cell(alloc, core::mem::take(&mut hasher.num));
2335                <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut hasher.buckets));
2336            }
2337            &mut UnionHasher::H6(ref mut hasher) => {
2338                <Alloc as Allocator<u16>>::free_cell(alloc, core::mem::take(&mut hasher.num));
2339                <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut hasher.buckets));
2340            }
2341            &mut UnionHasher::H9(ref mut hasher) => {
2342                <Alloc as Allocator<u16>>::free_cell(alloc, core::mem::take(&mut hasher.num_));
2343                <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut hasher.buckets_));
2344            }
2345            &mut UnionHasher::H10(ref mut hasher) => {
2346                hasher.free(alloc);
2347            }
2348            &mut UnionHasher::Uninit => {}
2349        }
2350        *self = UnionHasher::<Alloc>::default();
2351    }
2352}
2353
2354impl<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>> Default for UnionHasher<Alloc> {
2355    fn default() -> Self {
2356        UnionHasher::Uninit
2357    }
2358}
2359
2360/*UnionHasher::H2(BasicHasher {
2361GetHasherCommon:Struct1{params:BrotliHasherParams{
2362 type_:2,
2363 block_bits: 8,
2364 bucket_bits:16,
2365 hash_len: 4,
2366 num_last_distances_to_check:0},
2367is_prepared_:0,
2368dict_num_lookups:0,
2369dict_num_matches:0,
2370},
2371buckets_:H2Sub{
2372buckets_:[0;65537],
2373},
2374})
2375*/
2376fn CreateBackwardReferences<AH: AnyHasher>(
2377    dictionary: Option<&BrotliDictionary>,
2378    dictionary_hash: &[u16],
2379    num_bytes: usize,
2380    mut position: usize,
2381    ringbuffer: &[u8],
2382    ringbuffer_mask: usize,
2383    ringbuffer_break: Option<core::num::NonZeroUsize>,
2384    params: &BrotliEncoderParams,
2385    hasher: &mut AH,
2386    dist_cache: &mut [i32],
2387    last_insert_len: &mut usize,
2388    mut commands: &mut [Command],
2389    num_commands: &mut usize,
2390    num_literals: &mut usize,
2391) {
2392    let gap = 0usize;
2393    let max_backward_limit: usize = (1usize << params.lgwin).wrapping_sub(16);
2394    let mut new_commands_count: usize = 0;
2395    let mut insert_length: usize = *last_insert_len;
2396    let pos_end: usize = position.wrapping_add(num_bytes);
2397    let store_end: usize = if num_bytes >= hasher.StoreLookahead() {
2398        position
2399            .wrapping_add(num_bytes)
2400            .wrapping_sub(hasher.StoreLookahead())
2401            .wrapping_add(1)
2402    } else {
2403        position
2404    };
2405    let random_heuristics_window_size: usize = LiteralSpreeLengthForSparseSearch(params);
2406    let mut apply_random_heuristics: usize = position.wrapping_add(random_heuristics_window_size);
2407    let kMinScore: u64 = (30u64 * 8)
2408        .wrapping_mul(::core::mem::size_of::<u64>() as u64)
2409        .wrapping_add(100);
2410    hasher.PrepareDistanceCache(dist_cache);
2411    while position.wrapping_add(hasher.HashTypeLength()) < pos_end {
2412        let mut max_length: usize = pos_end.wrapping_sub(position);
2413        let mut max_distance: usize = min(position, max_backward_limit);
2414        let mut sr = HasherSearchResult {
2415            len: 0,
2416            len_x_code: 0,
2417            distance: 0,
2418            score: 0,
2419        };
2420        sr.len = 0usize;
2421        sr.len_x_code = 0usize;
2422        sr.distance = 0usize;
2423        sr.score = kMinScore;
2424        if hasher.FindLongestMatch(
2425            dictionary,
2426            dictionary_hash,
2427            ringbuffer,
2428            ringbuffer_mask,
2429            ringbuffer_break,
2430            dist_cache,
2431            position,
2432            max_length,
2433            max_distance,
2434            gap,
2435            params.dist.max_distance,
2436            &mut sr,
2437        ) {
2438            let mut delayed_backward_references_in_row: i32 = 0i32;
2439            max_length = max_length.wrapping_sub(1);
2440            'break6: loop {
2441                'continue7: loop {
2442                    let cost_diff_lazy: u64 = 175;
2443
2444                    let mut sr2 = HasherSearchResult {
2445                        len: 0,
2446                        len_x_code: 0,
2447                        distance: 0,
2448                        score: 0,
2449                    };
2450                    sr2.len = if params.quality < 5 {
2451                        min(sr.len.wrapping_sub(1), max_length)
2452                    } else {
2453                        0usize
2454                    };
2455                    sr2.len_x_code = 0usize;
2456                    sr2.distance = 0usize;
2457                    sr2.score = kMinScore;
2458                    max_distance = min(position.wrapping_add(1), max_backward_limit);
2459                    let is_match_found: bool = hasher.FindLongestMatch(
2460                        dictionary,
2461                        dictionary_hash,
2462                        ringbuffer,
2463                        ringbuffer_mask,
2464                        ringbuffer_break,
2465                        dist_cache,
2466                        position.wrapping_add(1),
2467                        max_length,
2468                        max_distance,
2469                        gap,
2470                        params.dist.max_distance,
2471                        &mut sr2,
2472                    );
2473                    if is_match_found && (sr2.score >= sr.score.wrapping_add(cost_diff_lazy)) {
2474                        position = position.wrapping_add(1);
2475                        insert_length = insert_length.wrapping_add(1);
2476                        sr = sr2;
2477                        if {
2478                            delayed_backward_references_in_row += 1;
2479                            delayed_backward_references_in_row
2480                        } < 4i32
2481                            && (position.wrapping_add(hasher.HashTypeLength()) < pos_end)
2482                        {
2483                            break 'continue7;
2484                        }
2485                    }
2486                    break 'break6;
2487                }
2488                max_length = max_length.wrapping_sub(1);
2489            }
2490            apply_random_heuristics = position
2491                .wrapping_add((2usize).wrapping_mul(sr.len))
2492                .wrapping_add(random_heuristics_window_size);
2493            max_distance = min(position, max_backward_limit);
2494            {
2495                let distance_code: usize =
2496                    ComputeDistanceCode(sr.distance, max_distance, dist_cache);
2497                if sr.distance <= max_distance && (distance_code > 0usize) {
2498                    dist_cache[3] = dist_cache[2];
2499                    dist_cache[2] = dist_cache[1];
2500                    dist_cache[1] = dist_cache[0];
2501                    dist_cache[0] = sr.distance as i32;
2502                    hasher.PrepareDistanceCache(dist_cache);
2503                }
2504                new_commands_count += 1;
2505
2506                let (old, new_commands) = core::mem::take(&mut commands).split_at_mut(1);
2507                commands = new_commands;
2508                old[0].init(
2509                    &params.dist,
2510                    insert_length,
2511                    sr.len,
2512                    sr.len ^ sr.len_x_code,
2513                    distance_code,
2514                );
2515            }
2516            *num_literals = num_literals.wrapping_add(insert_length);
2517            insert_length = 0usize;
2518            hasher.StoreRange(
2519                ringbuffer,
2520                ringbuffer_mask,
2521                position.wrapping_add(2),
2522                min(position.wrapping_add(sr.len), store_end),
2523            );
2524            position = position.wrapping_add(sr.len);
2525        } else {
2526            insert_length = insert_length.wrapping_add(1);
2527            position = position.wrapping_add(1);
2528
2529            if position > apply_random_heuristics {
2530                let kMargin: usize = max(hasher.StoreLookahead().wrapping_sub(1), 4);
2531                if position.wrapping_add(16) >= pos_end.wrapping_sub(kMargin) {
2532                    insert_length = insert_length.wrapping_add(pos_end - position);
2533                    position = pos_end;
2534                } else if position
2535                    > apply_random_heuristics
2536                        .wrapping_add((4usize).wrapping_mul(random_heuristics_window_size))
2537                {
2538                    hasher.Store4Vec4(ringbuffer, ringbuffer_mask, position);
2539                    insert_length = insert_length.wrapping_add(16);
2540                    position = position.wrapping_add(16);
2541                } else {
2542                    hasher.StoreEvenVec4(ringbuffer, ringbuffer_mask, position);
2543                    insert_length = insert_length.wrapping_add(8);
2544                    position = position.wrapping_add(8);
2545                }
2546            }
2547        }
2548    }
2549    insert_length = insert_length.wrapping_add(pos_end.wrapping_sub(position));
2550    *last_insert_len = insert_length;
2551    *num_commands = num_commands.wrapping_add(new_commands_count);
2552}
2553pub fn BrotliCreateBackwardReferences<
2554    Alloc: alloc::Allocator<u16>
2555        + alloc::Allocator<u32>
2556        + alloc::Allocator<u64>
2557        + alloc::Allocator<floatX>
2558        + alloc::Allocator<ZopfliNode>,
2559>(
2560    alloc: &mut Alloc,
2561    dictionary: &BrotliDictionary,
2562    num_bytes: usize,
2563    position: usize,
2564    ringbuffer: &[u8],
2565    ringbuffer_mask: usize,
2566    ringbuffer_break: Option<core::num::NonZeroUsize>,
2567    params: &BrotliEncoderParams,
2568    hasher_union: &mut UnionHasher<Alloc>,
2569    dist_cache: &mut [i32],
2570    last_insert_len: &mut usize,
2571    commands: &mut [Command],
2572    num_commands: &mut usize,
2573    num_literals: &mut usize,
2574) {
2575    match (hasher_union) {
2576        &mut UnionHasher::Uninit => panic!("working with uninitialized hash map"),
2577        &mut UnionHasher::H10(ref mut hasher) => {
2578            if params.quality >= 11 {
2579                super::backward_references_hq::BrotliCreateHqZopfliBackwardReferences(
2580                    alloc,
2581                    if params.use_dictionary {
2582                        Some(dictionary)
2583                    } else {
2584                        None
2585                    },
2586                    num_bytes,
2587                    position,
2588                    ringbuffer,
2589                    ringbuffer_mask,
2590                    ringbuffer_break,
2591                    params,
2592                    hasher,
2593                    dist_cache,
2594                    last_insert_len,
2595                    commands,
2596                    num_commands,
2597                    num_literals,
2598                )
2599            } else {
2600                super::backward_references_hq::BrotliCreateZopfliBackwardReferences(
2601                    alloc,
2602                    if params.use_dictionary {
2603                        Some(dictionary)
2604                    } else {
2605                        None
2606                    },
2607                    num_bytes,
2608                    position,
2609                    ringbuffer,
2610                    ringbuffer_mask,
2611                    ringbuffer_break,
2612                    params,
2613                    hasher,
2614                    dist_cache,
2615                    last_insert_len,
2616                    commands,
2617                    num_commands,
2618                    num_literals,
2619                )
2620            }
2621        }
2622        &mut UnionHasher::H2(ref mut hasher) => CreateBackwardReferences(
2623            if params.use_dictionary {
2624                Some(dictionary)
2625            } else {
2626                None
2627            },
2628            &kStaticDictionaryHash[..],
2629            num_bytes,
2630            position,
2631            ringbuffer,
2632            ringbuffer_mask,
2633            ringbuffer_break,
2634            params,
2635            hasher,
2636            dist_cache,
2637            last_insert_len,
2638            commands,
2639            num_commands,
2640            num_literals,
2641        ),
2642        &mut UnionHasher::H3(ref mut hasher) => CreateBackwardReferences(
2643            if params.use_dictionary {
2644                Some(dictionary)
2645            } else {
2646                None
2647            },
2648            &kStaticDictionaryHash[..],
2649            num_bytes,
2650            position,
2651            ringbuffer,
2652            ringbuffer_mask,
2653            ringbuffer_break,
2654            params,
2655            hasher,
2656            dist_cache,
2657            last_insert_len,
2658            commands,
2659            num_commands,
2660            num_literals,
2661        ),
2662        &mut UnionHasher::H4(ref mut hasher) => CreateBackwardReferences(
2663            if params.use_dictionary {
2664                Some(dictionary)
2665            } else {
2666                None
2667            },
2668            &kStaticDictionaryHash[..],
2669            num_bytes,
2670            position,
2671            ringbuffer,
2672            ringbuffer_mask,
2673            ringbuffer_break,
2674            params,
2675            hasher,
2676            dist_cache,
2677            last_insert_len,
2678            commands,
2679            num_commands,
2680            num_literals,
2681        ),
2682        &mut UnionHasher::H5(ref mut hasher) => CreateBackwardReferences(
2683            if params.use_dictionary {
2684                Some(dictionary)
2685            } else {
2686                None
2687            },
2688            &kStaticDictionaryHash[..],
2689            num_bytes,
2690            position,
2691            ringbuffer,
2692            ringbuffer_mask,
2693            ringbuffer_break,
2694            params,
2695            hasher,
2696            dist_cache,
2697            last_insert_len,
2698            commands,
2699            num_commands,
2700            num_literals,
2701        ),
2702        &mut UnionHasher::H5q7(ref mut hasher) => CreateBackwardReferences(
2703            if params.use_dictionary {
2704                Some(dictionary)
2705            } else {
2706                None
2707            },
2708            &kStaticDictionaryHash[..],
2709            num_bytes,
2710            position,
2711            ringbuffer,
2712            ringbuffer_mask,
2713            ringbuffer_break,
2714            params,
2715            hasher,
2716            dist_cache,
2717            last_insert_len,
2718            commands,
2719            num_commands,
2720            num_literals,
2721        ),
2722        &mut UnionHasher::H5q5(ref mut hasher) => CreateBackwardReferences(
2723            if params.use_dictionary {
2724                Some(dictionary)
2725            } else {
2726                None
2727            },
2728            &kStaticDictionaryHash[..],
2729            num_bytes,
2730            position,
2731            ringbuffer,
2732            ringbuffer_mask,
2733            ringbuffer_break,
2734            params,
2735            hasher,
2736            dist_cache,
2737            last_insert_len,
2738            commands,
2739            num_commands,
2740            num_literals,
2741        ),
2742        &mut UnionHasher::H6(ref mut hasher) => CreateBackwardReferences(
2743            if params.use_dictionary {
2744                Some(dictionary)
2745            } else {
2746                None
2747            },
2748            &kStaticDictionaryHash[..],
2749            num_bytes,
2750            position,
2751            ringbuffer,
2752            ringbuffer_mask,
2753            ringbuffer_break,
2754            params,
2755            hasher,
2756            dist_cache,
2757            last_insert_len,
2758            commands,
2759            num_commands,
2760            num_literals,
2761        ),
2762        &mut UnionHasher::H9(ref mut hasher) => CreateBackwardReferences(
2763            if params.use_dictionary {
2764                Some(dictionary)
2765            } else {
2766                None
2767            },
2768            &kStaticDictionaryHash[..],
2769            num_bytes,
2770            position,
2771            ringbuffer,
2772            ringbuffer_mask,
2773            ringbuffer_break,
2774            params,
2775            hasher,
2776            dist_cache,
2777            last_insert_len,
2778            commands,
2779            num_commands,
2780            num_literals,
2781        ),
2782        &mut UnionHasher::H54(ref mut hasher) => CreateBackwardReferences(
2783            if params.use_dictionary {
2784                Some(dictionary)
2785            } else {
2786                None
2787            },
2788            &kStaticDictionaryHash[..],
2789            num_bytes,
2790            position,
2791            ringbuffer,
2792            ringbuffer_mask,
2793            ringbuffer_break,
2794            params,
2795            hasher,
2796            dist_cache,
2797            last_insert_len,
2798            commands,
2799            num_commands,
2800            num_literals,
2801        ),
2802    }
2803}