Skip to main content

simd_brotli/enc/backward_references/
mod.rs

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