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