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