brotli/enc/backward_references/
hq.rs

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
33/*
34static kBrotliMinWindowBits: i32 = 10i32;
35
36static kBrotliMaxWindowBits: i32 = 24i32;
37
38static kInvalidMatch: u32 = 0xfffffffu32;
39
40static kCutoffTransformsCount: u32 = 10u32;
41
42static kCutoffTransforms: u64 = 0x71b520au64 << 32 | 0xda2d3200u32 as (u64);
43
44pub static kHashMul32: u32 = 0x1e35a7bdu32;
45
46pub static kHashMul64: u64 = 0x1e35a7bdu64 << 32 | 0x1e35a7bdu64;
47
48pub static kHashMul64Long: u64 = 0x1fe35a7bu32 as (u64) << 32 | 0xd3579bd3u32 as (u64);
49
50*/
51pub 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                    &params.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        /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
287        These could not be calculated before, since they require knowledge
288        of both the previous and the current block. */
289        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            /* Maximum distance is window size - 16, see section 9.1. of the spec.
293            Furthermore, we have to make sure that we don't look further back
294            from the start of the next block than the window size, otherwise we
295            could access already overwritten areas of the ring-buffer. */
296            let max_backward = handle.window_mask_ - max(BROTLI_WINDOW_GAP - 1, position - i);
297            let mut _best_len = 0;
298            /* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the
299            end of the current block and that we have at least
300            MAX_TREE_COMP_LENGTH tail in the ring-buffer. */
301            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, &params.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, //&params.dictionary ,
1382                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, &params.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}