1#![allow(dead_code, unused_imports)]
2use super::hash_to_binary_tree::{
3 kInfinity, Allocable, BackwardMatch, BackwardMatchMut, H10Params, StoreAndFindMatchesH10,
4 Union1, ZopfliNode, H10,
5};
6use super::{
7 kDistanceCacheIndex, kDistanceCacheOffset, kHashMul32, kHashMul64, kHashMul64Long,
8 kInvalidMatch, AnyHasher, BrotliEncoderParams, BrotliHasherParams,
9};
10use alloc;
11use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
12use core;
13use core::cmp::{max, min};
14use enc::command::{
15 BrotliDistanceParams, CombineLengthCodes, Command, ComputeDistanceCode, GetCopyLengthCode,
16 GetInsertLengthCode, PrefixEncodeCopyDistance,
17};
18use enc::constants::{kCopyExtra, kInsExtra};
19use enc::dictionary_hash::kStaticDictionaryHash;
20use enc::encode;
21use enc::literal_cost::BrotliEstimateBitCostsForLiterals;
22use enc::static_dict::{
23 kBrotliEncDictionary, BrotliDictionary, BrotliFindAllStaticDictionaryMatches,
24};
25use enc::static_dict::{
26 FindMatchLengthWithLimit, BROTLI_UNALIGNED_LOAD32, BROTLI_UNALIGNED_LOAD64,
27};
28use enc::util::{floatX, FastLog2, FastLog2f64, Log2FloorNonZero};
29
30const BROTLI_WINDOW_GAP: usize = 16;
31const BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN: usize = 37;
32
33pub const BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE: usize = 544;
52pub const BROTLI_NUM_LITERAL_SYMBOLS: usize = 256;
53pub const BROTLI_NUM_COMMAND_SYMBOLS: usize = 704;
54
55pub const BROTLI_SIMPLE_DISTANCE_ALPHABET_SIZE: usize = encode::BROTLI_NUM_DISTANCE_SHORT_CODES
56 as usize
57 + (2 * encode::BROTLI_LARGE_MAX_DISTANCE_BITS as usize);
58
59const STORE_LOOKAHEAD_H_10: usize = 128;
60
61#[inline(always)]
62pub fn BrotliInitZopfliNodes(array: &mut [ZopfliNode], length: usize) {
63 let stub = ZopfliNode::default();
64 let mut i: usize;
65 i = 0usize;
66 while i < length {
67 array[i] = stub;
68 i = i.wrapping_add(1);
69 }
70}
71
72impl ZopfliNode {
73 #[inline(always)]
74 fn copy_length(&self) -> u32 {
75 self.length & 0x01ff_ffff
76 }
77
78 #[inline(always)]
79 fn copy_distance(&self) -> u32 {
80 self.distance
81 }
82
83 #[inline(always)]
84 fn length_code(&self) -> u32 {
85 self.copy_length()
86 .wrapping_add(9)
87 .wrapping_sub(self.length >> 25)
88 }
89
90 #[inline(always)]
91 fn distance_code(&self) -> u32 {
92 let short_code: u32 = self.dcode_insert_length >> 27;
93 if short_code == 0u32 {
94 self.copy_distance().wrapping_add(16).wrapping_sub(1)
95 } else {
96 short_code.wrapping_sub(1)
97 }
98 }
99}
100
101pub fn BrotliZopfliCreateCommands(
102 num_bytes: usize,
103 block_start: usize,
104 max_backward_limit: usize,
105 nodes: &[ZopfliNode],
106 dist_cache: &mut [i32],
107 last_insert_len: &mut usize,
108 params: &BrotliEncoderParams,
109 commands: &mut [Command],
110 num_literals: &mut usize,
111) {
112 let mut pos: usize = 0usize;
113 let mut offset: u32 = match (nodes[0]).u {
114 Union1::next(off) => off,
115 _ => 0,
116 };
117 let mut i: usize;
118 let gap: usize = 0usize;
119 i = 0usize;
120 while offset != !(0u32) {
121 {
122 let next: &ZopfliNode = &nodes[pos.wrapping_add(offset as usize)];
123 let copy_length = next.copy_length() as usize;
124 let mut insert_length: usize = (next.dcode_insert_length & 0x07ff_ffff) as usize;
125 pos = pos.wrapping_add(insert_length);
126 offset = match next.u {
127 Union1::next(off) => off,
128 _ => 0,
129 };
130 if i == 0usize {
131 insert_length = insert_length.wrapping_add(*last_insert_len);
132 *last_insert_len = 0usize;
133 }
134 {
135 let distance: usize = next.copy_distance() as usize;
136 let len_code: usize = next.length_code() as usize;
137 let max_distance: usize = min(block_start.wrapping_add(pos), max_backward_limit);
138 let is_dictionary = distance > max_distance.wrapping_add(gap);
139 let dist_code: usize = next.distance_code() as usize;
140 commands[i].init(
141 ¶ms.dist,
142 insert_length,
143 copy_length,
144 len_code,
145 dist_code,
146 );
147 if !is_dictionary && dist_code > 0 {
148 dist_cache[3] = dist_cache[2];
149 dist_cache[2] = dist_cache[1];
150 dist_cache[1] = dist_cache[0];
151 dist_cache[0] = distance as i32;
152 }
153 }
154 *num_literals = num_literals.wrapping_add(insert_length);
155 pos = pos.wrapping_add(copy_length);
156 }
157 i = i.wrapping_add(1);
158 }
159 *last_insert_len = last_insert_len.wrapping_add(num_bytes.wrapping_sub(pos));
160}
161
162#[inline(always)]
163fn MaxZopfliLen(params: &BrotliEncoderParams) -> usize {
164 (if params.quality <= 10i32 {
165 150i32
166 } else {
167 325i32
168 }) as usize
169}
170
171pub struct ZopfliCostModel<AllocF: Allocator<floatX>> {
172 pub cost_cmd_: [floatX; BROTLI_NUM_COMMAND_SYMBOLS],
173 pub cost_dist_: AllocF::AllocatedMemory,
174 pub distance_histogram_size: u32,
175 pub literal_costs_: AllocF::AllocatedMemory,
176 pub min_cost_cmd_: floatX,
177 pub num_bytes_: usize,
178}
179
180#[derive(Copy, Clone, Debug)]
181pub struct PosData {
182 pub pos: usize,
183 pub distance_cache: [i32; 4],
184 pub costdiff: floatX,
185 pub cost: floatX,
186}
187
188#[derive(Copy, Clone, Debug)]
189pub struct StartPosQueue {
190 pub q_: [PosData; 8],
191 pub idx_: usize,
192}
193impl Default for StartPosQueue {
194 #[inline(always)]
195 fn default() -> Self {
196 StartPosQueue {
197 q_: [PosData {
198 pos: 0,
199 distance_cache: [0; 4],
200 costdiff: 0.0,
201 cost: 0.0,
202 }; 8],
203 idx_: 0,
204 }
205 }
206}
207
208impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
209 fn init(m: &mut AllocF, dist: &BrotliDistanceParams, num_bytes: usize) -> Self {
210 Self {
211 num_bytes_: num_bytes,
212 cost_cmd_: [0.0; 704],
213 min_cost_cmd_: 0.0,
214 literal_costs_: if num_bytes.wrapping_add(2) > 0usize {
215 m.alloc_cell(num_bytes.wrapping_add(2))
216 } else {
217 AllocF::AllocatedMemory::default()
218 },
219 cost_dist_: if dist.alphabet_size > 0u32 {
220 m.alloc_cell(num_bytes.wrapping_add(dist.alphabet_size as usize))
221 } else {
222 AllocF::AllocatedMemory::default()
223 },
224 distance_histogram_size: min(dist.alphabet_size, 544),
225 }
226 }
227
228 fn set_from_literal_costs(
229 &mut self,
230 position: usize,
231 ringbuffer: &[u8],
232 ringbuffer_mask: usize,
233 ) {
234 let literal_costs = self.literal_costs_.slice_mut();
235 let mut literal_carry: floatX = 0.0;
236 let cost_dist = self.cost_dist_.slice_mut();
237 let cost_cmd = &mut self.cost_cmd_[..];
238 let num_bytes: usize = self.num_bytes_;
239 BrotliEstimateBitCostsForLiterals(
240 position,
241 num_bytes,
242 ringbuffer_mask,
243 ringbuffer,
244 &mut literal_costs[1..],
245 );
246 literal_costs[0] = 0.0 as (floatX);
247 for i in 0usize..num_bytes {
248 literal_carry = literal_carry as floatX + literal_costs[i.wrapping_add(1)] as floatX;
249 literal_costs[i.wrapping_add(1)] =
250 (literal_costs[i] as floatX + literal_carry) as floatX;
251 literal_carry -=
252 (literal_costs[i.wrapping_add(1)] as floatX - literal_costs[i] as floatX);
253 }
254 for i in 0..BROTLI_NUM_COMMAND_SYMBOLS {
255 cost_cmd[i] = FastLog2(11 + i as u64);
256 }
257 for i in 0usize..self.distance_histogram_size as usize {
258 cost_dist[i] = FastLog2((20u64).wrapping_add(i as (u64))) as (floatX);
259 }
260 self.min_cost_cmd_ = FastLog2(11) as (floatX);
261 }
262}
263
264#[inline(always)]
265fn HashBytesH10(data: &[u8]) -> u32 {
266 let h: u32 = BROTLI_UNALIGNED_LOAD32(data).wrapping_mul(kHashMul32);
267 h >> (32i32 - 17i32)
268}
269
270pub fn StitchToPreviousBlockH10<
271 AllocU32: Allocator<u32>,
272 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
273 Params: H10Params,
274>(
275 handle: &mut H10<AllocU32, Buckets, Params>,
276 num_bytes: usize,
277 position: usize,
278 ringbuffer: &[u8],
279 ringbuffer_mask: usize,
280) where
281 Buckets: PartialEq<Buckets>,
282{
283 if (num_bytes >= handle.HashTypeLength() - 1
284 && position >= Params::max_tree_comp_length() as usize)
285 {
286 let i_start = position - Params::max_tree_comp_length() as usize;
290 let i_end = min(position, i_start.wrapping_add(num_bytes));
291 for i in i_start..i_end {
292 let max_backward = handle.window_mask_ - max(BROTLI_WINDOW_GAP - 1, position - i);
297 let mut _best_len = 0;
298 StoreAndFindMatchesH10(
302 handle,
303 ringbuffer,
304 i,
305 ringbuffer_mask,
306 <Params as H10Params>::max_tree_comp_length() as usize,
307 max_backward,
308 &mut _best_len,
309 &mut [],
310 );
311 }
312 }
313}
314fn FindAllMatchesH10<
315 AllocU32: Allocator<u32>,
316 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
317 Params: H10Params,
318>(
319 handle: &mut H10<AllocU32, Buckets, Params>,
320 dictionary: Option<&BrotliDictionary>,
321 data: &[u8],
322 ring_buffer_mask: usize,
323 cur_ix: usize,
324 max_length: usize,
325 max_backward: usize,
326 gap: usize,
327 params: &BrotliEncoderParams,
328 matches: &mut [u64],
329) -> usize
330where
331 Buckets: PartialEq<Buckets>,
332{
333 let mut matches_offset = 0usize;
334 let cur_ix_masked: usize = cur_ix & ring_buffer_mask;
335 let mut best_len: usize = 1usize;
336 let short_match_max_backward: usize = (if params.quality != 11i32 {
337 16i32
338 } else {
339 64i32
340 }) as usize;
341 let mut stop: usize = cur_ix.wrapping_sub(short_match_max_backward);
342 let mut dict_matches = [kInvalidMatch; BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1];
343 let mut i: usize;
344 if cur_ix < short_match_max_backward {
345 stop = 0usize;
346 }
347 i = cur_ix.wrapping_sub(1);
348 'break14: while i > stop && (best_len <= 2usize) {
349 'continue15: loop {
350 {
351 let mut prev_ix: usize = i;
352 let backward: usize = cur_ix.wrapping_sub(prev_ix);
353 if backward > max_backward {
354 break 'break14;
355 }
356 prev_ix &= ring_buffer_mask;
357 if data[cur_ix_masked] as i32 != data[prev_ix] as i32
358 || data[cur_ix_masked.wrapping_add(1)] as i32
359 != data[prev_ix.wrapping_add(1)] as i32
360 {
361 break 'continue15;
362 }
363 {
364 let len: usize = FindMatchLengthWithLimit(
365 &data[prev_ix..],
366 &data[cur_ix_masked..],
367 max_length,
368 );
369 if len > best_len {
370 best_len = len;
371 BackwardMatchMut(&mut matches[matches_offset]).init(backward, len);
372 matches_offset += 1;
373 }
374 }
375 }
376 break;
377 }
378 i = i.wrapping_sub(1);
379 }
380 if best_len < max_length {
381 let loc_offset = StoreAndFindMatchesH10(
382 handle,
383 data,
384 cur_ix,
385 ring_buffer_mask,
386 max_length,
387 max_backward,
388 &mut best_len,
389 matches.split_at_mut(matches_offset).1,
390 );
391 matches_offset += loc_offset;
392 }
393 for i in 0..=37 {
394 dict_matches[i] = kInvalidMatch
395 }
396 {
397 let minlen = max(4, best_len.wrapping_add(1));
398 if dictionary.is_some()
399 && BrotliFindAllStaticDictionaryMatches(
400 dictionary.unwrap(),
401 &data[cur_ix_masked..],
402 minlen,
403 max_length,
404 &mut dict_matches[..],
405 ) != 0
406 {
407 assert!(params.use_dictionary);
408 let maxlen = min(37, max_length);
409 for l in minlen..=maxlen {
410 let dict_id: u32 = dict_matches[l];
411 if dict_id < kInvalidMatch {
412 let distance: usize = max_backward
413 .wrapping_add(gap)
414 .wrapping_add((dict_id >> 5) as usize)
415 .wrapping_add(1);
416 if distance <= params.dist.max_distance {
417 BackwardMatchMut(&mut matches[matches_offset]).init_dictionary(
418 distance,
419 l,
420 (dict_id & 31u32) as usize,
421 );
422 matches_offset += 1;
423 }
424 }
425 }
426 }
427 }
428 matches_offset
429}
430
431impl BackwardMatch {
432 #[inline(always)]
433 fn length(&self) -> usize {
434 (self.length_and_code() >> 5) as usize
435 }
436}
437
438#[inline(always)]
439fn MaxZopfliCandidates(params: &BrotliEncoderParams) -> usize {
440 (if params.quality <= 10i32 { 1i32 } else { 5i32 }) as usize
441}
442
443#[inline(always)]
444fn ComputeDistanceShortcut(
445 block_start: usize,
446 pos: usize,
447 max_backward: usize,
448 gap: usize,
449 nodes: &[ZopfliNode],
450) -> u32 {
451 let clen: usize = nodes[pos].copy_length() as usize;
452 let ilen: usize = ((nodes[pos]).dcode_insert_length) as usize & 0x07ff_ffff;
453 let dist: usize = nodes[pos].copy_distance() as usize;
454 if pos == 0usize {
455 0u32
456 } else if dist.wrapping_add(clen) <= block_start.wrapping_add(pos).wrapping_add(gap)
457 && dist <= max_backward.wrapping_add(gap)
458 && nodes[pos].distance_code() > 0
459 {
460 pos as u32
461 } else {
462 match (nodes[(pos.wrapping_sub(clen).wrapping_sub(ilen) as usize)]).u {
463 Union1::shortcut(shrt) => shrt,
464 _ => 0,
465 }
466 }
467}
468
469impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
470 #[inline(always)]
471 fn get_literal_costs(&self, from: usize, to: usize) -> floatX {
472 self.literal_costs_.slice()[to] - self.literal_costs_.slice()[from]
473 }
474}
475
476fn ComputeDistanceCache(
477 pos: usize,
478 mut starting_dist_cache: &[i32],
479 nodes: &[ZopfliNode],
480 dist_cache: &mut [i32],
481) {
482 let mut idx: i32 = 0i32;
483 let mut p: usize = match (nodes[pos]).u {
484 Union1::shortcut(shrt) => shrt,
485 _ => 0,
486 } as usize;
487 while idx < 4i32 && (p > 0usize) {
488 let ilen: usize = ((nodes[p]).dcode_insert_length) as usize & 0x07ff_ffff;
489 let clen = nodes[p].copy_length() as usize;
490 let dist = nodes[p].copy_distance() as usize;
491 dist_cache[({
492 let _old = idx;
493 idx += 1;
494 _old
495 } as usize)] = dist as i32;
496 p = match (nodes[(p.wrapping_sub(clen).wrapping_sub(ilen) as usize)]).u {
497 Union1::shortcut(shrt) => shrt,
498 _ => 0,
499 } as usize;
500 }
501 while idx < 4i32 {
502 {
503 dist_cache[(idx as usize)] = {
504 let (_old, _upper) = starting_dist_cache.split_at(1);
505 starting_dist_cache = _upper;
506 _old[0]
507 };
508 }
509 idx += 1;
510 }
511}
512
513impl StartPosQueue {
514 #[inline(always)]
515 fn size(&self) -> usize {
516 min(self.idx_, 8)
517 }
518
519 fn push(&mut self, posdata: &PosData) {
520 let mut offset: usize = !self.idx_ & 7usize;
521 self.idx_ = self.idx_.wrapping_add(1);
522 let len: usize = self.size();
523 let q: &mut [PosData; 8] = &mut self.q_;
524 q[offset] = *posdata;
525 for _i in 1..len {
526 if q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff {
527 q.swap(offset & 7, (offset + 1) & 7);
528 }
529 offset = offset.wrapping_add(1);
530 }
531 }
532}
533
534fn EvaluateNode<AllocF: Allocator<floatX>>(
535 block_start: usize,
536 pos: usize,
537 max_backward_limit: usize,
538 gap: usize,
539 starting_dist_cache: &[i32],
540 model: &ZopfliCostModel<AllocF>,
541 queue: &mut StartPosQueue,
542 nodes: &mut [ZopfliNode],
543) {
544 let node_cost: floatX = match (nodes[pos]).u {
545 Union1::cost(cst) => cst,
546 _ => 0.0,
547 };
548 (nodes[pos]).u = Union1::shortcut(ComputeDistanceShortcut(
549 block_start,
550 pos,
551 max_backward_limit,
552 gap,
553 nodes,
554 ));
555 if node_cost <= model.get_literal_costs(0, pos) {
556 let mut posdata = PosData {
557 pos,
558 cost: node_cost,
559 costdiff: node_cost - model.get_literal_costs(0, pos),
560 distance_cache: [0; 4],
561 };
562 ComputeDistanceCache(
563 pos,
564 starting_dist_cache,
565 nodes,
566 &mut posdata.distance_cache[..],
567 );
568 queue.push(&mut posdata);
569 }
570}
571
572impl StartPosQueue {
573 #[inline(always)]
574 fn at(&self, k: usize) -> &PosData {
575 &self.q_[k.wrapping_sub(self.idx_) & 7usize]
576 }
577}
578
579impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
580 #[inline(always)]
581 fn get_min_cost_cmd(&self) -> floatX {
582 self.min_cost_cmd_
583 }
584}
585
586#[inline(always)]
587fn ComputeMinimumCopyLength(
588 start_cost: floatX,
589 nodes: &[ZopfliNode],
590 num_bytes: usize,
591 pos: usize,
592) -> usize {
593 let mut min_cost: floatX = start_cost;
594 let mut len: usize = 2usize;
595 let mut next_len_bucket: usize = 4usize;
596 let mut next_len_offset: usize = 10usize;
597 while pos.wrapping_add(len) <= num_bytes
598 && (match (nodes[pos.wrapping_add(len)]).u {
599 Union1::cost(cst) => cst,
600 _ => 0.0,
601 } <= min_cost)
602 {
603 len = len.wrapping_add(1);
604 if len == next_len_offset {
605 min_cost += 1.0 as floatX;
606 next_len_offset = next_len_offset.wrapping_add(next_len_bucket);
607 next_len_bucket = next_len_bucket.wrapping_mul(2);
608 }
609 }
610 len
611}
612#[inline(always)]
613fn GetInsertExtra(inscode: u16) -> u32 {
614 kInsExtra[(inscode as usize)]
615}
616
617impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
618 #[inline(always)]
619 fn get_distance_cost(&self, distcode: usize) -> floatX {
620 self.cost_dist_.slice()[distcode]
621 }
622}
623
624#[inline(always)]
625fn GetCopyExtra(copycode: u16) -> u32 {
626 kCopyExtra[(copycode as usize)]
627}
628
629impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
630 #[inline(always)]
631 fn get_command_cost(&self, cmdcode: u16) -> floatX {
632 self.cost_cmd_[cmdcode as usize]
633 }
634}
635
636#[inline(always)]
637fn UpdateZopfliNode(
638 nodes: &mut [ZopfliNode],
639 pos: usize,
640 start_pos: usize,
641 len: usize,
642 len_code: usize,
643 dist: usize,
644 short_code: usize,
645 cost: floatX,
646) {
647 let next = &mut nodes[pos.wrapping_add(len)];
648 next.length = (len | len.wrapping_add(9u32 as usize).wrapping_sub(len_code) << 25) as u32;
649 next.distance = dist as u32;
650 next.dcode_insert_length = pos.wrapping_sub(start_pos) as u32 | (short_code << 27) as u32;
651 next.u = Union1::cost(cost);
652}
653
654impl BackwardMatch {
655 #[inline(always)]
656 fn length_code(&self) -> usize {
657 let code = (self.length_and_code() & 31u32) as usize;
658 if code != 0 {
659 code
660 } else {
661 self.length()
662 }
663 }
664}
665
666fn UpdateNodes<AllocF: Allocator<floatX>>(
667 num_bytes: usize,
668 block_start: usize,
669 pos: usize,
670 ringbuffer: &[u8],
671 ringbuffer_mask: usize,
672 params: &BrotliEncoderParams,
673 max_backward_limit: usize,
674 starting_dist_cache: &[i32],
675 num_matches: usize,
676 matches: &[u64],
677 model: &ZopfliCostModel<AllocF>,
678 queue: &mut StartPosQueue,
679 nodes: &mut [ZopfliNode],
680) -> usize {
681 let cur_ix: usize = block_start.wrapping_add(pos);
682 let cur_ix_masked: usize = cur_ix & ringbuffer_mask;
683 let max_distance: usize = min(cur_ix, max_backward_limit);
684 let max_len: usize = num_bytes.wrapping_sub(pos);
685 let max_zopfli_len: usize = MaxZopfliLen(params);
686 let max_iters: usize = MaxZopfliCandidates(params);
687 let min_len: usize;
688 let mut result: usize = 0usize;
689 let mut k: usize;
690 let gap: usize = 0usize;
691 EvaluateNode(
692 block_start,
693 pos,
694 max_backward_limit,
695 gap,
696 starting_dist_cache,
697 model,
698 queue,
699 nodes,
700 );
701 {
702 let posdata = queue.at(0);
703 let min_cost =
704 posdata.cost + model.get_min_cost_cmd() + model.get_literal_costs(posdata.pos, pos);
705 min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
706 }
707 k = 0usize;
708 while k < max_iters && k < queue.size() {
709 'continue28: loop {
710 {
711 let posdata = queue.at(k);
712 let start: usize = posdata.pos;
713 let inscode: u16 = GetInsertLengthCode(pos.wrapping_sub(start));
714 let start_costdiff: floatX = posdata.costdiff;
715 let base_cost: floatX = start_costdiff
716 + GetInsertExtra(inscode) as (floatX)
717 + model.get_literal_costs(0, pos);
718 let mut best_len: usize = min_len.wrapping_sub(1);
719 let mut j: usize = 0usize;
720 'break29: while j < 16usize && (best_len < max_len) {
721 'continue30: loop {
722 {
723 let idx: usize = kDistanceCacheIndex[j] as usize;
724 let distance_cache_len_minus_1 = 3;
725 debug_assert_eq!(
726 distance_cache_len_minus_1 + 1,
727 posdata.distance_cache.len()
728 );
729 let backward: usize = (posdata.distance_cache
730 [(idx & distance_cache_len_minus_1)]
731 + i32::from(kDistanceCacheOffset[j]))
732 as usize;
733 let mut prev_ix: usize = cur_ix.wrapping_sub(backward);
734 let len: usize;
735 let continuation: u8 = ringbuffer[cur_ix_masked.wrapping_add(best_len)];
736 if cur_ix_masked.wrapping_add(best_len) > ringbuffer_mask {
737 break 'break29;
738 }
739 if backward > max_distance.wrapping_add(gap) {
740 break 'continue30;
741 }
742 if backward <= max_distance {
743 if prev_ix >= cur_ix {
744 break 'continue30;
745 }
746 prev_ix &= ringbuffer_mask;
747 if prev_ix.wrapping_add(best_len) > ringbuffer_mask
748 || continuation as i32
749 != ringbuffer[(prev_ix.wrapping_add(best_len) as usize)]
750 as i32
751 {
752 break 'continue30;
753 }
754 len = FindMatchLengthWithLimit(
755 &ringbuffer[(prev_ix as usize)..],
756 &ringbuffer[cur_ix_masked..],
757 max_len,
758 );
759 } else {
760 break 'continue30;
761 }
762 {
763 let dist_cost = base_cost + model.get_distance_cost(j);
764 for l in best_len.wrapping_add(1)..=len {
765 let copycode: u16 = GetCopyLengthCode(l);
766 let cmdcode: u16 =
767 CombineLengthCodes(inscode, copycode, (j == 0usize) as i32);
768 let cost: floatX =
769 (if cmdcode < 128 { base_cost } else { dist_cost })
770 + (GetCopyExtra(copycode) as floatX)
771 + model.get_command_cost(cmdcode);
772 if cost
773 < match (nodes[pos.wrapping_add(l)]).u {
774 Union1::cost(cost) => cost,
775 _ => 0.0,
776 }
777 {
778 UpdateZopfliNode(
779 nodes,
780 pos,
781 start,
782 l,
783 l,
784 backward,
785 j.wrapping_add(1),
786 cost,
787 );
788 result = max(result, l);
789 }
790 best_len = l;
791 }
792 }
793 }
794 break;
795 }
796 j = j.wrapping_add(1);
797 }
798 if k >= 2usize {
799 break 'continue28;
800 }
801 {
802 let mut len: usize = min_len;
803 for j in 0usize..num_matches {
804 let match_ = BackwardMatch(matches[j]);
805 let dist: usize = match_.distance() as usize;
806 let is_dictionary_match = dist > max_distance.wrapping_add(gap);
807 let dist_code: usize = dist.wrapping_add(16).wrapping_sub(1);
808 let mut dist_symbol: u16 = 0;
809 let mut distextra: u32 = 0;
810
811 PrefixEncodeCopyDistance(
812 dist_code,
813 params.dist.num_direct_distance_codes as usize,
814 u64::from(params.dist.distance_postfix_bits),
815 &mut dist_symbol,
816 &mut distextra,
817 );
818 let distnumextra: u32 = u32::from(dist_symbol) >> 10;
819 let dist_cost = base_cost
820 + (distnumextra as floatX)
821 + model.get_distance_cost((dist_symbol as i32 & 0x03ff) as usize);
822 let max_match_len = match_.length();
823 if len < max_match_len
824 && (is_dictionary_match || max_match_len > max_zopfli_len)
825 {
826 len = max_match_len;
827 }
828 while len <= max_match_len {
829 {
830 let len_code: usize = if is_dictionary_match {
831 match_.length_code()
832 } else {
833 len
834 };
835 let copycode: u16 = GetCopyLengthCode(len_code);
836 let cmdcode: u16 = CombineLengthCodes(inscode, copycode, 0i32);
837 let cost: floatX = dist_cost
838 + GetCopyExtra(copycode) as (floatX)
839 + model.get_command_cost(cmdcode);
840 if let Union1::cost(nodeCost) = (nodes[pos.wrapping_add(len)]).u {
841 if cost < nodeCost {
842 UpdateZopfliNode(
843 nodes, pos, start, len, len_code, dist, 0usize, cost,
844 );
845 result = max(result, len);
846 }
847 }
848 }
849 len = len.wrapping_add(1);
850 }
851 }
852 }
853 }
854 break;
855 }
856 k = k.wrapping_add(1);
857 }
858 result
859}
860
861impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
862 #[inline(always)]
863 fn cleanup(&mut self, m: &mut AllocF) {
864 m.free_cell(core::mem::take(&mut self.literal_costs_));
865 m.free_cell(core::mem::take(&mut self.cost_dist_));
866 }
867}
868
869impl ZopfliNode {
870 #[inline(always)]
871 fn command_length(&self) -> u32 {
872 self.copy_length()
873 .wrapping_add(self.dcode_insert_length & 0x07ff_ffff)
874 }
875}
876
877#[inline(always)]
878fn ComputeShortestPathFromNodes(num_bytes: usize, nodes: &mut [ZopfliNode]) -> usize {
879 let mut index: usize = num_bytes;
880 let mut num_commands: usize = 0usize;
881 while (nodes[index].dcode_insert_length & 0x07ff_ffff) == 0 && nodes[index].length == 1 {
882 index = index.wrapping_sub(1);
883 }
884 nodes[index].u = Union1::next(!(0u32));
885 while index != 0 {
886 let len = nodes[index].command_length() as usize;
887 index = index.wrapping_sub(len);
888 (nodes[index]).u = Union1::next(len as u32);
889 num_commands = num_commands.wrapping_add(1);
890 }
891 num_commands
892}
893
894const MAX_NUM_MATCHES_H10: usize = 128;
895pub fn BrotliZopfliComputeShortestPath<
896 AllocU32: Allocator<u32>,
897 Buckets: Allocable<u32, AllocU32> + SliceWrapperMut<u32> + SliceWrapper<u32>,
898 Params: H10Params,
899 AllocF: Allocator<floatX>,
900>(
901 m: &mut AllocF,
902 dictionary: Option<&BrotliDictionary>,
903 num_bytes: usize,
904 position: usize,
905 ringbuffer: &[u8],
906 ringbuffer_mask: usize,
907 params: &BrotliEncoderParams,
908 max_backward_limit: usize,
909 dist_cache: &[i32],
910 handle: &mut H10<AllocU32, Buckets, Params>,
911 nodes: &mut [ZopfliNode],
912) -> usize
913where
914 Buckets: PartialEq<Buckets>,
915{
916 let max_zopfli_len: usize = MaxZopfliLen(params);
917 let mut model: ZopfliCostModel<AllocF>;
918 let mut queue: StartPosQueue;
919 let mut matches = [0; MAX_NUM_MATCHES_H10];
920 let store_end: usize = if num_bytes >= STORE_LOOKAHEAD_H_10 {
921 position
922 .wrapping_add(num_bytes)
923 .wrapping_sub(STORE_LOOKAHEAD_H_10)
924 .wrapping_add(1)
925 } else {
926 position
927 };
928 let mut i: usize;
929 let gap: usize = 0usize;
930 let lz_matches_offset: usize = 0usize;
931 (nodes[0]).length = 0u32;
932 (nodes[0]).u = Union1::cost(0.0);
933 model = ZopfliCostModel::init(m, ¶ms.dist, num_bytes);
934 if !(0i32 == 0) {
935 return 0usize;
936 }
937 model.set_from_literal_costs(position, ringbuffer, ringbuffer_mask);
938 queue = StartPosQueue::default();
939 i = 0usize;
940 while i.wrapping_add(handle.HashTypeLength()).wrapping_sub(1) < num_bytes {
941 {
942 let pos: usize = position.wrapping_add(i);
943 let max_distance: usize = min(pos, max_backward_limit);
944 let mut skip: usize;
945 let mut num_matches: usize = FindAllMatchesH10(
946 handle,
947 dictionary,
948 ringbuffer,
949 ringbuffer_mask,
950 pos,
951 num_bytes.wrapping_sub(i),
952 max_distance,
953 gap,
954 params,
955 &mut matches[lz_matches_offset..],
956 );
957 if num_matches > 0
958 && BackwardMatch(matches[num_matches.wrapping_sub(1)]).length() > max_zopfli_len
959 {
960 matches[0] = matches[num_matches.wrapping_sub(1)];
961 num_matches = 1usize;
962 }
963 skip = UpdateNodes(
964 num_bytes,
965 position,
966 i,
967 ringbuffer,
968 ringbuffer_mask,
969 params,
970 max_backward_limit,
971 dist_cache,
972 num_matches,
973 &matches[..],
974 &mut model,
975 &mut queue,
976 nodes,
977 );
978 if skip < 16384usize {
979 skip = 0usize;
980 }
981 if num_matches == 1 && BackwardMatch(matches[0]).length() > max_zopfli_len {
982 skip = max(BackwardMatch(matches[0]).length(), skip);
983 }
984 if skip > 1usize {
985 handle.StoreRange(
986 ringbuffer,
987 ringbuffer_mask,
988 pos.wrapping_add(1),
989 min(pos.wrapping_add(skip), store_end),
990 );
991 skip = skip.wrapping_sub(1);
992 while skip != 0 {
993 i = i.wrapping_add(1);
994 if i.wrapping_add(handle.HashTypeLength()).wrapping_sub(1) >= num_bytes {
995 break;
996 }
997 EvaluateNode(
998 position,
999 i,
1000 max_backward_limit,
1001 gap,
1002 dist_cache,
1003 &mut model,
1004 &mut queue,
1005 nodes,
1006 );
1007 skip = skip.wrapping_sub(1);
1008 }
1009 }
1010 }
1011 i = i.wrapping_add(1);
1012 }
1013
1014 model.cleanup(m);
1015
1016 ComputeShortestPathFromNodes(num_bytes, nodes)
1017}
1018
1019pub fn BrotliCreateZopfliBackwardReferences<
1020 Alloc: Allocator<u32> + Allocator<floatX> + Allocator<ZopfliNode>,
1021 Buckets: Allocable<u32, Alloc> + SliceWrapperMut<u32> + SliceWrapper<u32>,
1022 Params: H10Params,
1023>(
1024 alloc: &mut Alloc,
1025 dictionary: Option<&BrotliDictionary>,
1026 num_bytes: usize,
1027 position: usize,
1028 ringbuffer: &[u8],
1029 ringbuffer_mask: usize,
1030 params: &BrotliEncoderParams,
1031 hasher: &mut H10<Alloc, Buckets, Params>,
1032 dist_cache: &mut [i32],
1033 last_insert_len: &mut usize,
1034 commands: &mut [Command],
1035 num_commands: &mut usize,
1036 num_literals: &mut usize,
1037) where
1038 Buckets: PartialEq<Buckets>,
1039{
1040 let max_backward_limit: usize = (1usize << params.lgwin).wrapping_sub(16);
1041 let mut nodes: <Alloc as Allocator<ZopfliNode>>::AllocatedMemory;
1042 nodes = if num_bytes.wrapping_add(1) > 0usize {
1043 <Alloc as Allocator<ZopfliNode>>::alloc_cell(alloc, num_bytes.wrapping_add(1))
1044 } else {
1045 <Alloc as Allocator<ZopfliNode>>::AllocatedMemory::default()
1046 };
1047 if !(0i32 == 0) {
1048 return;
1049 }
1050 BrotliInitZopfliNodes(nodes.slice_mut(), num_bytes.wrapping_add(1));
1051 *num_commands = num_commands.wrapping_add(BrotliZopfliComputeShortestPath(
1052 alloc,
1053 dictionary,
1054 num_bytes,
1055 position,
1056 ringbuffer,
1057 ringbuffer_mask,
1058 params,
1059 max_backward_limit,
1060 dist_cache,
1061 hasher,
1062 nodes.slice_mut(),
1063 ));
1064 if !(0i32 == 0) {
1065 return;
1066 }
1067 BrotliZopfliCreateCommands(
1068 num_bytes,
1069 position,
1070 max_backward_limit,
1071 nodes.slice(),
1072 dist_cache,
1073 last_insert_len,
1074 params,
1075 commands,
1076 num_literals,
1077 );
1078 {
1079 <Alloc as Allocator<ZopfliNode>>::free_cell(alloc, core::mem::take(&mut nodes));
1080 }
1081}
1082
1083fn SetCost(histogram: &[u32], histogram_size: usize, literal_histogram: i32, cost: &mut [floatX]) {
1084 let mut sum: u64 = 0;
1085 let mut missing_symbol_sum: u64;
1086
1087 let mut i: usize;
1088 for i in 0usize..histogram_size {
1089 sum = sum.wrapping_add(u64::from(histogram[i]));
1090 }
1091 let log2sum: floatX = FastLog2(sum) as (floatX);
1092 missing_symbol_sum = sum;
1093 if literal_histogram == 0 {
1094 for i in 0usize..histogram_size {
1095 if histogram[i] == 0u32 {
1096 missing_symbol_sum = missing_symbol_sum.wrapping_add(1);
1097 }
1098 }
1099 }
1100 let missing_symbol_cost: floatX =
1101 FastLog2f64(missing_symbol_sum) as (floatX) + 2i32 as (floatX);
1102 i = 0usize;
1103 while i < histogram_size {
1104 'continue56: loop {
1105 {
1106 if histogram[i] == 0u32 {
1107 cost[i] = missing_symbol_cost;
1108 break 'continue56;
1109 }
1110 cost[i] = log2sum - FastLog2(u64::from(histogram[i])) as (floatX);
1111 if cost[i] < 1i32 as (floatX) {
1112 cost[i] = 1i32 as (floatX);
1113 }
1114 }
1115 break;
1116 }
1117 i = i.wrapping_add(1);
1118 }
1119}
1120
1121impl<AllocF: Allocator<floatX>> ZopfliCostModel<AllocF> {
1122 fn set_from_commands(
1123 &mut self,
1124 position: usize,
1125 ringbuffer: &[u8],
1126 ringbuffer_mask: usize,
1127 commands: &[Command],
1128 num_commands: usize,
1129 last_insert_len: usize,
1130 ) {
1131 let mut histogram_literal = [0u32; BROTLI_NUM_LITERAL_SYMBOLS];
1132 let mut histogram_cmd = [0u32; BROTLI_NUM_COMMAND_SYMBOLS];
1133 let mut histogram_dist = [0u32; BROTLI_SIMPLE_DISTANCE_ALPHABET_SIZE];
1134 let mut cost_literal = [0.0 as floatX; BROTLI_NUM_LITERAL_SYMBOLS];
1135 let mut pos: usize = position.wrapping_sub(last_insert_len);
1136 let mut min_cost_cmd: floatX = kInfinity;
1137 let mut i: usize;
1138 let cost_cmd: &mut [floatX] = &mut self.cost_cmd_[..];
1139 i = 0usize;
1140 while i < num_commands {
1141 {
1142 let inslength: usize = (commands[i]).insert_len_ as usize;
1143 let copylength: usize = commands[i].copy_len() as usize;
1144 let distcode: usize = (commands[i].dist_prefix_ as i32 & 0x03ff) as usize;
1145 let cmdcode: usize = (commands[i]).cmd_prefix_ as usize;
1146 {
1147 let _rhs = 1;
1148 let _lhs = &mut histogram_cmd[cmdcode];
1149 *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1150 }
1151 if cmdcode >= 128usize {
1152 let _rhs = 1;
1153 let _lhs = &mut histogram_dist[distcode];
1154 *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1155 }
1156 for j in 0usize..inslength {
1157 let _rhs = 1;
1158 let _lhs = &mut histogram_literal
1159 [(ringbuffer[(pos.wrapping_add(j) & ringbuffer_mask)] as usize)];
1160 *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1161 }
1162 pos = pos.wrapping_add(inslength.wrapping_add(copylength));
1163 }
1164 i = i.wrapping_add(1);
1165 }
1166 SetCost(
1167 &histogram_literal[..],
1168 BROTLI_NUM_LITERAL_SYMBOLS,
1169 1i32,
1170 &mut cost_literal,
1171 );
1172 SetCost(
1173 &histogram_cmd[..],
1174 BROTLI_NUM_COMMAND_SYMBOLS,
1175 0i32,
1176 &mut cost_cmd[..],
1177 );
1178 SetCost(
1179 &histogram_dist[..],
1180 self.distance_histogram_size as usize,
1181 0i32,
1182 self.cost_dist_.slice_mut(),
1183 );
1184 for i in 0usize..704usize {
1185 min_cost_cmd = min_cost_cmd.min(cost_cmd[i]);
1186 }
1187 self.min_cost_cmd_ = min_cost_cmd;
1188 {
1189 let literal_costs: &mut [floatX] = self.literal_costs_.slice_mut();
1190 let mut literal_carry: floatX = 0.0;
1191 let num_bytes: usize = self.num_bytes_;
1192 literal_costs[0] = 0.0 as (floatX);
1193 for i in 0usize..num_bytes {
1194 literal_carry += cost_literal
1195 [(ringbuffer[(position.wrapping_add(i) & ringbuffer_mask)] as usize)]
1196 as floatX;
1197 literal_costs[i.wrapping_add(1)] =
1198 (literal_costs[i] as floatX + literal_carry) as floatX;
1199 literal_carry -=
1200 (literal_costs[i.wrapping_add(1)] as floatX - literal_costs[i] as floatX);
1201 }
1202 }
1203 }
1204}
1205
1206fn ZopfliIterate<AllocF: Allocator<floatX>>(
1207 num_bytes: usize,
1208 position: usize,
1209 ringbuffer: &[u8],
1210 ringbuffer_mask: usize,
1211 params: &BrotliEncoderParams,
1212 max_backward_limit: usize,
1213 gap: usize,
1214 dist_cache: &[i32],
1215 model: &ZopfliCostModel<AllocF>,
1216 num_matches: &[u32],
1217 matches: &[u64],
1218 nodes: &mut [ZopfliNode],
1219) -> usize {
1220 let max_zopfli_len: usize = MaxZopfliLen(params);
1221 let mut queue: StartPosQueue;
1222 let mut cur_match_pos: usize = 0usize;
1223 let mut i: usize;
1224 (nodes[0]).length = 0u32;
1225 (nodes[0]).u = Union1::cost(0.0);
1226 queue = StartPosQueue::default();
1227 i = 0usize;
1228 while i.wrapping_add(3) < num_bytes {
1229 {
1230 let mut skip: usize = UpdateNodes(
1231 num_bytes,
1232 position,
1233 i,
1234 ringbuffer,
1235 ringbuffer_mask,
1236 params,
1237 max_backward_limit,
1238 dist_cache,
1239 num_matches[i] as usize,
1240 &matches[cur_match_pos..],
1241 model,
1242 &mut queue,
1243 nodes,
1244 );
1245 if skip < 16384usize {
1246 skip = 0usize;
1247 }
1248 cur_match_pos = cur_match_pos.wrapping_add(num_matches[i] as usize);
1249 if num_matches[i] == 1
1250 && BackwardMatch(matches[cur_match_pos.wrapping_sub(1)]).length() > max_zopfli_len
1251 {
1252 skip = max(
1253 BackwardMatch(matches[cur_match_pos.wrapping_sub(1)]).length(),
1254 skip,
1255 );
1256 }
1257 if skip > 1usize {
1258 skip = skip.wrapping_sub(1);
1259 while skip != 0 {
1260 i = i.wrapping_add(1);
1261 if i.wrapping_add(3) >= num_bytes {
1262 break;
1263 }
1264 EvaluateNode(
1265 position,
1266 i,
1267 max_backward_limit,
1268 gap,
1269 dist_cache,
1270 model,
1271 &mut queue,
1272 nodes,
1273 );
1274 cur_match_pos = cur_match_pos.wrapping_add(num_matches[i] as usize);
1275 skip = skip.wrapping_sub(1);
1276 }
1277 }
1278 }
1279 i = i.wrapping_add(1);
1280 }
1281 ComputeShortestPathFromNodes(num_bytes, nodes)
1282}
1283
1284pub fn BrotliCreateHqZopfliBackwardReferences<
1285 Alloc: Allocator<u32> + Allocator<u64> + Allocator<floatX> + Allocator<ZopfliNode>,
1286 Buckets: Allocable<u32, Alloc> + SliceWrapperMut<u32> + SliceWrapper<u32>,
1287 Params: H10Params,
1288>(
1289 alloc: &mut Alloc,
1290 dictionary: Option<&BrotliDictionary>,
1291 num_bytes: usize,
1292 position: usize,
1293 ringbuffer: &[u8],
1294 ringbuffer_mask: usize,
1295 params: &BrotliEncoderParams,
1296 hasher: &mut H10<Alloc, Buckets, Params>,
1297 dist_cache: &mut [i32],
1298 last_insert_len: &mut usize,
1299 commands: &mut [Command],
1300 num_commands: &mut usize,
1301 num_literals: &mut usize,
1302) where
1303 Buckets: PartialEq<Buckets>,
1304{
1305 let max_backward_limit: usize = (1usize << params.lgwin).wrapping_sub(16);
1306 let mut num_matches: <Alloc as Allocator<u32>>::AllocatedMemory = if num_bytes > 0usize {
1307 <Alloc as Allocator<u32>>::alloc_cell(alloc, num_bytes)
1308 } else {
1309 <Alloc as Allocator<u32>>::AllocatedMemory::default()
1310 };
1311 let mut matches_size: usize = (4usize).wrapping_mul(num_bytes);
1312 let store_end: usize = if num_bytes >= STORE_LOOKAHEAD_H_10 {
1313 position
1314 .wrapping_add(num_bytes)
1315 .wrapping_sub(STORE_LOOKAHEAD_H_10)
1316 .wrapping_add(1)
1317 } else {
1318 position
1319 };
1320 let mut cur_match_pos: usize = 0usize;
1321 let mut i: usize;
1322
1323 let mut orig_dist_cache = [0i32; 4];
1324
1325 let mut model: ZopfliCostModel<Alloc>;
1326 let mut nodes: <Alloc as Allocator<ZopfliNode>>::AllocatedMemory;
1327 let mut matches: <Alloc as Allocator<u64>>::AllocatedMemory = if matches_size > 0usize {
1328 <Alloc as Allocator<u64>>::alloc_cell(alloc, matches_size)
1329 } else {
1330 <Alloc as Allocator<u64>>::AllocatedMemory::default()
1331 };
1332 let gap: usize = 0usize;
1333 let shadow_matches: usize = 0usize;
1334 i = 0usize;
1335 while i.wrapping_add(hasher.HashTypeLength()).wrapping_sub(1) < num_bytes {
1336 {
1337 let pos: usize = position.wrapping_add(i);
1338 let max_distance: usize = min(pos, max_backward_limit);
1339 let max_length: usize = num_bytes.wrapping_sub(i);
1340
1341 let mut j: usize;
1342 {
1343 if matches_size < cur_match_pos.wrapping_add(128).wrapping_add(shadow_matches) {
1344 let mut new_size: usize = if matches_size == 0usize {
1345 cur_match_pos.wrapping_add(128).wrapping_add(shadow_matches)
1346 } else {
1347 matches_size
1348 };
1349 let mut new_array: <Alloc as Allocator<u64>>::AllocatedMemory;
1350 while new_size < cur_match_pos.wrapping_add(128).wrapping_add(shadow_matches) {
1351 new_size = new_size.wrapping_mul(2);
1352 }
1353 new_array = if new_size > 0usize {
1354 <Alloc as Allocator<u64>>::alloc_cell(alloc, new_size)
1355 } else {
1356 <Alloc as Allocator<u64>>::AllocatedMemory::default()
1357 };
1358 if matches_size != 0 {
1359 for (dst, src) in new_array
1360 .slice_mut()
1361 .split_at_mut(matches_size)
1362 .0
1363 .iter_mut()
1364 .zip(matches.slice().split_at(matches_size).0.iter())
1365 {
1366 *dst = *src;
1367 }
1368 }
1369 {
1370 <Alloc as Allocator<u64>>::free_cell(alloc, core::mem::take(&mut matches));
1371 }
1372 matches = new_array;
1373 matches_size = new_size;
1374 }
1375 }
1376 if !(0i32 == 0) {
1377 return;
1378 }
1379 let num_found_matches: usize = FindAllMatchesH10(
1380 hasher,
1381 dictionary, ringbuffer,
1383 ringbuffer_mask,
1384 pos,
1385 max_length,
1386 max_distance,
1387 gap,
1388 params,
1389 &mut matches.slice_mut()[cur_match_pos.wrapping_add(shadow_matches)..],
1390 );
1391 let cur_match_end: usize = cur_match_pos.wrapping_add(num_found_matches);
1392 j = cur_match_pos;
1393 while j.wrapping_add(1) < cur_match_end {
1394 {}
1395 j = j.wrapping_add(1);
1396 }
1397 num_matches.slice_mut()[i] = num_found_matches as u32;
1398 if num_found_matches > 0usize {
1399 let match_len =
1400 BackwardMatch(matches.slice()[cur_match_end.wrapping_sub(1)]).length();
1401 if match_len > 325usize {
1402 let skip: usize = match_len.wrapping_sub(1);
1403 let tmp = matches.slice()[(cur_match_end.wrapping_sub(1) as usize)];
1404 matches.slice_mut()[cur_match_pos] = tmp;
1405 cur_match_pos = cur_match_pos.wrapping_add(1);
1406 num_matches.slice_mut()[i] = 1u32;
1407 hasher.StoreRange(
1408 ringbuffer,
1409 ringbuffer_mask,
1410 pos.wrapping_add(1),
1411 min(pos.wrapping_add(match_len), store_end),
1412 );
1413 for item in num_matches
1414 .slice_mut()
1415 .split_at_mut(i.wrapping_add(1))
1416 .1
1417 .split_at_mut(skip)
1418 .0
1419 .iter_mut()
1420 {
1421 *item = 0;
1422 }
1423 i = i.wrapping_add(skip);
1424 } else {
1425 cur_match_pos = cur_match_end;
1426 }
1427 }
1428 }
1429 i = i.wrapping_add(1);
1430 }
1431 let orig_num_literals: usize = *num_literals;
1432 let orig_last_insert_len: usize = *last_insert_len;
1433 for (i, j) in orig_dist_cache
1434 .split_at_mut(4)
1435 .0
1436 .iter_mut()
1437 .zip(dist_cache.split_at(4).0)
1438 {
1439 *i = *j;
1440 }
1441 let orig_num_commands: usize = *num_commands;
1442 nodes = if num_bytes.wrapping_add(1) > 0usize {
1443 <Alloc as Allocator<ZopfliNode>>::alloc_cell(alloc, num_bytes.wrapping_add(1))
1444 } else {
1445 <Alloc as Allocator<ZopfliNode>>::AllocatedMemory::default()
1446 };
1447 if !(0i32 == 0) {
1448 return;
1449 }
1450 model = ZopfliCostModel::init(alloc, ¶ms.dist, num_bytes);
1451 if !(0i32 == 0) {
1452 return;
1453 }
1454 for i in 0usize..2usize {
1455 BrotliInitZopfliNodes(nodes.slice_mut(), num_bytes.wrapping_add(1));
1456 if i == 0usize {
1457 model.set_from_literal_costs(position, ringbuffer, ringbuffer_mask);
1458 } else {
1459 model.set_from_commands(
1460 position,
1461 ringbuffer,
1462 ringbuffer_mask,
1463 commands,
1464 num_commands.wrapping_sub(orig_num_commands),
1465 orig_last_insert_len,
1466 );
1467 }
1468 *num_commands = orig_num_commands;
1469 *num_literals = orig_num_literals;
1470 *last_insert_len = orig_last_insert_len;
1471 for (i, j) in dist_cache
1472 .split_at_mut(4)
1473 .0
1474 .iter_mut()
1475 .zip(orig_dist_cache.split_at(4).0)
1476 {
1477 *i = *j;
1478 }
1479 *num_commands = num_commands.wrapping_add(ZopfliIterate(
1480 num_bytes,
1481 position,
1482 ringbuffer,
1483 ringbuffer_mask,
1484 params,
1485 max_backward_limit,
1486 gap,
1487 dist_cache,
1488 &mut model,
1489 num_matches.slice(),
1490 matches.slice(),
1491 nodes.slice_mut(),
1492 ));
1493 BrotliZopfliCreateCommands(
1494 num_bytes,
1495 position,
1496 max_backward_limit,
1497 nodes.slice(),
1498 dist_cache,
1499 last_insert_len,
1500 params,
1501 commands,
1502 num_literals,
1503 );
1504 }
1505 model.cleanup(alloc);
1506 <Alloc as Allocator<ZopfliNode>>::free_cell(alloc, nodes);
1507 <Alloc as Allocator<u64>>::free_cell(alloc, matches);
1508 <Alloc as Allocator<u32>>::free_cell(alloc, num_matches);
1509}