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