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
42fn 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 pub type_: i32,
63 pub bucket_bits: i32,
65 pub block_bits: i32,
67 pub hash_len: i32,
69 pub num_last_distances_to_check: i32,
71 pub literal_byte_score: i32,
73}
74
75#[derive(Clone, Debug)]
76pub struct BrotliEncoderParams {
77 pub dist: BrotliDistanceParams,
78 pub mode: BrotliEncoderMode,
80 pub quality: i32,
82 pub q9_5: bool,
83 pub lgwin: i32,
85 pub lgblock: i32,
87 pub size_hint: usize,
89 pub disable_literal_context_modeling: i32,
92 pub hasher: BrotliHasherParams,
93 pub log_meta_block: bool,
95 pub stride_detection_quality: u8,
100 pub high_entropy_detection_quality: u8,
102 pub cdf_adaptation_detection: u8,
105 pub prior_bitmask_detection: u8,
107 pub literal_adaptation: [(u16, u16); 4],
109 pub large_window: bool,
110 pub avoid_distance_prefix_search: bool,
112 pub byte_align: bool,
115 pub bare_stream: bool,
118 pub catable: bool,
120 pub use_dictionary: bool,
122 pub appendable: bool,
124 pub magic_number: bool,
126 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 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, }
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, }
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, }
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, pub buckets_: <Alloc as Allocator<u32>>::AllocatedMemory, 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
661const BROTLI_DISTANCE_BIT_PENALTY: u32 = 120;
663
664const BROTLI_SCORE_BASE: u32 = (BROTLI_DISTANCE_BIT_PENALTY * 8 * 8);
666const kDistanceShortCodeCost: [u32; 16] = [
667 BROTLI_SCORE_BASE + 60,
669 BROTLI_SCORE_BASE - 95,
671 BROTLI_SCORE_BASE - 117,
672 BROTLI_SCORE_BASE - 127,
673 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 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 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, 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 }
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 0xffff_ffff }
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 }
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 0xffff_ffff }
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 0xffff_ffff }
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 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 (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 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; 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 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
1824pub 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 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(¶ms.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; 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 } 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
2703fn 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 ¶ms.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}