brotli/enc/backward_references/
hq.rs

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